opensim – Blame information for rev 4

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 eva 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 Thread cmdHandlerThread;
53 private static int cmdHandlerThreadCycleSleepms;
4 eva 54 private static readonly System.Timers.Timer cmdEventTimer = new System.Timers.Timer();
1 eva 55  
56 /// <summary>
57 /// Lock for reading/writing static components of AsyncCommandManager.
58 /// </summary>
59 /// <remarks>
60 /// This lock exists so that multiple threads from different engines and/or different copies of the same engine
61 /// are prevented from running non-thread safe code (e.g. read/write of lists) concurrently.
62 /// </remarks>
63 private static object staticLock = new object();
64  
65 private static List<IScriptEngine> m_ScriptEngines =
66 new List<IScriptEngine>();
67  
68 public IScriptEngine m_ScriptEngine;
69  
70 private static Dictionary<IScriptEngine, Dataserver> m_Dataserver =
71 new Dictionary<IScriptEngine, Dataserver>();
72 private static Dictionary<IScriptEngine, Timer> m_Timer =
73 new Dictionary<IScriptEngine, Timer>();
74 private static Dictionary<IScriptEngine, Listener> m_Listener =
75 new Dictionary<IScriptEngine, Listener>();
76 private static Dictionary<IScriptEngine, HttpRequest> m_HttpRequest =
77 new Dictionary<IScriptEngine, HttpRequest>();
78 private static Dictionary<IScriptEngine, SensorRepeat> m_SensorRepeat =
79 new Dictionary<IScriptEngine, SensorRepeat>();
80 private static Dictionary<IScriptEngine, XmlRequest> m_XmlRequest =
81 new Dictionary<IScriptEngine, XmlRequest>();
82  
83 public Dataserver DataserverPlugin
84 {
85 get
86 {
87 lock (staticLock)
88 return m_Dataserver[m_ScriptEngine];
89 }
90 }
91  
92 public Timer TimerPlugin
93 {
94 get
95 {
96 lock (staticLock)
97 return m_Timer[m_ScriptEngine];
98 }
99 }
100  
101 public HttpRequest HttpRequestPlugin
102 {
103 get
104 {
105 lock (staticLock)
106 return m_HttpRequest[m_ScriptEngine];
107 }
108 }
109  
110 public Listener ListenerPlugin
111 {
112 get
113 {
114 lock (staticLock)
115 return m_Listener[m_ScriptEngine];
116 }
117 }
118  
119 public SensorRepeat SensorRepeatPlugin
120 {
121 get
122 {
123 lock (staticLock)
124 return m_SensorRepeat[m_ScriptEngine];
125 }
126 }
127  
128 public XmlRequest XmlRequestPlugin
129 {
130 get
131 {
132 lock (staticLock)
133 return m_XmlRequest[m_ScriptEngine];
134 }
135 }
136  
137 public IScriptEngine[] ScriptEngines
138 {
139 get
140 {
141 lock (staticLock)
142 return m_ScriptEngines.ToArray();
143 }
144 }
145  
146 public AsyncCommandManager(IScriptEngine _ScriptEngine)
147 {
148 m_ScriptEngine = _ScriptEngine;
149  
150 // If there is more than one scene in the simulator or multiple script engines are used on the same region
151 // then more than one thread could arrive at this block of code simultaneously. However, it cannot be
152 // executed concurrently both because concurrent list operations are not thread-safe and because of other
153 // race conditions such as the later check of cmdHandlerThread == null.
154 lock (staticLock)
155 {
156 if (m_ScriptEngines.Count == 0)
157 ReadConfig();
158  
159 if (!m_ScriptEngines.Contains(m_ScriptEngine))
160 m_ScriptEngines.Add(m_ScriptEngine);
161  
162 // Create instances of all plugins
163 if (!m_Dataserver.ContainsKey(m_ScriptEngine))
164 m_Dataserver[m_ScriptEngine] = new Dataserver(this);
165 if (!m_Timer.ContainsKey(m_ScriptEngine))
166 m_Timer[m_ScriptEngine] = new Timer(this);
167 if (!m_HttpRequest.ContainsKey(m_ScriptEngine))
168 m_HttpRequest[m_ScriptEngine] = new HttpRequest(this);
169 if (!m_Listener.ContainsKey(m_ScriptEngine))
170 m_Listener[m_ScriptEngine] = new Listener(this);
171 if (!m_SensorRepeat.ContainsKey(m_ScriptEngine))
172 m_SensorRepeat[m_ScriptEngine] = new SensorRepeat(this);
173 if (!m_XmlRequest.ContainsKey(m_ScriptEngine))
174 m_XmlRequest[m_ScriptEngine] = new XmlRequest(this);
175  
176 StartThread();
177 }
178 }
179  
180 private static void StartThread()
181 {
4 eva 182 if (!cmdEventTimer.Enabled.Equals(false)) return;
183 // Start the timer event
184 cmdEventTimer.Elapsed += (sender, args) =>
1 eva 185 {
4 eva 186 try
187 {
188 DoOneCmdHandlerPass();
189 }
190 catch (Exception e)
191 {
192 m_log.Error("[ASYNC COMMAND MANAGER]: Exception in command handler pass: ", e);
193 }
194 };
195 cmdEventTimer.Interval = cmdHandlerThreadCycleSleepms;
196 cmdEventTimer.Enabled = true;
1 eva 197 }
198  
199 private void ReadConfig()
200 {
201 // cmdHandlerThreadCycleSleepms = m_ScriptEngine.Config.GetInt("AsyncLLCommandLoopms", 100);
202 // TODO: Make this sane again
4 eva 203 cmdHandlerThreadCycleSleepms = 10;
1 eva 204 }
205  
206 ~AsyncCommandManager()
207 {
208 // Shut down thread
209 // try
210 // {
211 // if (cmdHandlerThread != null)
212 // {
213 // if (cmdHandlerThread.IsAlive == true)
214 // {
215 // cmdHandlerThread.Abort();
216 // //cmdHandlerThread.Join();
217 // }
218 // }
219 // }
220 // catch
221 // {
222 // }
223 }
224  
225 /// <summary>
226 /// Main loop for the manager thread
227 /// </summary>
228 private static void CmdHandlerThreadLoop()
229 {
230 while (true)
231 {
232 try
233 {
4 eva 234 Thread.Sleep(cmdHandlerThreadCycleSleepms);
1 eva 235  
236 DoOneCmdHandlerPass();
4 eva 237  
1 eva 238 Watchdog.UpdateThread();
239 }
240 catch (Exception e)
241 {
242 m_log.Error("[ASYNC COMMAND MANAGER]: Exception in command handler pass: ", e);
243 }
244 }
245 }
246  
247 private static void DoOneCmdHandlerPass()
248 {
249 lock (staticLock)
250 {
251 // Check HttpRequests
252 m_HttpRequest[m_ScriptEngines[0]].CheckHttpRequests();
253  
254 // Check XMLRPCRequests
255 m_XmlRequest[m_ScriptEngines[0]].CheckXMLRPCRequests();
256  
257 foreach (IScriptEngine s in m_ScriptEngines)
258 {
259 // Check Listeners
260 m_Listener[s].CheckListeners();
261  
262 // Check timers
263 m_Timer[s].CheckTimerEvents();
264  
265 // Check Sensors
266 m_SensorRepeat[s].CheckSenseRepeaterEvents();
267  
268 // Check dataserver
269 m_Dataserver[s].ExpireRequests();
270 }
271 }
272 }
273  
274 /// <summary>
275 /// Remove a specific script (and all its pending commands)
276 /// </summary>
277 /// <param name="localID"></param>
278 /// <param name="itemID"></param>
279 public static void RemoveScript(IScriptEngine engine, uint localID, UUID itemID)
280 {
281 // m_log.DebugFormat("[ASYNC COMMAND MANAGER]: Removing facilities for script {0}", itemID);
282  
283 lock (staticLock)
284 {
285 // Remove dataserver events
286 m_Dataserver[engine].RemoveEvents(localID, itemID);
287  
288 // Remove from: Timers
289 m_Timer[engine].UnSetTimerEvents(localID, itemID);
290  
291 // Remove from: HttpRequest
292 IHttpRequestModule iHttpReq = engine.World.RequestModuleInterface<IHttpRequestModule>();
293 if (iHttpReq != null)
294 iHttpReq.StopHttpRequestsForScript(itemID);
295  
296 IWorldComm comms = engine.World.RequestModuleInterface<IWorldComm>();
297 if (comms != null)
298 comms.DeleteListener(itemID);
299  
300 IXMLRPC xmlrpc = engine.World.RequestModuleInterface<IXMLRPC>();
301 if (xmlrpc != null)
302 {
303 xmlrpc.DeleteChannels(itemID);
304 xmlrpc.CancelSRDRequests(itemID);
305 }
306  
307 // Remove Sensors
308 m_SensorRepeat[engine].UnSetSenseRepeaterEvents(localID, itemID);
309 }
310 }
311  
312 /// <summary>
313 /// Get the sensor repeat plugin for this script engine.
314 /// </summary>
315 /// <param name="engine"></param>
316 /// <returns></returns>
317 public static SensorRepeat GetSensorRepeatPlugin(IScriptEngine engine)
318 {
319 lock (staticLock)
320 {
321 if (m_SensorRepeat.ContainsKey(engine))
322 return m_SensorRepeat[engine];
323 else
324 return null;
325 }
326 }
327  
328 /// <summary>
329 /// Get the dataserver plugin for this script engine.
330 /// </summary>
331 /// <param name="engine"></param>
332 /// <returns></returns>
333 public static Dataserver GetDataserverPlugin(IScriptEngine engine)
334 {
335 lock (staticLock)
336 {
337 if (m_Dataserver.ContainsKey(engine))
338 return m_Dataserver[engine];
339 else
340 return null;
341 }
342 }
343  
344 /// <summary>
345 /// Get the timer plugin for this script engine.
346 /// </summary>
347 /// <param name="engine"></param>
348 /// <returns></returns>
349 public static Timer GetTimerPlugin(IScriptEngine engine)
350 {
351 lock (staticLock)
352 {
353 if (m_Timer.ContainsKey(engine))
354 return m_Timer[engine];
355 else
356 return null;
357 }
358 }
359  
360 /// <summary>
361 /// Get the listener plugin for this script engine.
362 /// </summary>
363 /// <param name="engine"></param>
364 /// <returns></returns>
365 public static Listener GetListenerPlugin(IScriptEngine engine)
366 {
367 lock (staticLock)
368 {
369 if (m_Listener.ContainsKey(engine))
370 return m_Listener[engine];
371 else
372 return null;
373 }
374 }
375  
376 public static Object[] GetSerializationData(IScriptEngine engine, UUID itemID)
377 {
378 List<Object> data = new List<Object>();
379  
380 lock (staticLock)
381 {
382 Object[] listeners = m_Listener[engine].GetSerializationData(itemID);
383 if (listeners.Length > 0)
384 {
385 data.Add("listener");
386 data.Add(listeners.Length);
387 data.AddRange(listeners);
388 }
389  
390 Object[] timers=m_Timer[engine].GetSerializationData(itemID);
391 if (timers.Length > 0)
392 {
393 data.Add("timer");
394 data.Add(timers.Length);
395 data.AddRange(timers);
396 }
397  
398 Object[] sensors = m_SensorRepeat[engine].GetSerializationData(itemID);
399 if (sensors.Length > 0)
400 {
401 data.Add("sensor");
402 data.Add(sensors.Length);
403 data.AddRange(sensors);
404 }
405 }
406  
407 return data.ToArray();
408 }
409  
410 public static void CreateFromData(IScriptEngine engine, uint localID,
411 UUID itemID, UUID hostID, Object[] data)
412 {
413 int idx = 0;
414 int len;
415  
416 while (idx < data.Length)
417 {
418 string type = data[idx].ToString();
419 len = (int)data[idx+1];
420 idx+=2;
421  
422 if (len > 0)
423 {
424 Object[] item = new Object[len];
425 Array.Copy(data, idx, item, 0, len);
426  
427 idx+=len;
428  
429 lock (staticLock)
430 {
431 switch (type)
432 {
433 case "listener":
434 m_Listener[engine].CreateFromData(localID, itemID,
435 hostID, item);
436 break;
437 case "timer":
438 m_Timer[engine].CreateFromData(localID, itemID,
439 hostID, item);
440 break;
441 case "sensor":
442 m_SensorRepeat[engine].CreateFromData(localID,
443 itemID, hostID, item);
444 break;
445 }
446 }
447 }
448 }
449 }
450 }
4 eva 451 }