OpenSim
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros
AsyncCommandManager.cs
Go to the documentation of this file.
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.Threading;
32 using OpenMetaverse;
33 using OpenSim.Framework;
34 using OpenSim.Framework.Monitoring;
35 using OpenSim.Region.Framework.Interfaces;
36 using OpenSim.Region.ScriptEngine.Interfaces;
37 using OpenSim.Region.ScriptEngine.Shared;
38 using OpenSim.Region.ScriptEngine.Shared.Api.Plugins;
40 using System.Reflection;
41 using log4net;
42 
43 namespace OpenSim.Region.ScriptEngine.Shared.Api
44 {
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;
54 
62  private static object staticLock = new object();
63 
64  private static List<IScriptEngine> m_ScriptEngines =
65  new List<IScriptEngine>();
66 
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  StartThread();
176  }
177  }
178 
179  private static void StartThread()
180  {
181  if (cmdHandlerThread == null)
182  {
183  // Start the thread that will be doing the work
184  cmdHandlerThread
185  = WorkManager.StartThread(
186  CmdHandlerThreadLoop, "AsyncLSLCmdHandlerThread", ThreadPriority.Normal, true, true);
187  }
188  }
189 
190  private void ReadConfig()
191  {
192 // cmdHandlerThreadCycleSleepms = m_ScriptEngine.Config.GetInt("AsyncLLCommandLoopms", 100);
193  // TODO: Make this sane again
194  cmdHandlerThreadCycleSleepms = 100;
195  }
196 
197  ~AsyncCommandManager()
198  {
199  // Shut down thread
200 // try
201 // {
202 // if (cmdHandlerThread != null)
203 // {
204 // if (cmdHandlerThread.IsAlive == true)
205 // {
206 // cmdHandlerThread.Abort();
207 // //cmdHandlerThread.Join();
208 // }
209 // }
210 // }
211 // catch
212 // {
213 // }
214  }
215 
219  private static void CmdHandlerThreadLoop()
220  {
221  while (true)
222  {
223  try
224  {
225  Thread.Sleep(cmdHandlerThreadCycleSleepms);
226 
227  DoOneCmdHandlerPass();
228 
229  Watchdog.UpdateThread();
230  }
231  catch (Exception e)
232  {
233  m_log.Error("[ASYNC COMMAND MANAGER]: Exception in command handler pass: ", e);
234  }
235  }
236  }
237 
238  private static void DoOneCmdHandlerPass()
239  {
240  lock (staticLock)
241  {
242  // Check HttpRequests
243  m_HttpRequest[m_ScriptEngines[0]].CheckHttpRequests();
244 
245  // Check XMLRPCRequests
246  m_XmlRequest[m_ScriptEngines[0]].CheckXMLRPCRequests();
247 
248  foreach (IScriptEngine s in m_ScriptEngines)
249  {
250  // Check Listeners
251  m_Listener[s].CheckListeners();
252 
253  // Check timers
254  m_Timer[s].CheckTimerEvents();
255 
256  // Check Sensors
257  m_SensorRepeat[s].CheckSenseRepeaterEvents();
258 
259  // Check dataserver
260  m_Dataserver[s].ExpireRequests();
261  }
262  }
263  }
264 
270  public static void RemoveScript(IScriptEngine engine, uint localID, UUID itemID)
271  {
272  // Remove a specific script
273 // m_log.DebugFormat("[ASYNC COMMAND MANAGER]: Removing facilities for script {0}", itemID);
274 
275  lock (staticLock)
276  {
277  // Remove dataserver events
278  m_Dataserver[engine].RemoveEvents(localID, itemID);
279 
280  // Remove from: Timers
281  m_Timer[engine].UnSetTimerEvents(localID, itemID);
282 
283  // Remove from: HttpRequest
284  IHttpRequestModule iHttpReq = engine.World.RequestModuleInterface<IHttpRequestModule>();
285  if (iHttpReq != null)
286  iHttpReq.StopHttpRequest(localID, itemID);
287 
288  IWorldComm comms = engine.World.RequestModuleInterface<IWorldComm>();
289  if (comms != null)
290  comms.DeleteListener(itemID);
291 
292  IXMLRPC xmlrpc = engine.World.RequestModuleInterface<IXMLRPC>();
293  if (xmlrpc != null)
294  {
295  xmlrpc.DeleteChannels(itemID);
296  xmlrpc.CancelSRDRequests(itemID);
297  }
298 
299  // Remove Sensors
300  m_SensorRepeat[engine].UnSetSenseRepeaterEvents(localID, itemID);
301  }
302  }
303 
304  public static void StateChange(IScriptEngine engine, uint localID, UUID itemID)
305  {
306  // Remove a specific script
307 
308  // Remove dataserver events
309  m_Dataserver[engine].RemoveEvents(localID, itemID);
310 
311  IWorldComm comms = engine.World.RequestModuleInterface<IWorldComm>();
312  if (comms != null)
313  comms.DeleteListener(itemID);
314 
315  IXMLRPC xmlrpc = engine.World.RequestModuleInterface<IXMLRPC>();
316  if (xmlrpc != null)
317  {
318  xmlrpc.DeleteChannels(itemID);
319  xmlrpc.CancelSRDRequests(itemID);
320  }
321  // Remove Sensors
322  m_SensorRepeat[engine].UnSetSenseRepeaterEvents(localID, itemID);
323 
324  }
325 
332  {
333  lock (staticLock)
334  {
335  if (m_SensorRepeat.ContainsKey(engine))
336  return m_SensorRepeat[engine];
337  else
338  return null;
339  }
340  }
341 
348  {
349  lock (staticLock)
350  {
351  if (m_Dataserver.ContainsKey(engine))
352  return m_Dataserver[engine];
353  else
354  return null;
355  }
356  }
357 
363  public static Timer GetTimerPlugin(IScriptEngine engine)
364  {
365  lock (staticLock)
366  {
367  if (m_Timer.ContainsKey(engine))
368  return m_Timer[engine];
369  else
370  return null;
371  }
372  }
373 
380  {
381  lock (staticLock)
382  {
383  if (m_Listener.ContainsKey(engine))
384  return m_Listener[engine];
385  else
386  return null;
387  }
388  }
389 
390 
391 
392  public static Object[] GetSerializationData(IScriptEngine engine, UUID itemID)
393  {
394  List<Object> data = new List<Object>();
395 
396  lock (staticLock)
397  {
398  Object[] listeners = m_Listener[engine].GetSerializationData(itemID);
399  if (listeners.Length > 0)
400  {
401  data.Add("listener");
402  data.Add(listeners.Length);
403  data.AddRange(listeners);
404  }
405 
406  Object[] timers=m_Timer[engine].GetSerializationData(itemID);
407  if (timers.Length > 0)
408  {
409  data.Add("timer");
410  data.Add(timers.Length);
411  data.AddRange(timers);
412  }
413 
414  Object[] sensors = m_SensorRepeat[engine].GetSerializationData(itemID);
415  if (sensors.Length > 0)
416  {
417  data.Add("sensor");
418  data.Add(sensors.Length);
419  data.AddRange(sensors);
420  }
421  }
422 
423  return data.ToArray();
424  }
425 
426  public static void CreateFromData(IScriptEngine engine, uint localID,
427  UUID itemID, UUID hostID, Object[] data)
428  {
429  int idx = 0;
430  int len;
431 
432  while (idx < data.Length)
433  {
434  string type = data[idx].ToString();
435  len = (int)data[idx+1];
436  idx+=2;
437 
438  if (len > 0)
439  {
440  Object[] item = new Object[len];
441  Array.Copy(data, idx, item, 0, len);
442 
443  idx+=len;
444 
445  lock (staticLock)
446  {
447  switch (type)
448  {
449  case "listener":
450  m_Listener[engine].CreateFromData(localID, itemID,
451  hostID, item);
452  break;
453  case "timer":
454  m_Timer[engine].CreateFromData(localID, itemID,
455  hostID, item);
456  break;
457  case "sensor":
458  m_SensorRepeat[engine].CreateFromData(localID,
459  itemID, hostID, item);
460  break;
461  }
462  }
463  }
464  }
465  }
466  }
467 }
static Timer GetTimerPlugin(IScriptEngine engine)
Get the timer plugin for this script engine.
Handles LSL commands that takes long time and returns an event, for example timers, HTTP requests, etc.
OpenSim.Region.ScriptEngine.Shared.Api.Plugins.Timer Timer
static void RemoveScript(IScriptEngine engine, uint localID, UUID itemID)
Remove a specific script (and all its pending commands)
static void StateChange(IScriptEngine engine, uint localID, UUID itemID)
static SensorRepeat GetSensorRepeatPlugin(IScriptEngine engine)
Get the sensor repeat plugin for this script engine.
An interface for a script API module to communicate with the engine it's running under ...
static Dataserver GetDataserverPlugin(IScriptEngine engine)
Get the dataserver plugin for this script engine.
static void CreateFromData(IScriptEngine engine, uint localID, UUID itemID, UUID hostID, Object[] data)
static Object[] GetSerializationData(IScriptEngine engine, UUID itemID)
static Listener GetListenerPlugin(IScriptEngine engine)
Get the listener plugin for this script engine.