opensim-development – Blame information for rev 2

Subversion Repositories:
Rev:
Rev Author Line No. Line
2 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;
1 eva 53 private static int cmdHandlerThreadCycleSleepms;
2 eva 54 private static readonly System.Timers.Timer cmdEventTimer = new System.Timers.Timer();
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
1 eva 84 {
2 eva 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 {
1 eva 182 if (!cmdEventTimer.Enabled.Equals(false)) return;
183 // Start the timer event
184 cmdEventTimer.Elapsed += (sender, args) =>
185 {
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;
2 eva 197 }
198  
199 private void ReadConfig()
200 {
201 // cmdHandlerThreadCycleSleepms = m_ScriptEngine.Config.GetInt("AsyncLLCommandLoopms", 100);
202 // TODO: Make this sane again
203 cmdHandlerThreadCycleSleepms = 10;
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 private static void DoOneCmdHandlerPass()
226 {
227 lock (staticLock)
228 {
229 // Check HttpRequests
230 m_HttpRequest[m_ScriptEngines[0]].CheckHttpRequests();
231  
232 // Check XMLRPCRequests
233 m_XmlRequest[m_ScriptEngines[0]].CheckXMLRPCRequests();
234  
235 foreach (IScriptEngine s in m_ScriptEngines)
236 {
237 // Check Listeners
238 m_Listener[s].CheckListeners();
239  
240 // Check timers
241 m_Timer[s].CheckTimerEvents();
242  
243 // Check Sensors
244 m_SensorRepeat[s].CheckSenseRepeaterEvents();
245  
246 // Check dataserver
247 m_Dataserver[s].ExpireRequests();
248 }
249 }
250 }
251  
252 /// <summary>
253 /// Remove a specific script (and all its pending commands)
254 /// </summary>
255 /// <param name="localID"></param>
256 /// <param name="itemID"></param>
257 public static void RemoveScript(IScriptEngine engine, uint localID, UUID itemID)
258 {
259 // m_log.DebugFormat("[ASYNC COMMAND MANAGER]: Removing facilities for script {0}", itemID);
260  
261 lock (staticLock)
262 {
263 // Remove dataserver events
264 m_Dataserver[engine].RemoveEvents(localID, itemID);
265  
266 // Remove from: Timers
267 m_Timer[engine].UnSetTimerEvents(localID, itemID);
268  
269 // Remove from: HttpRequest
270 IHttpRequestModule iHttpReq = engine.World.RequestModuleInterface<IHttpRequestModule>();
271 if (iHttpReq != null)
272 iHttpReq.StopHttpRequestsForScript(itemID);
273  
274 IWorldComm comms = engine.World.RequestModuleInterface<IWorldComm>();
275 if (comms != null)
276 comms.DeleteListener(itemID);
277  
278 IXMLRPC xmlrpc = engine.World.RequestModuleInterface<IXMLRPC>();
279 if (xmlrpc != null)
280 {
281 xmlrpc.DeleteChannels(itemID);
282 xmlrpc.CancelSRDRequests(itemID);
283 }
284  
285 // Remove Sensors
286 m_SensorRepeat[engine].UnSetSenseRepeaterEvents(localID, itemID);
287 }
288 }
289  
290 /// <summary>
291 /// Get the sensor repeat plugin for this script engine.
292 /// </summary>
293 /// <param name="engine"></param>
294 /// <returns></returns>
295 public static SensorRepeat GetSensorRepeatPlugin(IScriptEngine engine)
296 {
297 lock (staticLock)
298 {
299 if (m_SensorRepeat.ContainsKey(engine))
300 return m_SensorRepeat[engine];
301 else
302 return null;
303 }
304 }
305  
306 /// <summary>
307 /// Get the dataserver plugin for this script engine.
308 /// </summary>
309 /// <param name="engine"></param>
310 /// <returns></returns>
311 public static Dataserver GetDataserverPlugin(IScriptEngine engine)
312 {
313 lock (staticLock)
314 {
315 if (m_Dataserver.ContainsKey(engine))
316 return m_Dataserver[engine];
317 else
318 return null;
319 }
320 }
321  
322 /// <summary>
323 /// Get the timer plugin for this script engine.
324 /// </summary>
325 /// <param name="engine"></param>
326 /// <returns></returns>
327 public static Timer GetTimerPlugin(IScriptEngine engine)
328 {
329 lock (staticLock)
330 {
331 if (m_Timer.ContainsKey(engine))
332 return m_Timer[engine];
333 else
334 return null;
335 }
336 }
337  
338 /// <summary>
339 /// Get the listener plugin for this script engine.
340 /// </summary>
341 /// <param name="engine"></param>
342 /// <returns></returns>
343 public static Listener GetListenerPlugin(IScriptEngine engine)
344 {
345 lock (staticLock)
346 {
347 if (m_Listener.ContainsKey(engine))
348 return m_Listener[engine];
349 else
350 return null;
351 }
352 }
353  
354 public static Object[] GetSerializationData(IScriptEngine engine, UUID itemID)
355 {
356 List<Object> data = new List<Object>();
357  
358 lock (staticLock)
359 {
360 Object[] listeners = m_Listener[engine].GetSerializationData(itemID);
361 if (listeners.Length > 0)
362 {
363 data.Add("listener");
364 data.Add(listeners.Length);
365 data.AddRange(listeners);
366 }
367  
368 Object[] timers=m_Timer[engine].GetSerializationData(itemID);
369 if (timers.Length > 0)
370 {
371 data.Add("timer");
372 data.Add(timers.Length);
373 data.AddRange(timers);
374 }
375  
376 Object[] sensors = m_SensorRepeat[engine].GetSerializationData(itemID);
377 if (sensors.Length > 0)
378 {
379 data.Add("sensor");
380 data.Add(sensors.Length);
381 data.AddRange(sensors);
382 }
383 }
384  
385 return data.ToArray();
386 }
387  
388 public static void CreateFromData(IScriptEngine engine, uint localID,
389 UUID itemID, UUID hostID, Object[] data)
390 {
391 int idx = 0;
392 int len;
393  
394 while (idx < data.Length)
395 {
396 string type = data[idx].ToString();
397 len = (int)data[idx+1];
398 idx+=2;
399  
400 if (len > 0)
401 {
402 Object[] item = new Object[len];
403 Array.Copy(data, idx, item, 0, len);
404  
405 idx+=len;
406  
407 lock (staticLock)
408 {
409 switch (type)
410 {
411 case "listener":
412 m_Listener[engine].CreateFromData(localID, itemID,
413 hostID, item);
414 break;
415 case "timer":
416 m_Timer[engine].CreateFromData(localID, itemID,
417 hostID, item);
418 break;
419 case "sensor":
420 m_SensorRepeat[engine].CreateFromData(localID,
421 itemID, hostID, item);
422 break;
423 }
424 }
425 }
426 }
427 }
428 }
429 }