aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/AsyncCommandManager.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/ScriptEngine/Shared/Api/Implementation/AsyncCommandManager.cs')
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Implementation/AsyncCommandManager.cs329
1 files changed, 199 insertions, 130 deletions
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/AsyncCommandManager.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/AsyncCommandManager.cs
index 47a9cdc..036cb5d 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/AsyncCommandManager.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/AsyncCommandManager.cs
@@ -28,7 +28,9 @@
28using System; 28using System;
29using System.Collections; 29using System.Collections;
30using System.Collections.Generic; 30using System.Collections.Generic;
31using System.Reflection;
31using System.Threading; 32using System.Threading;
33using log4net;
32using OpenMetaverse; 34using OpenMetaverse;
33using OpenSim.Framework; 35using OpenSim.Framework;
34using OpenSim.Framework.Monitoring; 36using OpenSim.Framework.Monitoring;
@@ -45,15 +47,24 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
45 /// </summary> 47 /// </summary>
46 public class AsyncCommandManager 48 public class AsyncCommandManager
47 { 49 {
50 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
51
48 private static Thread cmdHandlerThread; 52 private static Thread cmdHandlerThread;
49 private static int cmdHandlerThreadCycleSleepms; 53 private static int cmdHandlerThreadCycleSleepms;
50 54
51 private static List<IScene> m_Scenes = new List<IScene>(); 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
52 private static List<IScriptEngine> m_ScriptEngines = 64 private static List<IScriptEngine> m_ScriptEngines =
53 new List<IScriptEngine>(); 65 new List<IScriptEngine>();
54 66
55 public IScriptEngine m_ScriptEngine; 67 public IScriptEngine m_ScriptEngine;
56 private IScene m_Scene;
57 68
58 private static Dictionary<IScriptEngine, Dataserver> m_Dataserver = 69 private static Dictionary<IScriptEngine, Dataserver> m_Dataserver =
59 new Dictionary<IScriptEngine, Dataserver>(); 70 new Dictionary<IScriptEngine, Dataserver>();
@@ -70,67 +81,99 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
70 81
71 public Dataserver DataserverPlugin 82 public Dataserver DataserverPlugin
72 { 83 {
73 get { return m_Dataserver[m_ScriptEngine]; } 84 get
85 {
86 lock (staticLock)
87 return m_Dataserver[m_ScriptEngine];
88 }
74 } 89 }
75 90
76 public Timer TimerPlugin 91 public Timer TimerPlugin
77 { 92 {
78 get { return m_Timer[m_ScriptEngine]; } 93 get
94 {
95 lock (staticLock)
96 return m_Timer[m_ScriptEngine];
97 }
79 } 98 }
80 99
81 public HttpRequest HttpRequestPlugin 100 public HttpRequest HttpRequestPlugin
82 { 101 {
83 get { return m_HttpRequest[m_ScriptEngine]; } 102 get
103 {
104 lock (staticLock)
105 return m_HttpRequest[m_ScriptEngine];
106 }
84 } 107 }
85 108
86 public Listener ListenerPlugin 109 public Listener ListenerPlugin
87 { 110 {
88 get { return m_Listener[m_ScriptEngine]; } 111 get
112 {
113 lock (staticLock)
114 return m_Listener[m_ScriptEngine];
115 }
89 } 116 }
90 117
91 public SensorRepeat SensorRepeatPlugin 118 public SensorRepeat SensorRepeatPlugin
92 { 119 {
93 get { return m_SensorRepeat[m_ScriptEngine]; } 120 get
121 {
122 lock (staticLock)
123 return m_SensorRepeat[m_ScriptEngine];
124 }
94 } 125 }
95 126
96 public XmlRequest XmlRequestPlugin 127 public XmlRequest XmlRequestPlugin
97 { 128 {
98 get { return m_XmlRequest[m_ScriptEngine]; } 129 get
130 {
131 lock (staticLock)
132 return m_XmlRequest[m_ScriptEngine];
133 }
99 } 134 }
100 135
101 public IScriptEngine[] ScriptEngines 136 public IScriptEngine[] ScriptEngines
102 { 137 {
103 get { return m_ScriptEngines.ToArray(); } 138 get
139 {
140 lock (staticLock)
141 return m_ScriptEngines.ToArray();
142 }
104 } 143 }
105 144
106 public AsyncCommandManager(IScriptEngine _ScriptEngine) 145 public AsyncCommandManager(IScriptEngine _ScriptEngine)
107 { 146 {
108 m_ScriptEngine = _ScriptEngine; 147 m_ScriptEngine = _ScriptEngine;
109 m_Scene = m_ScriptEngine.World; 148
110 149 // If there is more than one scene in the simulator or multiple script engines are used on the same region
111 if (m_Scenes.Count == 0) 150 // then more than one thread could arrive at this block of code simultaneously. However, it cannot be
112 ReadConfig(); 151 // executed concurrently both because concurrent list operations are not thread-safe and because of other
113 152 // race conditions such as the later check of cmdHandlerThread == null.
114 if (!m_Scenes.Contains(m_Scene)) 153 lock (staticLock)
115 m_Scenes.Add(m_Scene); 154 {
116 if (!m_ScriptEngines.Contains(m_ScriptEngine)) 155 if (m_ScriptEngines.Count == 0)
117 m_ScriptEngines.Add(m_ScriptEngine); 156 ReadConfig();
118 157
119 // Create instances of all plugins 158 if (!m_ScriptEngines.Contains(m_ScriptEngine))
120 if (!m_Dataserver.ContainsKey(m_ScriptEngine)) 159 m_ScriptEngines.Add(m_ScriptEngine);
121 m_Dataserver[m_ScriptEngine] = new Dataserver(this); 160
122 if (!m_Timer.ContainsKey(m_ScriptEngine)) 161 // Create instances of all plugins
123 m_Timer[m_ScriptEngine] = new Timer(this); 162 if (!m_Dataserver.ContainsKey(m_ScriptEngine))
124 if (!m_HttpRequest.ContainsKey(m_ScriptEngine)) 163 m_Dataserver[m_ScriptEngine] = new Dataserver(this);
125 m_HttpRequest[m_ScriptEngine] = new HttpRequest(this); 164 if (!m_Timer.ContainsKey(m_ScriptEngine))
126 if (!m_Listener.ContainsKey(m_ScriptEngine)) 165 m_Timer[m_ScriptEngine] = new Timer(this);
127 m_Listener[m_ScriptEngine] = new Listener(this); 166 if (!m_HttpRequest.ContainsKey(m_ScriptEngine))
128 if (!m_SensorRepeat.ContainsKey(m_ScriptEngine)) 167 m_HttpRequest[m_ScriptEngine] = new HttpRequest(this);
129 m_SensorRepeat[m_ScriptEngine] = new SensorRepeat(this); 168 if (!m_Listener.ContainsKey(m_ScriptEngine))
130 if (!m_XmlRequest.ContainsKey(m_ScriptEngine)) 169 m_Listener[m_ScriptEngine] = new Listener(this);
131 m_XmlRequest[m_ScriptEngine] = new XmlRequest(this); 170 if (!m_SensorRepeat.ContainsKey(m_ScriptEngine))
132 171 m_SensorRepeat[m_ScriptEngine] = new SensorRepeat(this);
133 StartThread(); 172 if (!m_XmlRequest.ContainsKey(m_ScriptEngine))
173 m_XmlRequest[m_ScriptEngine] = new XmlRequest(this);
174
175 StartThread();
176 }
134 } 177 }
135 178
136 private static void StartThread() 179 private static void StartThread()
@@ -139,7 +182,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
139 { 182 {
140 // Start the thread that will be doing the work 183 // Start the thread that will be doing the work
141 cmdHandlerThread 184 cmdHandlerThread
142 = Watchdog.StartThread( 185 = WorkManager.StartThread(
143 CmdHandlerThreadLoop, "AsyncLSLCmdHandlerThread", ThreadPriority.Normal, true, true); 186 CmdHandlerThreadLoop, "AsyncLSLCmdHandlerThread", ThreadPriority.Normal, true, true);
144 } 187 }
145 } 188 }
@@ -179,42 +222,43 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
179 { 222 {
180 try 223 try
181 { 224 {
182 while (true) 225 Thread.Sleep(cmdHandlerThreadCycleSleepms);
183 {
184 Thread.Sleep(cmdHandlerThreadCycleSleepms);
185 226
186 DoOneCmdHandlerPass(); 227 DoOneCmdHandlerPass();
187 228
188 Watchdog.UpdateThread(); 229 Watchdog.UpdateThread();
189 }
190 } 230 }
191 catch 231 catch (Exception e)
192 { 232 {
233 m_log.Error("[ASYNC COMMAND MANAGER]: Exception in command handler pass: ", e);
193 } 234 }
194 } 235 }
195 } 236 }
196 237
197 private static void DoOneCmdHandlerPass() 238 private static void DoOneCmdHandlerPass()
198 { 239 {
199 // Check HttpRequests 240 lock (staticLock)
200 m_HttpRequest[m_ScriptEngines[0]].CheckHttpRequests(); 241 {
242 // Check HttpRequests
243 m_HttpRequest[m_ScriptEngines[0]].CheckHttpRequests();
201 244
202 // Check XMLRPCRequests 245 // Check XMLRPCRequests
203 m_XmlRequest[m_ScriptEngines[0]].CheckXMLRPCRequests(); 246 m_XmlRequest[m_ScriptEngines[0]].CheckXMLRPCRequests();
204 247
205 foreach (IScriptEngine s in m_ScriptEngines) 248 foreach (IScriptEngine s in m_ScriptEngines)
206 { 249 {
207 // Check Listeners 250 // Check Listeners
208 m_Listener[s].CheckListeners(); 251 m_Listener[s].CheckListeners();
209 252
210 // Check timers 253 // Check timers
211 m_Timer[s].CheckTimerEvents(); 254 m_Timer[s].CheckTimerEvents();
212 255
213 // Check Sensors 256 // Check Sensors
214 m_SensorRepeat[s].CheckSenseRepeaterEvents(); 257 m_SensorRepeat[s].CheckSenseRepeaterEvents();
215 258
216 // Check dataserver 259 // Check dataserver
217 m_Dataserver[s].ExpireRequests(); 260 m_Dataserver[s].ExpireRequests();
261 }
218 } 262 }
219 } 263 }
220 264
@@ -225,19 +269,44 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
225 /// <param name="itemID"></param> 269 /// <param name="itemID"></param>
226 public static void RemoveScript(IScriptEngine engine, uint localID, UUID itemID) 270 public static void RemoveScript(IScriptEngine engine, uint localID, UUID itemID)
227 { 271 {
272// m_log.DebugFormat("[ASYNC COMMAND MANAGER]: Removing facilities for script {0}", itemID);
273
274 lock (staticLock)
275 {
276 // Remove dataserver events
277 m_Dataserver[engine].RemoveEvents(localID, itemID);
278
279 // Remove from: Timers
280 m_Timer[engine].UnSetTimerEvents(localID, itemID);
281
282 // Remove from: HttpRequest
283 IHttpRequestModule iHttpReq = engine.World.RequestModuleInterface<IHttpRequestModule>();
284 if (iHttpReq != null)
285 iHttpReq.StopHttpRequestsForScript(itemID);
286
287 IWorldComm comms = engine.World.RequestModuleInterface<IWorldComm>();
288 if (comms != null)
289 comms.DeleteListener(itemID);
290
291 IXMLRPC xmlrpc = engine.World.RequestModuleInterface<IXMLRPC>();
292 if (xmlrpc != null)
293 {
294 xmlrpc.DeleteChannels(itemID);
295 xmlrpc.CancelSRDRequests(itemID);
296 }
297
298 // Remove Sensors
299 m_SensorRepeat[engine].UnSetSenseRepeaterEvents(localID, itemID);
300 }
301 }
302
303 public static void StateChange(IScriptEngine engine, uint localID, UUID itemID)
304 {
228 // Remove a specific script 305 // Remove a specific script
229 306
230 // Remove dataserver events 307 // Remove dataserver events
231 m_Dataserver[engine].RemoveEvents(localID, itemID); 308 m_Dataserver[engine].RemoveEvents(localID, itemID);
232 309
233 // Remove from: Timers
234 m_Timer[engine].UnSetTimerEvents(localID, itemID);
235
236 // Remove from: HttpRequest
237 IHttpRequestModule iHttpReq = engine.World.RequestModuleInterface<IHttpRequestModule>();
238 if (iHttpReq != null)
239 iHttpReq.StopHttpRequest(localID, itemID);
240
241 IWorldComm comms = engine.World.RequestModuleInterface<IWorldComm>(); 310 IWorldComm comms = engine.World.RequestModuleInterface<IWorldComm>();
242 if (comms != null) 311 if (comms != null)
243 comms.DeleteListener(itemID); 312 comms.DeleteListener(itemID);
@@ -248,9 +317,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
248 xmlrpc.DeleteChannels(itemID); 317 xmlrpc.DeleteChannels(itemID);
249 xmlrpc.CancelSRDRequests(itemID); 318 xmlrpc.CancelSRDRequests(itemID);
250 } 319 }
251
252 // Remove Sensors 320 // Remove Sensors
253 m_SensorRepeat[engine].UnSetSenseRepeaterEvents(localID, itemID); 321 m_SensorRepeat[engine].UnSetSenseRepeaterEvents(localID, itemID);
322
254 } 323 }
255 324
256 /// <summary> 325 /// <summary>
@@ -260,10 +329,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
260 /// <returns></returns> 329 /// <returns></returns>
261 public static SensorRepeat GetSensorRepeatPlugin(IScriptEngine engine) 330 public static SensorRepeat GetSensorRepeatPlugin(IScriptEngine engine)
262 { 331 {
263 if (m_SensorRepeat.ContainsKey(engine)) 332 lock (staticLock)
264 return m_SensorRepeat[engine]; 333 {
265 else 334 if (m_SensorRepeat.ContainsKey(engine))
266 return null; 335 return m_SensorRepeat[engine];
336 else
337 return null;
338 }
267 } 339 }
268 340
269 /// <summary> 341 /// <summary>
@@ -273,10 +345,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
273 /// <returns></returns> 345 /// <returns></returns>
274 public static Dataserver GetDataserverPlugin(IScriptEngine engine) 346 public static Dataserver GetDataserverPlugin(IScriptEngine engine)
275 { 347 {
276 if (m_Dataserver.ContainsKey(engine)) 348 lock (staticLock)
277 return m_Dataserver[engine]; 349 {
278 else 350 if (m_Dataserver.ContainsKey(engine))
279 return null; 351 return m_Dataserver[engine];
352 else
353 return null;
354 }
280 } 355 }
281 356
282 /// <summary> 357 /// <summary>
@@ -286,10 +361,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
286 /// <returns></returns> 361 /// <returns></returns>
287 public static Timer GetTimerPlugin(IScriptEngine engine) 362 public static Timer GetTimerPlugin(IScriptEngine engine)
288 { 363 {
289 if (m_Timer.ContainsKey(engine)) 364 lock (staticLock)
290 return m_Timer[engine]; 365 {
291 else 366 if (m_Timer.ContainsKey(engine))
292 return null; 367 return m_Timer[engine];
368 else
369 return null;
370 }
293 } 371 }
294 372
295 /// <summary> 373 /// <summary>
@@ -299,38 +377,44 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
299 /// <returns></returns> 377 /// <returns></returns>
300 public static Listener GetListenerPlugin(IScriptEngine engine) 378 public static Listener GetListenerPlugin(IScriptEngine engine)
301 { 379 {
302 if (m_Listener.ContainsKey(engine)) 380 lock (staticLock)
303 return m_Listener[engine]; 381 {
304 else 382 if (m_Listener.ContainsKey(engine))
305 return null; 383 return m_Listener[engine];
384 else
385 return null;
386 }
306 } 387 }
307 388
308 public static Object[] GetSerializationData(IScriptEngine engine, UUID itemID) 389 public static Object[] GetSerializationData(IScriptEngine engine, UUID itemID)
309 { 390 {
310 List<Object> data = new List<Object>(); 391 List<Object> data = new List<Object>();
311 392
312 Object[] listeners = m_Listener[engine].GetSerializationData(itemID); 393 lock (staticLock)
313 if (listeners.Length > 0)
314 { 394 {
315 data.Add("listener"); 395 Object[] listeners = m_Listener[engine].GetSerializationData(itemID);
316 data.Add(listeners.Length); 396 if (listeners.Length > 0)
317 data.AddRange(listeners); 397 {
318 } 398 data.Add("listener");
399 data.Add(listeners.Length);
400 data.AddRange(listeners);
401 }
319 402
320 Object[] timers=m_Timer[engine].GetSerializationData(itemID); 403 Object[] timers=m_Timer[engine].GetSerializationData(itemID);
321 if (timers.Length > 0) 404 if (timers.Length > 0)
322 { 405 {
323 data.Add("timer"); 406 data.Add("timer");
324 data.Add(timers.Length); 407 data.Add(timers.Length);
325 data.AddRange(timers); 408 data.AddRange(timers);
326 } 409 }
327 410
328 Object[] sensors = m_SensorRepeat[engine].GetSerializationData(itemID); 411 Object[] sensors = m_SensorRepeat[engine].GetSerializationData(itemID);
329 if (sensors.Length > 0) 412 if (sensors.Length > 0)
330 { 413 {
331 data.Add("sensor"); 414 data.Add("sensor");
332 data.Add(sensors.Length); 415 data.Add(sensors.Length);
333 data.AddRange(sensors); 416 data.AddRange(sensors);
417 }
334 } 418 }
335 419
336 return data.ToArray(); 420 return data.ToArray();
@@ -355,41 +439,26 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
355 439
356 idx+=len; 440 idx+=len;
357 441
442 lock (staticLock)
443 {
358 switch (type) 444 switch (type)
359 { 445 {
360 case "listener": 446 case "listener":
361 m_Listener[engine].CreateFromData(localID, itemID, 447 m_Listener[engine].CreateFromData(localID, itemID,
362 hostID, item); 448 hostID, item);
363 break; 449 break;
364 case "timer": 450 case "timer":
365 m_Timer[engine].CreateFromData(localID, itemID, 451 m_Timer[engine].CreateFromData(localID, itemID,
366 hostID, item); 452 hostID, item);
367 break; 453 break;
368 case "sensor": 454 case "sensor":
369 m_SensorRepeat[engine].CreateFromData(localID, 455 m_SensorRepeat[engine].CreateFromData(localID,
370 itemID, hostID, item); 456 itemID, hostID, item);
371 break; 457 break;
458 }
372 } 459 }
373 } 460 }
374 } 461 }
375 } 462 }
376
377 #region Check llRemoteData channels
378
379 #endregion
380
381 #region Check llListeners
382
383 #endregion
384
385 /// <summary>
386 /// If set to true then threads and stuff should try to make a graceful exit
387 /// </summary>
388 public bool PleaseShutdown
389 {
390 get { return _PleaseShutdown; }
391 set { _PleaseShutdown = value; }
392 }
393 private bool _PleaseShutdown = false;
394 } 463 }
395} 464}