clockwerk-opensim – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 vero 1 /*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27  
28 using System;
29 using System.Collections;
30 using System.Collections.Generic;
31 using System.Reflection;
32 using System.Threading;
33 using log4net;
34 using OpenMetaverse;
35 using OpenSim.Framework;
36 using OpenSim.Framework.Monitoring;
37 using OpenSim.Region.Framework.Interfaces;
38 using OpenSim.Region.ScriptEngine.Interfaces;
39 using OpenSim.Region.ScriptEngine.Shared;
40 using OpenSim.Region.ScriptEngine.Shared.Api.Plugins;
41 using Timer=OpenSim.Region.ScriptEngine.Shared.Api.Plugins.Timer;
42  
43 namespace OpenSim.Region.ScriptEngine.Shared.Api
44 {
45 /// <summary>
46 /// Handles LSL commands that takes long time and returns an event, for example timers, HTTP requests, etc.
47 /// </summary>
48 public class AsyncCommandManager
49 {
50 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
51  
52 private static int cmdHandlerThreadCycleSleepms;
53 private static readonly System.Timers.Timer cmdEventTimer = new System.Timers.Timer();
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  
64 private static List<IScriptEngine> m_ScriptEngines =
65 new List<IScriptEngine>();
66  
67 public IScriptEngine m_ScriptEngine;
68  
69 private static Dictionary<IScriptEngine, Dataserver> m_Dataserver =
70 new Dictionary<IScriptEngine, Dataserver>();
71 private static Dictionary<IScriptEngine, Timer> m_Timer =
72 new Dictionary<IScriptEngine, Timer>();
73 private static Dictionary<IScriptEngine, Listener> m_Listener =
74 new Dictionary<IScriptEngine, Listener>();
75 private static Dictionary<IScriptEngine, HttpRequest> m_HttpRequest =
76 new Dictionary<IScriptEngine, HttpRequest>();
77 private static Dictionary<IScriptEngine, SensorRepeat> m_SensorRepeat =
78 new Dictionary<IScriptEngine, SensorRepeat>();
79 private static Dictionary<IScriptEngine, XmlRequest> m_XmlRequest =
80 new Dictionary<IScriptEngine, XmlRequest>();
81  
82 public Dataserver DataserverPlugin
83 {
84 get
85 {
86 lock (staticLock)
87 return m_Dataserver[m_ScriptEngine];
88 }
89 }
90  
91 public Timer TimerPlugin
92 {
93 get
94 {
95 lock (staticLock)
96 return m_Timer[m_ScriptEngine];
97 }
98 }
99  
100 public HttpRequest HttpRequestPlugin
101 {
102 get
103 {
104 lock (staticLock)
105 return m_HttpRequest[m_ScriptEngine];
106 }
107 }
108  
109 public Listener ListenerPlugin
110 {
111 get
112 {
113 lock (staticLock)
114 return m_Listener[m_ScriptEngine];
115 }
116 }
117  
118 public SensorRepeat SensorRepeatPlugin
119 {
120 get
121 {
122 lock (staticLock)
123 return m_SensorRepeat[m_ScriptEngine];
124 }
125 }
126  
127 public XmlRequest XmlRequestPlugin
128 {
129 get
130 {
131 lock (staticLock)
132 return m_XmlRequest[m_ScriptEngine];
133 }
134 }
135  
136 public IScriptEngine[] ScriptEngines
137 {
138 get
139 {
140 lock (staticLock)
141 return m_ScriptEngines.ToArray();
142 }
143 }
144  
145 public AsyncCommandManager(IScriptEngine _ScriptEngine)
146 {
147 m_ScriptEngine = _ScriptEngine;
148  
149 // If there is more than one scene in the simulator or multiple script engines are used on the same region
150 // then more than one thread could arrive at this block of code simultaneously. However, it cannot be
151 // executed concurrently both because concurrent list operations are not thread-safe and because of other
152 // race conditions such as the later check of cmdHandlerThread == null.
153 lock (staticLock)
154 {
155 if (m_ScriptEngines.Count == 0)
156 ReadConfig();
157  
158 if (!m_ScriptEngines.Contains(m_ScriptEngine))
159 m_ScriptEngines.Add(m_ScriptEngine);
160  
161 // Create instances of all plugins
162 if (!m_Dataserver.ContainsKey(m_ScriptEngine))
163 m_Dataserver[m_ScriptEngine] = new Dataserver(this);
164 if (!m_Timer.ContainsKey(m_ScriptEngine))
165 m_Timer[m_ScriptEngine] = new Timer(this);
166 if (!m_HttpRequest.ContainsKey(m_ScriptEngine))
167 m_HttpRequest[m_ScriptEngine] = new HttpRequest(this);
168 if (!m_Listener.ContainsKey(m_ScriptEngine))
169 m_Listener[m_ScriptEngine] = new Listener(this);
170 if (!m_SensorRepeat.ContainsKey(m_ScriptEngine))
171 m_SensorRepeat[m_ScriptEngine] = new SensorRepeat(this);
172 if (!m_XmlRequest.ContainsKey(m_ScriptEngine))
173 m_XmlRequest[m_ScriptEngine] = new XmlRequest(this);
174  
175 if (cmdEventTimer.Enabled.Equals(true)) return;
176 // Start the timer
177 cmdEventTimer.Elapsed += (sender, args) =>
178 {
179 try
180 {
181 DoOneCmdHandlerPass();
182 }
183 catch (Exception e)
184 {
185 m_log.Error("[ASYNC COMMAND MANAGER]: Exception in command handler pass: ", e);
186 }
187 };
188  
189 cmdEventTimer.Interval = cmdHandlerThreadCycleSleepms;
190 cmdEventTimer.Enabled = true;
191 }
192 }
193  
194 private void ReadConfig()
195 {
196 // cmdHandlerThreadCycleSleepms = m_ScriptEngine.Config.GetInt("AsyncLLCommandLoopms", 100);
197 // TODO: Make this sane again
198 cmdHandlerThreadCycleSleepms = 50;
199 }
200  
201 ~AsyncCommandManager()
202 {
203 // Shut down thread
204 // try
205 // {
206 // if (cmdHandlerThread != null)
207 // {
208 // if (cmdHandlerThread.IsAlive == true)
209 // {
210 // cmdHandlerThread.Abort();
211 // //cmdHandlerThread.Join();
212 // }
213 // }
214 // }
215 // catch
216 // {
217 // }
218 }
219  
220 /// <summary>
221 /// Main loop for the manager thread
222 /// </summary>
223 private static void CmdHandlerThreadLoop()
224 {
225 while (true)
226 {
227 try
228 {
229 Thread.Sleep(cmdHandlerThreadCycleSleepms);
230  
231 DoOneCmdHandlerPass();
232  
233 Watchdog.UpdateThread();
234 }
235 catch (Exception e)
236 {
237 m_log.Error("[ASYNC COMMAND MANAGER]: Exception in command handler pass: ", e);
238 }
239 }
240 }
241  
242 private static void DoOneCmdHandlerPass()
243 {
244 lock (staticLock)
245 {
246 // Check HttpRequests
247 m_HttpRequest[m_ScriptEngines[0]].CheckHttpRequests();
248  
249 // Check XMLRPCRequests
250 m_XmlRequest[m_ScriptEngines[0]].CheckXMLRPCRequests();
251  
252 foreach (IScriptEngine s in m_ScriptEngines)
253 {
254 // Check Listeners
255 m_Listener[s].CheckListeners();
256  
257 // Check timers
258 m_Timer[s].CheckTimerEvents();
259  
260 // Check Sensors
261 m_SensorRepeat[s].CheckSenseRepeaterEvents();
262  
263 // Check dataserver
264 m_Dataserver[s].ExpireRequests();
265 }
266 }
267 }
268  
269 /// <summary>
270 /// Remove a specific script (and all its pending commands)
271 /// </summary>
272 /// <param name="localID"></param>
273 /// <param name="itemID"></param>
274 public static void RemoveScript(IScriptEngine engine, uint localID, UUID itemID)
275 {
276 // m_log.DebugFormat("[ASYNC COMMAND MANAGER]: Removing facilities for script {0}", itemID);
277  
278 lock (staticLock)
279 {
280 // Remove dataserver events
281 m_Dataserver[engine].RemoveEvents(localID, itemID);
282  
283 // Remove from: Timers
284 m_Timer[engine].UnSetTimerEvents(localID, itemID);
285  
286 // Remove from: HttpRequest
287 IHttpRequestModule iHttpReq = engine.World.RequestModuleInterface<IHttpRequestModule>();
288 if (iHttpReq != null)
289 iHttpReq.StopHttpRequestsForScript(itemID);
290  
291 IWorldComm comms = engine.World.RequestModuleInterface<IWorldComm>();
292 if (comms != null)
293 comms.DeleteListener(itemID);
294  
295 IXMLRPC xmlrpc = engine.World.RequestModuleInterface<IXMLRPC>();
296 if (xmlrpc != null)
297 {
298 xmlrpc.DeleteChannels(itemID);
299 xmlrpc.CancelSRDRequests(itemID);
300 }
301  
302 // Remove Sensors
303 m_SensorRepeat[engine].UnSetSenseRepeaterEvents(localID, itemID);
304 }
305 }
306  
307 public static void StateChange(IScriptEngine engine, uint localID, UUID itemID)
308 {
309 // Remove a specific script
310  
311 // Remove dataserver events
312 m_Dataserver[engine].RemoveEvents(localID, itemID);
313  
314 IWorldComm comms = engine.World.RequestModuleInterface<IWorldComm>();
315 if (comms != null)
316 comms.DeleteListener(itemID);
317  
318 IXMLRPC xmlrpc = engine.World.RequestModuleInterface<IXMLRPC>();
319 if (xmlrpc != null)
320 {
321 xmlrpc.DeleteChannels(itemID);
322 xmlrpc.CancelSRDRequests(itemID);
323 }
324 // Remove Sensors
325 m_SensorRepeat[engine].UnSetSenseRepeaterEvents(localID, itemID);
326  
327 }
328  
329 /// <summary>
330 /// Get the sensor repeat plugin for this script engine.
331 /// </summary>
332 /// <param name="engine"></param>
333 /// <returns></returns>
334 public static SensorRepeat GetSensorRepeatPlugin(IScriptEngine engine)
335 {
336 lock (staticLock)
337 {
338 if (m_SensorRepeat.ContainsKey(engine))
339 return m_SensorRepeat[engine];
340 else
341 return null;
342 }
343 }
344  
345 /// <summary>
346 /// Get the dataserver plugin for this script engine.
347 /// </summary>
348 /// <param name="engine"></param>
349 /// <returns></returns>
350 public static Dataserver GetDataserverPlugin(IScriptEngine engine)
351 {
352 lock (staticLock)
353 {
354 if (m_Dataserver.ContainsKey(engine))
355 return m_Dataserver[engine];
356 else
357 return null;
358 }
359 }
360  
361 /// <summary>
362 /// Get the timer plugin for this script engine.
363 /// </summary>
364 /// <param name="engine"></param>
365 /// <returns></returns>
366 public static Timer GetTimerPlugin(IScriptEngine engine)
367 {
368 lock (staticLock)
369 {
370 if (m_Timer.ContainsKey(engine))
371 return m_Timer[engine];
372 else
373 return null;
374 }
375 }
376  
377 /// <summary>
378 /// Get the listener plugin for this script engine.
379 /// </summary>
380 /// <param name="engine"></param>
381 /// <returns></returns>
382 public static Listener GetListenerPlugin(IScriptEngine engine)
383 {
384 lock (staticLock)
385 {
386 if (m_Listener.ContainsKey(engine))
387 return m_Listener[engine];
388 else
389 return null;
390 }
391 }
392  
393 public static Object[] GetSerializationData(IScriptEngine engine, UUID itemID)
394 {
395 List<Object> data = new List<Object>();
396  
397 lock (staticLock)
398 {
399 Object[] listeners = m_Listener[engine].GetSerializationData(itemID);
400 if (listeners.Length > 0)
401 {
402 data.Add("listener");
403 data.Add(listeners.Length);
404 data.AddRange(listeners);
405 }
406  
407 Object[] timers=m_Timer[engine].GetSerializationData(itemID);
408 if (timers.Length > 0)
409 {
410 data.Add("timer");
411 data.Add(timers.Length);
412 data.AddRange(timers);
413 }
414  
415 Object[] sensors = m_SensorRepeat[engine].GetSerializationData(itemID);
416 if (sensors.Length > 0)
417 {
418 data.Add("sensor");
419 data.Add(sensors.Length);
420 data.AddRange(sensors);
421 }
422 }
423  
424 return data.ToArray();
425 }
426  
427 public static void CreateFromData(IScriptEngine engine, uint localID,
428 UUID itemID, UUID hostID, Object[] data)
429 {
430 int idx = 0;
431 int len;
432  
433 while (idx < data.Length)
434 {
435 string type = data[idx].ToString();
436 len = (int)data[idx+1];
437 idx+=2;
438  
439 if (len > 0)
440 {
441 Object[] item = new Object[len];
442 Array.Copy(data, idx, item, 0, len);
443  
444 idx+=len;
445  
446 lock (staticLock)
447 {
448 switch (type)
449 {
450 case "listener":
451 m_Listener[engine].CreateFromData(localID, itemID,
452 hostID, item);
453 break;
454 case "timer":
455 m_Timer[engine].CreateFromData(localID, itemID,
456 hostID, item);
457 break;
458 case "sensor":
459 m_SensorRepeat[engine].CreateFromData(localID,
460 itemID, hostID, item);
461 break;
462 }
463 }
464 }
465 }
466 }
467 }
468 }