From 111d1ba8260fa6ac104fadb26bbb45ac1b62c9f5 Mon Sep 17 00:00:00 2001
From: Justin Clark-Casey (justincc)
Date: Fri, 20 Sep 2013 22:41:53 +0100
Subject: 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.
---
 OpenSim/Region/Framework/Scenes/ScenePresence.cs | 38 ++++++++++++++++++++----
 1 file changed, 33 insertions(+), 5 deletions(-)

diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs
index f12d629..8d72e18 100644
--- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs
+++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs
@@ -311,7 +311,21 @@ namespace OpenSim.Region.Framework.Scenes
         /// </summary>
         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>
         /// 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
             // viewer (in turn triggered by the source region sending it a TeleportFinish event) waits until it's non-zero
             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);
                 Thread.Sleep(200);
             }
 
-            if (m_originRegionID.Equals(UUID.Zero))
+            if (originID.Equals(UUID.Zero))
             {
                 // Movement into region will fail
                 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}",
                     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;
             }
 //            else
@@ -3461,7 +3488,8 @@ namespace OpenSim.Region.Framework.Scenes
 
         private void CopyFrom(AgentData cAgent)
         {
-            m_originRegionID = cAgent.RegionID;
+            lock (m_originRegionIDAccessLock)
+                m_originRegionID = cAgent.RegionID;
 
             m_callbackURI = cAgent.CallbackURI;
 //            m_log.DebugFormat(
-- 
cgit v1.1