diff options
Diffstat (limited to 'OpenSim/Region/ScriptEngine/Shared/Api/Implementation/AsyncCommandManager.cs')
-rw-r--r-- | OpenSim/Region/ScriptEngine/Shared/Api/Implementation/AsyncCommandManager.cs | 329 |
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 @@ | |||
28 | using System; | 28 | using System; |
29 | using System.Collections; | 29 | using System.Collections; |
30 | using System.Collections.Generic; | 30 | using System.Collections.Generic; |
31 | using System.Reflection; | ||
31 | using System.Threading; | 32 | using System.Threading; |
33 | using log4net; | ||
32 | using OpenMetaverse; | 34 | using OpenMetaverse; |
33 | using OpenSim.Framework; | 35 | using OpenSim.Framework; |
34 | using OpenSim.Framework.Monitoring; | 36 | using 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 | } |