aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorJustin Clark-Casey (justincc)2013-05-31 22:50:15 +0100
committerJustin Clark-Casey (justincc)2013-05-31 22:50:15 +0100
commit921ad8704e08fccc994f7907e7cb1e9372e355b9 (patch)
tree90e96e9d8b5158c247d44c4219809d2ee8981c43
parentrefactor: Remove unused AsyncCommandManager.PleaseShutdown (diff)
downloadopensim-SC_OLD-921ad8704e08fccc994f7907e7cb1e9372e355b9.zip
opensim-SC_OLD-921ad8704e08fccc994f7907e7cb1e9372e355b9.tar.gz
opensim-SC_OLD-921ad8704e08fccc994f7907e7cb1e9372e355b9.tar.bz2
opensim-SC_OLD-921ad8704e08fccc994f7907e7cb1e9372e355b9.tar.xz
Lock areas of AsyncCommandManager where multiple threads could try to access/update the same static structures simultaneously.
This is possible where there is more than one scene (multiple copies of the same script engine) and/or more than one script engine being used. These operations are not thread safe and could be leading to the exceptions/problems seen in http://opensimulator.org/mantis/view.php?id=6651 This also prevents a small race condition where more than one AsyncLSLCmdHandlerThread could be started.
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Implementation/AsyncCommandManager.cs288
1 files changed, 177 insertions, 111 deletions
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/AsyncCommandManager.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/AsyncCommandManager.cs
index c71b571..72e8415 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/AsyncCommandManager.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/AsyncCommandManager.cs
@@ -52,6 +52,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
52 private static Thread cmdHandlerThread; 52 private static Thread cmdHandlerThread;
53 private static int cmdHandlerThreadCycleSleepms; 53 private static int cmdHandlerThreadCycleSleepms;
54 54
55 /// <summary>
56 /// Lock for reading/writing static components of AsyncCommandManager.
57 /// </summary>
58 /// <remarks>
59 /// This lock exists so that multiple threads from different engines and/or different copies of the same engine
60 /// are prevented from running non-thread safe code (e.g. read/write of lists) concurrently.
61 /// </remarks>
62 private static object staticLock = new object();
63
55 private static List<IScene> m_Scenes = new List<IScene>(); 64 private static List<IScene> m_Scenes = new List<IScene>();
56 private static List<IScriptEngine> m_ScriptEngines = 65 private static List<IScriptEngine> m_ScriptEngines =
57 new List<IScriptEngine>(); 66 new List<IScriptEngine>();
@@ -74,37 +83,65 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
74 83
75 public Dataserver DataserverPlugin 84 public Dataserver DataserverPlugin
76 { 85 {
77 get { return m_Dataserver[m_ScriptEngine]; } 86 get
87 {
88 lock (staticLock)
89 return m_Dataserver[m_ScriptEngine];
90 }
78 } 91 }
79 92
80 public Timer TimerPlugin 93 public Timer TimerPlugin
81 { 94 {
82 get { return m_Timer[m_ScriptEngine]; } 95 get
96 {
97 lock (staticLock)
98 return m_Timer[m_ScriptEngine];
99 }
83 } 100 }
84 101
85 public HttpRequest HttpRequestPlugin 102 public HttpRequest HttpRequestPlugin
86 { 103 {
87 get { return m_HttpRequest[m_ScriptEngine]; } 104 get
105 {
106 lock (staticLock)
107 return m_HttpRequest[m_ScriptEngine];
108 }
88 } 109 }
89 110
90 public Listener ListenerPlugin 111 public Listener ListenerPlugin
91 { 112 {
92 get { return m_Listener[m_ScriptEngine]; } 113 get
114 {
115 lock (staticLock)
116 return m_Listener[m_ScriptEngine];
117 }
93 } 118 }
94 119
95 public SensorRepeat SensorRepeatPlugin 120 public SensorRepeat SensorRepeatPlugin
96 { 121 {
97 get { return m_SensorRepeat[m_ScriptEngine]; } 122 get
123 {
124 lock (staticLock)
125 return m_SensorRepeat[m_ScriptEngine];
126 }
98 } 127 }
99 128
100 public XmlRequest XmlRequestPlugin 129 public XmlRequest XmlRequestPlugin
101 { 130 {
102 get { return m_XmlRequest[m_ScriptEngine]; } 131 get
132 {
133 lock (staticLock)
134 return m_XmlRequest[m_ScriptEngine];
135 }
103 } 136 }
104 137
105 public IScriptEngine[] ScriptEngines 138 public IScriptEngine[] ScriptEngines
106 { 139 {
107 get { return m_ScriptEngines.ToArray(); } 140 get
141 {
142 lock (staticLock)
143 return m_ScriptEngines.ToArray();
144 }
108 } 145 }
109 146
110 public AsyncCommandManager(IScriptEngine _ScriptEngine) 147 public AsyncCommandManager(IScriptEngine _ScriptEngine)
@@ -112,29 +149,36 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
112 m_ScriptEngine = _ScriptEngine; 149 m_ScriptEngine = _ScriptEngine;
113 m_Scene = m_ScriptEngine.World; 150 m_Scene = m_ScriptEngine.World;
114 151
115 if (m_Scenes.Count == 0) 152 // If there is more than one scene in the simulator or multiple script engines are used on the same region
116 ReadConfig(); 153 // then more than one thread could arrive at this block of code simultaneously. However, it cannot be
117 154 // executed concurrently both because concurrent list operations are not thread-safe and because of other
118 if (!m_Scenes.Contains(m_Scene)) 155 // race conditions such as the later check of cmdHandlerThread == null.
119 m_Scenes.Add(m_Scene); 156 lock (staticLock)
120 if (!m_ScriptEngines.Contains(m_ScriptEngine)) 157 {
121 m_ScriptEngines.Add(m_ScriptEngine); 158 if (m_Scenes.Count == 0)
122 159 ReadConfig();
123 // Create instances of all plugins 160
124 if (!m_Dataserver.ContainsKey(m_ScriptEngine)) 161 if (!m_Scenes.Contains(m_Scene))
125 m_Dataserver[m_ScriptEngine] = new Dataserver(this); 162 m_Scenes.Add(m_Scene);
126 if (!m_Timer.ContainsKey(m_ScriptEngine)) 163 if (!m_ScriptEngines.Contains(m_ScriptEngine))
127 m_Timer[m_ScriptEngine] = new Timer(this); 164 m_ScriptEngines.Add(m_ScriptEngine);
128 if (!m_HttpRequest.ContainsKey(m_ScriptEngine)) 165
129 m_HttpRequest[m_ScriptEngine] = new HttpRequest(this); 166 // Create instances of all plugins
130 if (!m_Listener.ContainsKey(m_ScriptEngine)) 167 if (!m_Dataserver.ContainsKey(m_ScriptEngine))
131 m_Listener[m_ScriptEngine] = new Listener(this); 168 m_Dataserver[m_ScriptEngine] = new Dataserver(this);
132 if (!m_SensorRepeat.ContainsKey(m_ScriptEngine)) 169 if (!m_Timer.ContainsKey(m_ScriptEngine))
133 m_SensorRepeat[m_ScriptEngine] = new SensorRepeat(this); 170 m_Timer[m_ScriptEngine] = new Timer(this);
134 if (!m_XmlRequest.ContainsKey(m_ScriptEngine)) 171 if (!m_HttpRequest.ContainsKey(m_ScriptEngine))
135 m_XmlRequest[m_ScriptEngine] = new XmlRequest(this); 172 m_HttpRequest[m_ScriptEngine] = new HttpRequest(this);
136 173 if (!m_Listener.ContainsKey(m_ScriptEngine))
137 StartThread(); 174 m_Listener[m_ScriptEngine] = new Listener(this);
175 if (!m_SensorRepeat.ContainsKey(m_ScriptEngine))
176 m_SensorRepeat[m_ScriptEngine] = new SensorRepeat(this);
177 if (!m_XmlRequest.ContainsKey(m_ScriptEngine))
178 m_XmlRequest[m_ScriptEngine] = new XmlRequest(this);
179
180 StartThread();
181 }
138 } 182 }
139 183
140 private static void StartThread() 184 private static void StartThread()
@@ -198,25 +242,28 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
198 242
199 private static void DoOneCmdHandlerPass() 243 private static void DoOneCmdHandlerPass()
200 { 244 {
201 // Check HttpRequests 245 lock (staticLock)
202 m_HttpRequest[m_ScriptEngines[0]].CheckHttpRequests(); 246 {
247 // Check HttpRequests
248 m_HttpRequest[m_ScriptEngines[0]].CheckHttpRequests();
203 249
204 // Check XMLRPCRequests 250 // Check XMLRPCRequests
205 m_XmlRequest[m_ScriptEngines[0]].CheckXMLRPCRequests(); 251 m_XmlRequest[m_ScriptEngines[0]].CheckXMLRPCRequests();
206 252
207 foreach (IScriptEngine s in m_ScriptEngines) 253 foreach (IScriptEngine s in m_ScriptEngines)
208 { 254 {
209 // Check Listeners 255 // Check Listeners
210 m_Listener[s].CheckListeners(); 256 m_Listener[s].CheckListeners();
211 257
212 // Check timers 258 // Check timers
213 m_Timer[s].CheckTimerEvents(); 259 m_Timer[s].CheckTimerEvents();
214 260
215 // Check Sensors 261 // Check Sensors
216 m_SensorRepeat[s].CheckSenseRepeaterEvents(); 262 m_SensorRepeat[s].CheckSenseRepeaterEvents();
217 263
218 // Check dataserver 264 // Check dataserver
219 m_Dataserver[s].ExpireRequests(); 265 m_Dataserver[s].ExpireRequests();
266 }
220 } 267 }
221 } 268 }
222 269
@@ -229,32 +276,33 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
229 { 276 {
230// m_log.DebugFormat("[ASYNC COMMAND MANAGER]: Removing facilities for script {0}", itemID); 277// m_log.DebugFormat("[ASYNC COMMAND MANAGER]: Removing facilities for script {0}", itemID);
231 278
232 // Remove a specific script 279 lock (staticLock)
280 {
281 // Remove dataserver events
282 m_Dataserver[engine].RemoveEvents(localID, itemID);
233 283
234 // Remove dataserver events 284 // Remove from: Timers
235 m_Dataserver[engine].RemoveEvents(localID, itemID); 285 m_Timer[engine].UnSetTimerEvents(localID, itemID);
236 286
237 // Remove from: Timers 287 // Remove from: HttpRequest
238 m_Timer[engine].UnSetTimerEvents(localID, itemID); 288 IHttpRequestModule iHttpReq = engine.World.RequestModuleInterface<IHttpRequestModule>();
289 if (iHttpReq != null)
290 iHttpReq.StopHttpRequestsForScript(itemID);
239 291
240 // Remove from: HttpRequest 292 IWorldComm comms = engine.World.RequestModuleInterface<IWorldComm>();
241 IHttpRequestModule iHttpReq = engine.World.RequestModuleInterface<IHttpRequestModule>(); 293 if (comms != null)
242 if (iHttpReq != null) 294 comms.DeleteListener(itemID);
243 iHttpReq.StopHttpRequestsForScript(itemID);
244 295
245 IWorldComm comms = engine.World.RequestModuleInterface<IWorldComm>(); 296 IXMLRPC xmlrpc = engine.World.RequestModuleInterface<IXMLRPC>();
246 if (comms != null) 297 if (xmlrpc != null)
247 comms.DeleteListener(itemID); 298 {
299 xmlrpc.DeleteChannels(itemID);
300 xmlrpc.CancelSRDRequests(itemID);
301 }
248 302
249 IXMLRPC xmlrpc = engine.World.RequestModuleInterface<IXMLRPC>(); 303 // Remove Sensors
250 if (xmlrpc != null) 304 m_SensorRepeat[engine].UnSetSenseRepeaterEvents(localID, itemID);
251 {
252 xmlrpc.DeleteChannels(itemID);
253 xmlrpc.CancelSRDRequests(itemID);
254 } 305 }
255
256 // Remove Sensors
257 m_SensorRepeat[engine].UnSetSenseRepeaterEvents(localID, itemID);
258 } 306 }
259 307
260 /// <summary> 308 /// <summary>
@@ -264,10 +312,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
264 /// <returns></returns> 312 /// <returns></returns>
265 public static SensorRepeat GetSensorRepeatPlugin(IScriptEngine engine) 313 public static SensorRepeat GetSensorRepeatPlugin(IScriptEngine engine)
266 { 314 {
267 if (m_SensorRepeat.ContainsKey(engine)) 315 lock (staticLock)
268 return m_SensorRepeat[engine]; 316 {
269 else 317 if (m_SensorRepeat.ContainsKey(engine))
270 return null; 318 return m_SensorRepeat[engine];
319 else
320 return null;
321 }
271 } 322 }
272 323
273 /// <summary> 324 /// <summary>
@@ -277,10 +328,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
277 /// <returns></returns> 328 /// <returns></returns>
278 public static Dataserver GetDataserverPlugin(IScriptEngine engine) 329 public static Dataserver GetDataserverPlugin(IScriptEngine engine)
279 { 330 {
280 if (m_Dataserver.ContainsKey(engine)) 331 lock (staticLock)
281 return m_Dataserver[engine]; 332 {
282 else 333 if (m_Dataserver.ContainsKey(engine))
283 return null; 334 return m_Dataserver[engine];
335 else
336 return null;
337 }
284 } 338 }
285 339
286 /// <summary> 340 /// <summary>
@@ -290,10 +344,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
290 /// <returns></returns> 344 /// <returns></returns>
291 public static Timer GetTimerPlugin(IScriptEngine engine) 345 public static Timer GetTimerPlugin(IScriptEngine engine)
292 { 346 {
293 if (m_Timer.ContainsKey(engine)) 347 lock (staticLock)
294 return m_Timer[engine]; 348 {
295 else 349 if (m_Timer.ContainsKey(engine))
296 return null; 350 return m_Timer[engine];
351 else
352 return null;
353 }
297 } 354 }
298 355
299 /// <summary> 356 /// <summary>
@@ -303,38 +360,44 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
303 /// <returns></returns> 360 /// <returns></returns>
304 public static Listener GetListenerPlugin(IScriptEngine engine) 361 public static Listener GetListenerPlugin(IScriptEngine engine)
305 { 362 {
306 if (m_Listener.ContainsKey(engine)) 363 lock (staticLock)
307 return m_Listener[engine]; 364 {
308 else 365 if (m_Listener.ContainsKey(engine))
309 return null; 366 return m_Listener[engine];
367 else
368 return null;
369 }
310 } 370 }
311 371
312 public static Object[] GetSerializationData(IScriptEngine engine, UUID itemID) 372 public static Object[] GetSerializationData(IScriptEngine engine, UUID itemID)
313 { 373 {
314 List<Object> data = new List<Object>(); 374 List<Object> data = new List<Object>();
315 375
316 Object[] listeners = m_Listener[engine].GetSerializationData(itemID); 376 lock (staticLock)
317 if (listeners.Length > 0)
318 { 377 {
319 data.Add("listener"); 378 Object[] listeners = m_Listener[engine].GetSerializationData(itemID);
320 data.Add(listeners.Length); 379 if (listeners.Length > 0)
321 data.AddRange(listeners); 380 {
322 } 381 data.Add("listener");
382 data.Add(listeners.Length);
383 data.AddRange(listeners);
384 }
323 385
324 Object[] timers=m_Timer[engine].GetSerializationData(itemID); 386 Object[] timers=m_Timer[engine].GetSerializationData(itemID);
325 if (timers.Length > 0) 387 if (timers.Length > 0)
326 { 388 {
327 data.Add("timer"); 389 data.Add("timer");
328 data.Add(timers.Length); 390 data.Add(timers.Length);
329 data.AddRange(timers); 391 data.AddRange(timers);
330 } 392 }
331 393
332 Object[] sensors = m_SensorRepeat[engine].GetSerializationData(itemID); 394 Object[] sensors = m_SensorRepeat[engine].GetSerializationData(itemID);
333 if (sensors.Length > 0) 395 if (sensors.Length > 0)
334 { 396 {
335 data.Add("sensor"); 397 data.Add("sensor");
336 data.Add(sensors.Length); 398 data.Add(sensors.Length);
337 data.AddRange(sensors); 399 data.AddRange(sensors);
400 }
338 } 401 }
339 402
340 return data.ToArray(); 403 return data.ToArray();
@@ -359,20 +422,23 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
359 422
360 idx+=len; 423 idx+=len;
361 424
425 lock (staticLock)
426 {
362 switch (type) 427 switch (type)
363 { 428 {
364 case "listener": 429 case "listener":
365 m_Listener[engine].CreateFromData(localID, itemID, 430 m_Listener[engine].CreateFromData(localID, itemID,
366 hostID, item); 431 hostID, item);
367 break; 432 break;
368 case "timer": 433 case "timer":
369 m_Timer[engine].CreateFromData(localID, itemID, 434 m_Timer[engine].CreateFromData(localID, itemID,
370 hostID, item); 435 hostID, item);
371 break; 436 break;
372 case "sensor": 437 case "sensor":
373 m_SensorRepeat[engine].CreateFromData(localID, 438 m_SensorRepeat[engine].CreateFromData(localID,
374 itemID, hostID, item); 439 itemID, hostID, item);
375 break; 440 break;
441 }
376 } 442 }
377 } 443 }
378 } 444 }