Lock around read/write of ScenePresence.m_originRegionID to make sure that all threads are seeing the latest value and not a cached one.

There is a possibilty that some V2 teleport failures are due to the viewer triggered CompleteMovement thread not seeing the change of m_originRegionID by the UpdateAgent thread.
varregion
Justin Clark-Casey (justincc) 2013-09-20 22:41:53 +01:00
parent c6dea6ee78
commit c01db5fbdd
1 changed files with 33 additions and 5 deletions

View File

@ -311,7 +311,21 @@ namespace OpenSim.Region.Framework.Scenes
/// </summary> /// </summary>
private string m_callbackURI; private string m_callbackURI;
public UUID m_originRegionID; /// <summary>
/// Records the region from which this presence originated, if not from login.
/// </summary>
/// <remarks>
/// Also acts as a signal in the teleport V2 process to release UpdateAgent after a viewer has triggered
/// CompleteMovement and made the previous child agent a root agent.
/// </remarks>
private UUID m_originRegionID;
/// <summary>
/// This object is used as a lock before accessing m_originRegionID to make sure that every thread is seeing
/// the very latest value and not using some cached version. Cannot make m_originRegionID itself volatite as
/// it is a value type.
/// </summary>
private object m_originRegionIDAccessLock = new object();
/// <summary> /// <summary>
/// Used by the entity transfer module to signal when the presence should not be closed because a subsequent /// Used by the entity transfer module to signal when the presence should not be closed because a subsequent
@ -1359,13 +1373,21 @@ namespace OpenSim.Region.Framework.Scenes
// m_originRegionID is UUID.Zero; after, it's non-Zero. The CompleteMovement sequence initiated from the // m_originRegionID is UUID.Zero; after, it's non-Zero. The CompleteMovement sequence initiated from the
// viewer (in turn triggered by the source region sending it a TeleportFinish event) waits until it's non-zero // viewer (in turn triggered by the source region sending it a TeleportFinish event) waits until it's non-zero
int count = 50; int count = 50;
while (m_originRegionID.Equals(UUID.Zero) && count-- > 0) UUID originID;
lock (m_originRegionIDAccessLock)
originID = m_originRegionID;
while (originID.Equals(UUID.Zero) && count-- > 0)
{ {
lock (m_originRegionIDAccessLock)
originID = m_originRegionID;
m_log.DebugFormat("[SCENE PRESENCE]: Agent {0} waiting for update in {1}", client.Name, Scene.Name); m_log.DebugFormat("[SCENE PRESENCE]: Agent {0} waiting for update in {1}", client.Name, Scene.Name);
Thread.Sleep(200); Thread.Sleep(200);
} }
if (m_originRegionID.Equals(UUID.Zero)) if (originID.Equals(UUID.Zero))
{ {
// Movement into region will fail // Movement into region will fail
m_log.WarnFormat("[SCENE PRESENCE]: Update agent {0} never arrived in {1}", client.Name, Scene.Name); m_log.WarnFormat("[SCENE PRESENCE]: Update agent {0} never arrived in {1}", client.Name, Scene.Name);
@ -1444,7 +1466,12 @@ namespace OpenSim.Region.Framework.Scenes
"[SCENE PRESENCE]: Releasing {0} {1} with callback to {2}", "[SCENE PRESENCE]: Releasing {0} {1} with callback to {2}",
client.Name, client.AgentId, m_callbackURI); client.Name, client.AgentId, m_callbackURI);
Scene.SimulationService.ReleaseAgent(m_originRegionID, UUID, m_callbackURI); UUID originID;
lock (m_originRegionIDAccessLock)
originID = m_originRegionID;
Scene.SimulationService.ReleaseAgent(originID, UUID, m_callbackURI);
m_callbackURI = null; m_callbackURI = null;
} }
// else // else
@ -3461,7 +3488,8 @@ namespace OpenSim.Region.Framework.Scenes
private void CopyFrom(AgentData cAgent) private void CopyFrom(AgentData cAgent)
{ {
m_originRegionID = cAgent.RegionID; lock (m_originRegionIDAccessLock)
m_originRegionID = cAgent.RegionID;
m_callbackURI = cAgent.CallbackURI; m_callbackURI = cAgent.CallbackURI;
// m_log.DebugFormat( // m_log.DebugFormat(