aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ScriptEngine/XMREngine/XMREngine.cs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--OpenSim/Region/ScriptEngine/XMREngine/XMREngine.cs2102
1 files changed, 2102 insertions, 0 deletions
diff --git a/OpenSim/Region/ScriptEngine/XMREngine/XMREngine.cs b/OpenSim/Region/ScriptEngine/XMREngine/XMREngine.cs
new file mode 100644
index 0000000..7447f2f
--- /dev/null
+++ b/OpenSim/Region/ScriptEngine/XMREngine/XMREngine.cs
@@ -0,0 +1,2102 @@
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// based on XMREngine from Mike Rieker (Dreamnation) and Melanie Thielker
29// but with several changes to be more cross platform.
30
31
32using log4net;
33using Mono.Addins;
34using Nini.Config;
35using OpenSim.Framework;
36using OpenSim.Framework.Console;
37using OpenSim.Framework.Monitoring;
38using OpenSim.Region.ClientStack.Linden;
39using OpenSim.Region.Framework.Interfaces;
40using OpenSim.Region.Framework.Scenes;
41using OpenSim.Region.ScriptEngine.Interfaces;
42using OpenSim.Region.ScriptEngine.Shared;
43using OpenSim.Region.ScriptEngine.Shared.Api;
44using OpenMetaverse;
45using System;
46using System.Collections;
47using System.Collections.Generic;
48using System.Diagnostics;
49using System.IO;
50using System.Reflection;
51using System.Reflection.Emit;
52using System.Text;
53using System.Threading;
54using System.Timers;
55using System.Xml;
56
57using LSL_Float = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLFloat;
58using LSL_Integer = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLInteger;
59using LSL_Key = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
60using LSL_List = OpenSim.Region.ScriptEngine.Shared.LSL_Types.list;
61using LSL_Rotation = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion;
62using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
63using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3;
64
65[assembly: Addin("XMREngine", OpenSim.VersionInfo.VersionNumber)]
66[assembly: AddinDependency("OpenSim.Region.Framework", OpenSim.VersionInfo.VersionNumber)]
67
68namespace OpenSim.Region.ScriptEngine.XMREngine
69{
70 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "XMREngine")]
71 public partial class XMREngine : INonSharedRegionModule, IScriptEngine,
72 IScriptModule
73 {
74 public static readonly DetectParams[] zeroDetectParams = new DetectParams[0];
75 private static ArrayList noScriptErrors = new ArrayList();
76 public static readonly ILog m_log =
77 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
78 private static readonly string[] scriptReferencedAssemblies = new string[0];
79
80 private bool m_LateInit;
81 private bool m_TraceCalls;
82 public bool m_Verbose;
83 public bool m_ScriptDebug;
84 public Scene m_Scene;
85 private IConfigSource m_ConfigSource;
86 private IConfig m_Config;
87 private string m_ScriptBasePath;
88 private bool m_Enabled = false;
89 public bool m_StartProcessing = false;
90 public bool m_UseSourceHashCode = false;
91 public ConstructorInfo uThreadCtor;
92 private Dictionary<UUID, ArrayList> m_ScriptErrors =
93 new Dictionary<UUID, ArrayList>();
94 private Dictionary<UUID, List<UUID>> m_ObjectItemList =
95 new Dictionary<UUID, List<UUID>>();
96 private Dictionary<UUID, XMRInstance[]> m_ObjectInstArray =
97 new Dictionary<UUID, XMRInstance[]>();
98 public Dictionary<string,FieldInfo> m_XMRInstanceApiCtxFieldInfos =
99 new Dictionary<string,FieldInfo> ();
100 private int m_StackSize;
101 private int m_HeapSize;
102
103 private XMRScriptThread[] m_ScriptThreads;
104 private int m_WakeUpOne = 0;
105 public object m_WakeUpLock = new object();
106 private Dictionary<Thread,XMRScriptThread> m_AllThreads = new Dictionary<Thread,XMRScriptThread> ();
107
108 private bool m_SuspendScriptThreadFlag = false;
109 /**
110 * @brief Something was just added to the Start or Yield queue so
111 * wake one of the XMRScriptThread instances to run it.
112 */
113
114 private Thread m_SleepThread = null;
115 private bool m_Exiting = false;
116
117 private int m_MaintenanceInterval = 10;
118 private System.Timers.Timer m_MaintenanceTimer;
119 public int numThreadScriptWorkers;
120
121 private object m_FrameUpdateLock = new object ();
122 private event ThreadStart m_FrameUpdateList = null;
123
124 // Various instance lists:
125 // m_InstancesDict = all known instances
126 // find an instance given its itemID
127 // m_StartQueue = instances that have just had event queued to them
128 // m_YieldQueue = instances that are ready to run right now
129 // m_SleepQueue = instances that have m_SleepUntil valid
130 // sorted by ascending m_SleepUntil
131
132 private Dictionary<UUID, XMRInstance> m_InstancesDict =
133 new Dictionary<UUID, XMRInstance>();
134 public Queue<ThreadStart> m_ThunkQueue = new Queue<ThreadStart> ();
135 public XMRInstQueue m_StartQueue = new XMRInstQueue();
136 public XMRInstQueue m_YieldQueue = new XMRInstQueue();
137 public XMRInstQueue m_SleepQueue = new XMRInstQueue();
138 private string m_LockedDict = "nobody";
139
140 public XMREngine()
141 {
142 }
143
144 public string Name
145 {
146 get { return "XMREngine"; }
147 }
148
149 public Type ReplaceableInterface
150 {
151 get { return null; }
152 }
153
154 public string ScriptEnginePath
155 {
156 get { return m_ScriptBasePath; }
157 }
158
159 public string ScriptClassName
160 {
161 get { return "XMREngineScript"; }
162 }
163
164 public string ScriptBaseClassName
165 {
166 get { return typeof (XMRInstance).FullName; }
167 }
168
169 public ParameterInfo[] ScriptBaseClassParameters
170 {
171 get { return typeof(XMRInstance).GetConstructor (new Type[] { typeof (WaitHandle) }).GetParameters (); }
172 }
173
174 public string[] ScriptReferencedAssemblies
175 {
176 get { return scriptReferencedAssemblies; }
177 }
178
179 public void WakeUpOne()
180 {
181 lock (m_WakeUpLock)
182 {
183 m_WakeUpOne++;
184 Monitor.Pulse(m_WakeUpLock);
185 }
186 }
187
188 public void AddThread(Thread thd, XMRScriptThread xthd)
189 {
190 lock(m_AllThreads)
191 m_AllThreads.Add(thd, xthd);
192 }
193
194 public void RemoveThread(Thread thd)
195 {
196 lock(m_AllThreads)
197 m_AllThreads.Remove(thd);
198 }
199
200 public XMRScriptThread CurrentScriptThread ()
201 {
202 XMRScriptThread st;
203 lock (m_AllThreads)
204 m_AllThreads.TryGetValue (Thread.CurrentThread, out st);
205
206 return st;
207 }
208
209 public void Initialise(IConfigSource config)
210 {
211 TraceCalls("[XMREngine]: Initialize entry");
212 m_ConfigSource = config;
213
214 ////foreach (IConfig icfg in config.Configs) {
215 //// m_log.Debug("[XMREngine]: Initialise: configs[" + icfg.Name + "]");
216 //// foreach (string key in icfg.GetKeys ()) {
217 //// m_log.Debug("[XMREngine]: Initialise: " + key + "=" + icfg.GetExpanded (key));
218 //// }
219 ////}
220
221 m_Enabled = false;
222 m_Config = config.Configs["XMREngine"];
223 if (m_Config == null)
224 {
225 m_log.Info("[XMREngine]: no config, assuming disabled");
226 return;
227 }
228
229 m_Enabled = m_Config.GetBoolean("Enabled", false);
230 m_log.InfoFormat("[XMREngine]: config enabled={0}", m_Enabled);
231 if (!m_Enabled)
232 return;
233
234 Type uThreadType = null;
235 uThreadType = typeof (ScriptUThread_Nul);
236 uThreadCtor = uThreadType.GetConstructor (new Type[] { typeof (XMRInstance) });
237
238 m_UseSourceHashCode = m_Config.GetBoolean("UseSourceHashCode", false);
239 numThreadScriptWorkers = m_Config.GetInt("NumThreadScriptWorkers", 3);
240 m_ScriptThreads = new XMRScriptThread[numThreadScriptWorkers];
241
242 m_TraceCalls = m_Config.GetBoolean("TraceCalls", false);
243 m_Verbose = m_Config.GetBoolean("Verbose", false);
244 m_ScriptDebug = m_Config.GetBoolean("ScriptDebug", false);
245
246 // Verify that our ScriptEventCode's match OpenSim's scriptEvent's.
247 bool err = false;
248 for (int i = 0; i < 32; i ++)
249 {
250 string mycode = "undefined";
251 string oscode = "undefined";
252 try
253 {
254 mycode = ((ScriptEventCode)i).ToString();
255 Convert.ToInt32(mycode);
256 mycode = "undefined";
257 }
258 catch { }
259 try
260 {
261 oscode = ((OpenSim.Region.Framework.Scenes.scriptEvents)(1 << i)).ToString();
262 Convert.ToInt32(oscode);
263 oscode = "undefined";
264 }
265 catch { }
266 if (mycode != oscode)
267 {
268 m_log.ErrorFormat("[XMREngine]: {0} mycode={1}, oscode={2}", i, mycode, oscode);
269 err = true;
270 }
271 }
272 if (err)
273 {
274 m_Enabled = false;
275 return;
276 }
277
278 for (int i = 0; i < numThreadScriptWorkers; i ++)
279 {
280 m_ScriptThreads[i] = new XMRScriptThread(this, i);;
281 }
282
283
284 m_SleepThread = StartMyThread(RunSleepThread, "xmrengine sleep", ThreadPriority.Normal);
285
286 m_StackSize = m_Config.GetInt("ScriptStackSize", 2048) << 10;
287 m_HeapSize = m_Config.GetInt("ScriptHeapSize", 1024) << 10;
288
289 m_log.InfoFormat("[XMREngine]: Enabled, {0}.{1} Meg (0x{2}) stacks",
290 (m_StackSize >> 20).ToString (),
291 (((m_StackSize % 0x100000) * 1000)
292 >> 20).ToString ("D3"),
293 m_StackSize.ToString ("X"));
294
295 m_log.InfoFormat("[XMREngine]: ... {0}.{1} Meg (0x{2}) heaps",
296 (m_HeapSize >> 20).ToString (),
297 (((m_HeapSize % 0x100000) * 1000)
298 >> 20).ToString ("D3"),
299 m_HeapSize.ToString ("X"));
300
301 m_MaintenanceInterval = m_Config.GetInt("MaintenanceInterval", 10);
302
303 if (m_MaintenanceInterval > 0)
304 {
305 m_MaintenanceTimer = new System.Timers.Timer(m_MaintenanceInterval * 60000);
306 m_MaintenanceTimer.Elapsed += DoMaintenance;
307 m_MaintenanceTimer.Start();
308 }
309
310 MainConsole.Instance.Commands.AddCommand("xmr", false,
311 "xmr",
312 "xmr [...|help|...] ...",
313 "Run xmr script engine commands",
314 RunTest);
315
316 TraceCalls("[XMREngine]: Initialize successful");
317 }
318
319 public void AddRegion(Scene scene)
320 {
321 if (!m_Enabled)
322 return;
323
324 TraceCalls("[XMREngine]: XMREngine.AddRegion({0})", scene.RegionInfo.RegionName);
325
326 m_Scene = scene;
327
328 m_Scene.RegisterModuleInterface<IScriptModule>(this);
329
330 m_ScriptBasePath = m_Config.GetString ("ScriptBasePath", "ScriptData");
331 m_ScriptBasePath = Path.Combine (m_ScriptBasePath, scene.RegionInfo.RegionID.ToString());
332
333 Directory.CreateDirectory(m_ScriptBasePath);
334
335 m_Scene.EventManager.OnRezScript += OnRezScript;
336
337 m_Scene.StackModuleInterface<IScriptModule>(this);
338 }
339
340 private void OneTimeLateInitialization ()
341 {
342 // Build list of defined APIs and their 'this' types and define a field in XMRInstanceSuperType.
343 ApiManager am = new ApiManager ();
344 Dictionary<string,Type> apiCtxTypes = new Dictionary<string,Type> ();
345 foreach (string api in am.GetApis ())
346 {
347 m_log.Debug ("[XMREngine]: adding api " + api);
348 IScriptApi scriptApi = am.CreateApi (api);
349 Type apiCtxType = scriptApi.GetType ();
350 if (api == "LSL") apiCtxType = typeof (XMRLSL_Api);
351 apiCtxTypes[api] = apiCtxType;
352 }
353
354 if (ScriptCodeGen.xmrInstSuperType == null) // Only create type once!
355 {
356 // Start creating type XMRInstanceSuperType that contains a field
357 // m_ApiManager_<APINAME> that points to the per-instance context
358 // struct for that API, ie, the 'this' value passed to all methods
359 // in that API. It is in essence:
360
361 // public class XMRInstanceSuperType : XMRInstance {
362 // public XMRLSL_Api m_ApiManager_LSL; // 'this' value for all ll...() functions
363 // public MOD_Api m_ApiManager_MOD; // 'this' value for all mod...() functions
364 // public OSSL_Api m_ApiManager_OSSL; // 'this' value for all os...() functions
365 // ....
366 // }
367
368 AssemblyName assemblyName = new AssemblyName ();
369 assemblyName.Name = "XMRInstanceSuperAssembly";
370 AssemblyBuilder assemblyBuilder = Thread.GetDomain().DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
371#if DEBUG
372 Type daType = typeof(DebuggableAttribute);
373 ConstructorInfo daCtor = daType.GetConstructor(new Type[] { typeof(DebuggableAttribute.DebuggingModes) });
374
375 CustomAttributeBuilder daBuilder = new CustomAttributeBuilder(daCtor, new object[] {
376 DebuggableAttribute.DebuggingModes.DisableOptimizations |
377 DebuggableAttribute.DebuggingModes.EnableEditAndContinue |
378 DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints |
379 DebuggableAttribute.DebuggingModes.Default });
380
381 assemblyBuilder.SetCustomAttribute(daBuilder);
382#endif
383 ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("XMRInstanceSuperModule");
384 TypeBuilder typeBuilder = moduleBuilder.DefineType("XMRInstanceSuperType", TypeAttributes.Public | TypeAttributes.Class);
385 typeBuilder.SetParent(typeof (XMRInstance));
386
387 foreach (string apiname in apiCtxTypes.Keys)
388 {
389 string fieldName = "m_ApiManager_" + apiname;
390 typeBuilder.DefineField (fieldName, apiCtxTypes[apiname], FieldAttributes.Public);
391 }
392
393 // Finalize definition of XMRInstanceSuperType.
394 // Give the compiler a short name to reference it by,
395 // otherwise it will try to use the AssemblyQualifiedName
396 // and fail miserably.
397 ScriptCodeGen.xmrInstSuperType = typeBuilder.CreateType ();
398 ScriptObjWriter.DefineInternalType ("xmrsuper", ScriptCodeGen.xmrInstSuperType);
399 }
400
401 // Tell the compiler about all the constants and methods for each API.
402 // We also tell the compiler how to get the per-instance context for each API
403 // by reading the corresponding m_ApiManager_<APINAME> field of XMRInstanceSuperType.
404
405 foreach (KeyValuePair<string,Type> kvp in apiCtxTypes)
406 {
407 // get API name and the corresponding per-instance context type
408 string api = kvp.Key;
409 Type apiCtxType = kvp.Value;
410
411 // give script compiler an abbreviated name for the API context type
412 ScriptObjWriter.DefineInternalType ("apimanager_" + api, apiCtxType);
413
414 // this field tells the compiled code where the per-instance API context object is
415 // eg, for the OSSL API, it is in ((XMRInstanceSuperType)inst).m_ApiManager_OSSL
416 string fieldName = "m_ApiManager_" + api;
417 FieldInfo fieldInfo = ScriptCodeGen.xmrInstSuperType.GetField (fieldName);
418 m_XMRInstanceApiCtxFieldInfos[api] = fieldInfo;
419
420 // now tell the compiler about the constants and methods for the API
421 ScriptConst.AddInterfaceConstants (null, apiCtxType.GetFields ());
422 TokenDeclInline.AddInterfaceMethods (null, apiCtxType.GetMethods (), fieldInfo);
423 }
424
425 // Add sim-specific APIs to the compiler.
426
427 IScriptModuleComms comms = m_Scene.RequestModuleInterface<IScriptModuleComms> ();
428 if (comms != null)
429 {
430 // Add methods to list of built-in functions.
431 Delegate[] methods = comms.GetScriptInvocationList ();
432 foreach (Delegate m in methods)
433 {
434 MethodInfo mi = m.Method;
435 try
436 {
437 CommsCallCodeGen cccg = new CommsCallCodeGen (mi, comms, m_XMRInstanceApiCtxFieldInfos["MOD"]);
438 Verbose ("[XMREngine]: added comms function " + cccg.fullName);
439 }
440 catch (Exception e)
441 {
442 m_log.Error ("[XMREngine]: failed to add comms function " + mi.Name);
443 m_log.Error ("[XMREngine]: - " + e.ToString ());
444 }
445 }
446
447 // Add constants to list of built-in constants.
448
449 Dictionary<string,object> consts = comms.GetConstants ();
450 foreach (KeyValuePair<string,object> kvp in consts)
451 {
452 try
453 {
454 ScriptConst sc = ScriptConst.AddConstant (kvp.Key, kvp.Value);
455 Verbose ("[XMREngine]: added comms constant " + sc.name);
456 }
457 catch (Exception e)
458 {
459 m_log.Error ("[XMREngine]: failed to add comms constant " + kvp.Key);
460 m_log.Error ("[XMREngine]: - " + e.Message);
461 }
462 }
463 }
464 else
465 {
466 Verbose ("[XMREngine]: comms not enabled");
467 }
468 }
469
470 /**
471 * @brief Generate code for the calls to the comms functions.
472 * It is a tRUlY EvIL interface.
473 * To call the function we must call an XMRInstanceSuperType.m_ApiManager_MOD.modInvoker?()
474 * method passing it the name of the function as a string and the script
475 * argument list wrapped up in an object[] array. The modInvoker?() methods
476 * do some sick type conversions (with corresponding mallocs) so we can't
477 * call the methods directly.
478 */
479 private class CommsCallCodeGen : TokenDeclInline
480 {
481 private static Type[] modInvokerArgTypes = new Type[] { typeof (string), typeof (object[]) };
482 public static FieldInfo xmrInstModApiCtxField;
483
484 private MethodInfo modInvokerMeth;
485 private string methName;
486
487 /**
488 * @brief Constructor
489 * @param mi = method to make available to scripts
490 * mi.Name = name that is used by scripts
491 * mi.GetParameters() = parameter list as defined by module
492 * includes the 'UUID host','UUID script' parameters that script does not see
493 * allowed types for script-visible parameters are as follows:
494 * Single -> float
495 * Int32 -> integer
496 * OpenMetaverse.UUID -> key
497 * Object[] -> list
498 * OpenMetaverse.Quaternion -> rotation
499 * String -> string
500 * OpenMetaverse.Vector3 -> vector
501 * mi.ReturnType = return type as defined by module
502 * types are same as allowed for parameters
503 * @param comms = comms module the method came from
504 * @param apictxfi = what field in XMRInstanceSuperType the 'this' value is for this method
505 */
506 public CommsCallCodeGen (MethodInfo mi, IScriptModuleComms comms, FieldInfo apictxfi)
507 : base (null, false, NameArgSig (mi), RetType (mi))
508 {
509 methName = mi.Name;
510 string modInvokerName = comms.LookupModInvocation (methName);
511 if (modInvokerName == null)
512 throw new Exception("cannot find comms method " + methName);
513 modInvokerMeth = typeof(MOD_Api).GetMethod(modInvokerName, modInvokerArgTypes);
514 xmrInstModApiCtxField = apictxfi;
515 }
516
517 // script-visible name(argtype,...) signature string
518 private static string NameArgSig (MethodInfo mi)
519 {
520 StringBuilder sb = new StringBuilder ();
521 sb.Append (mi.Name);
522 sb.Append ('(');
523 ParameterInfo[] mps = mi.GetParameters ();
524 for (int i = 2; i < mps.Length; i ++)
525 {
526 ParameterInfo pi = mps[i];
527 if (i > 2) sb.Append (',');
528 sb.Append (ParamType (pi.ParameterType));
529 }
530 sb.Append (')');
531 return sb.ToString ();
532 }
533
534 // script-visible return type
535 // note that although we support void, the comms stuff does not
536 private static TokenType RetType (MethodInfo mi)
537 {
538 Type rt = mi.ReturnType;
539 if (rt == typeof (float)) return new TokenTypeFloat (null);
540 if (rt == typeof (int)) return new TokenTypeInt (null);
541 if (rt == typeof (object[])) return new TokenTypeList (null);
542 if (rt == typeof (OpenMetaverse.UUID)) return new TokenTypeKey (null);
543 if (rt == typeof (OpenMetaverse.Quaternion)) return new TokenTypeRot (null);
544 if (rt == typeof (string)) return new TokenTypeStr (null);
545 if (rt == typeof (OpenMetaverse.Vector3)) return new TokenTypeVec (null);
546 if (rt == null || rt == typeof (void)) return new TokenTypeVoid (null);
547 throw new Exception ("unsupported return type " + rt.Name);
548 }
549
550 // script-visible parameter type
551 private static string ParamType (Type t)
552 {
553 if (t == typeof (float)) return "float";
554 if (t == typeof (int)) return "integer";
555 if (t == typeof (OpenMetaverse.UUID)) return "key";
556 if (t == typeof (object[])) return "list";
557 if (t == typeof (OpenMetaverse.Quaternion)) return "rotation";
558 if (t == typeof (string)) return "string";
559 if (t == typeof (OpenMetaverse.Vector3)) return "vector";
560 throw new Exception ("unsupported parameter type " + t.Name);
561 }
562
563 /**
564 * @brief Called by the compiler to generate a call to the comms function.
565 * @param scg = which script is being compiled
566 * @param errorAt = where in the source code the call is being made (for error messages)
567 * @param result = a temp location to put the return value in if any
568 * @param args = array of script-visible arguments being passed to the function
569 */
570 public override void CodeGen (ScriptCodeGen scg, Token errorAt, CompValuTemp result, CompValu[] args)
571 {
572 // Set up 'this' pointer for modInvoker?() = value from ApiManager.CreateApi("MOD").
573 scg.PushXMRInst ();
574 scg.ilGen.Emit (errorAt, OpCodes.Castclass, xmrInstModApiCtxField.DeclaringType);
575 scg.ilGen.Emit (errorAt, OpCodes.Ldfld, xmrInstModApiCtxField);
576
577 // Set up 'fname' argument to modInvoker?() = name of the function to be called.
578 scg.ilGen.Emit (errorAt, OpCodes.Ldstr, methName);
579
580 // Set up 'parms' argument to modInvoker?() = object[] of the script-visible parameters,
581 // in their LSL-wrapped form. Of course, the modInvoker?() method will malloc yet another
582 // object[] and type-convert these parameters one-by-one with another round of unwrapping
583 // and wrapping.
584 // Types allowed in this object[]:
585 // LSL_Float, LSL_Integer, LSL_Key, LSL_List, LSL_Rotation, LSL_String, LSL_Vector
586
587 int nargs = args.Length;
588 scg.ilGen.Emit (errorAt, OpCodes.Ldc_I4, nargs);
589 scg.ilGen.Emit (errorAt, OpCodes.Newarr, typeof (object));
590
591 for (int i = 0; i < nargs; i ++)
592 {
593 scg.ilGen.Emit (errorAt, OpCodes.Dup);
594 scg.ilGen.Emit (errorAt, OpCodes.Ldc_I4, i);
595
596 // get location and type of argument
597 CompValu arg = args[i];
598 TokenType argtype = arg.type;
599
600 // if already in a form acceptable to modInvoker?(),
601 // just push it to the stack and convert to object
602 // by boxing it if necessary
603
604 // but if something like a double, int, string, etc
605 // push to stack converting to the LSL-wrapped type
606 // then convert to object by boxing if necessary
607
608 Type boxit = null;
609 if (argtype is TokenTypeLSLFloat)
610 {
611 args[i].PushVal (scg, errorAt);
612 boxit = typeof (LSL_Float);
613 }
614 else if (argtype is TokenTypeLSLInt)
615 {
616 args[i].PushVal (scg, errorAt);
617 boxit = typeof (LSL_Integer);
618 }
619 else if (argtype is TokenTypeLSLKey)
620 {
621 args[i].PushVal (scg, errorAt);
622 boxit = typeof (LSL_Key);
623 }
624 else if (argtype is TokenTypeList)
625 {
626 args[i].PushVal (scg, errorAt);
627 boxit = typeof (LSL_List);
628 }
629 else if (argtype is TokenTypeRot)
630 {
631 args[i].PushVal (scg, errorAt);
632 boxit = typeof (LSL_Rotation);
633 }
634 else if (argtype is TokenTypeLSLString)
635 {
636 args[i].PushVal (scg, errorAt);
637 boxit = typeof (LSL_String);
638 }
639 else if (argtype is TokenTypeVec)
640 {
641 args[i].PushVal (scg, errorAt);
642 boxit = typeof (LSL_Vector);
643 }
644 else if (argtype is TokenTypeFloat)
645 {
646 args[i].PushVal (scg, errorAt, new TokenTypeLSLFloat (argtype));
647 boxit = typeof (LSL_Float);
648 }
649 else if (argtype is TokenTypeInt)
650 {
651 args[i].PushVal (scg, errorAt, new TokenTypeLSLInt (argtype));
652 boxit = typeof (LSL_Integer);
653 }
654 else if (argtype is TokenTypeKey)
655 {
656 args[i].PushVal (scg, errorAt, new TokenTypeLSLKey (argtype));
657 boxit = typeof (LSL_Key);
658 }
659 else if (argtype is TokenTypeStr)
660 {
661 args[i].PushVal (scg, errorAt, new TokenTypeLSLString (argtype));
662 boxit = typeof (LSL_String);
663 }
664 else
665 throw new Exception ("unsupported arg type " + argtype.GetType ().Name);
666
667 if (boxit.IsValueType)
668 scg.ilGen.Emit (errorAt, OpCodes.Box, boxit);
669
670 // pop the object into the object[]
671 scg.ilGen.Emit (errorAt, OpCodes.Stelem, typeof (object));
672 }
673
674 // Call the modInvoker?() method.
675 // It leaves an LSL-wrapped type on the stack.
676 if (modInvokerMeth.IsVirtual)
677 scg.ilGen.Emit (errorAt, OpCodes.Callvirt, modInvokerMeth);
678 else
679 scg.ilGen.Emit (errorAt, OpCodes.Call, modInvokerMeth);
680
681 // The 3rd arg to Pop() is the type on the stack,
682 // ie, what modInvoker?() actually returns.
683 // The Pop() method will wrap/unwrap as needed.
684 Type retSysType = modInvokerMeth.ReturnType;
685 if (retSysType == null)
686 retSysType = typeof (void);
687 TokenType retTokType = TokenType.FromSysType (errorAt, retSysType);
688 result.Pop (scg, errorAt, retTokType);
689 }
690 }
691
692 /**
693 * @brief Called late in shutdown procedure,
694 * after the 'Shutting down..." message.
695 */
696 public void RemoveRegion(Scene scene)
697 {
698 if (!m_Enabled)
699 return;
700
701 TraceCalls("[XMREngine]: XMREngine.RemoveRegion({0})", scene.RegionInfo.RegionName);
702
703 // Write script states out to .state files so it will be
704 // available when the region is restarted.
705 DoMaintenance(null, null);
706
707 // Stop executing script threads and wait for final
708 // one to finish (ie, script gets to CheckRun() call).
709 m_Exiting = true;
710
711 m_Scene.EventManager.OnFrame -= OnFrame;
712 m_Scene.EventManager.OnRezScript -= OnRezScript;
713 m_Scene.EventManager.OnRemoveScript -= OnRemoveScript;
714 m_Scene.EventManager.OnScriptReset -= OnScriptReset;
715 m_Scene.EventManager.OnStartScript -= OnStartScript;
716 m_Scene.EventManager.OnStopScript -= OnStopScript;
717 m_Scene.EventManager.OnGetScriptRunning -= OnGetScriptRunning;
718 m_Scene.EventManager.OnShutdown -= OnShutdown;
719
720 for (int i = 0; i < numThreadScriptWorkers; i ++)
721 {
722 XMRScriptThread scriptThread = m_ScriptThreads[i];
723 if (scriptThread != null)
724 {
725 scriptThread.WakeUpScriptThread();
726 Monitor.PulseAll (m_WakeUpLock);
727 scriptThread.Terminate();
728 m_ScriptThreads[i] = null;
729 }
730 }
731
732 if (m_SleepThread != null)
733 {
734 lock (m_SleepQueue)
735 {
736 Monitor.PulseAll (m_SleepQueue);
737 }
738 if(!m_SleepThread.Join(250))
739 m_SleepThread.Abort();
740 m_SleepThread = null;
741 }
742
743 m_Enabled = false;
744 m_Scene = null;
745 }
746
747 public void RegionLoaded(Scene scene)
748 {
749 if (!m_Enabled)
750 return;
751
752 TraceCalls("[XMREngine]: XMREngine.RegionLoaded({0})", scene.RegionInfo.RegionName);
753
754 m_Scene.EventManager.OnFrame += OnFrame;
755 m_Scene.EventManager.OnRemoveScript += OnRemoveScript;
756 m_Scene.EventManager.OnScriptReset += OnScriptReset;
757 m_Scene.EventManager.OnStartScript += OnStartScript;
758 m_Scene.EventManager.OnStopScript += OnStopScript;
759 m_Scene.EventManager.OnGetScriptRunning += OnGetScriptRunning;
760 m_Scene.EventManager.OnShutdown += OnShutdown;
761
762 InitEvents();
763 }
764
765 public void StartProcessing()
766 {
767 m_log.Debug ("[XMREngine]: StartProcessing entry");
768 m_Scene.EventManager.TriggerEmptyScriptCompileQueue (0, "");
769 m_StartProcessing = true;
770 for (int i = 0; i < numThreadScriptWorkers; i ++) {
771 WakeUpOne();
772 }
773 m_log.Debug ("[XMREngine]: StartProcessing return");
774 }
775
776 public void Close()
777 {
778 TraceCalls("[XMREngine]: XMREngine.Close()");
779 }
780
781 private void RunTest (string module, string[] args)
782 {
783 if (args.Length < 2)
784 {
785 m_log.Info ("[XMREngine]: missing command, try 'xmr help'");
786 return;
787 }
788
789 switch (args[1])
790 {
791 case "cvv":
792 switch (args.Length)
793 {
794 case 2:
795 m_log.InfoFormat ("[XMREngine]: compiled version value = {0}",
796 ScriptCodeGen.COMPILED_VERSION_VALUE);
797 break;
798
799 case 3:
800 try
801 {
802 ScriptCodeGen.COMPILED_VERSION_VALUE = Convert.ToInt32 (args[2]);
803 }
804 catch
805 {
806 m_log.Error ("[XMREngine]: bad/missing version number");
807 }
808 break;
809
810 default:
811 m_log.Error ("[XMREngine]: xmr cvv [<new_compiled_version_value>]");
812 break;
813 }
814 break;
815
816 case "echo":
817 for (int i = 0; i < args.Length; i ++)
818 m_log.Info ("[XMREngine]: echo[" + i + "]=<" + args[i] + ">");
819
820 break;
821
822 case "gc":
823 GC.Collect();
824 break;
825
826 case "help":
827 case "?":
828 m_log.Info ("[XMREngine]: xmr cvv [<newvalue>] - show/set compiled version value");
829 m_log.Info ("[XMREngine]: xmr gc");
830 m_log.Info ("[XMREngine]: xmr ls [-help ...]");
831 m_log.Info ("[XMREngine]: xmr mvv [<newvalue>] - show/set migration version value");
832 m_log.Info ("[XMREngine]: xmr pev [-help ...] - post event");
833 m_log.Info ("[XMREngine]: xmr reset [-help ...]");
834 m_log.Info ("[XMREngine]: xmr resume - resume script processing");
835 m_log.Info ("[XMREngine]: xmr suspend - suspend script processing");
836 m_log.Info ("[XMREngine]: xmr tracecalls [yes | no]");
837 m_log.Info ("[XMREngine]: xmr verbose [yes | no]");
838 break;
839
840 case "ls":
841 XmrTestLs (args, 2);
842 break;
843
844 case "mvv":
845 switch (args.Length)
846 {
847 case 2:
848 m_log.InfoFormat ("[XMREngine]: migration version value = {0}",
849 XMRInstance.migrationVersion);
850 break;
851
852 case 3:
853 try
854 {
855 int mvv = Convert.ToInt32 (args[2]);
856 if ((mvv < 0) || (mvv > 255)) throw new Exception ("out of range");
857 XMRInstance.migrationVersion = (byte) mvv;
858 }
859 catch (Exception e)
860 {
861 m_log.Error ("[XMREngine]: bad/missing version number (" + e.Message + ")");
862 }
863 break;
864
865 default:
866 m_log.Error ("[XMREngine]: xmr mvv [<new_migration_version_value>]");
867 break;
868 }
869 break;
870
871 case "pev":
872 XmrTestPev (args, 2);
873 break;
874
875 case "reset":
876 XmrTestReset (args, 2);
877 break;
878
879 case "resume":
880 m_log.Info ("[XMREngine]: resuming scripts");
881 m_SuspendScriptThreadFlag = false;
882 for (int i = 0; i < numThreadScriptWorkers; i ++)
883 m_ScriptThreads[i].WakeUpScriptThread();
884 Monitor.PulseAll(m_WakeUpLock);
885 break;
886
887 case "suspend":
888 m_log.Info ("[XMREngine]: suspending scripts");
889 m_SuspendScriptThreadFlag = true;
890 for (int i = 0; i < numThreadScriptWorkers; i ++)
891 m_ScriptThreads[i].WakeUpScriptThread();
892 Monitor.PulseAll(m_WakeUpLock);
893 break;
894
895 case "tracecalls":
896 if (args.Length > 2)
897 m_TraceCalls = (args[2][0] & 1) != 0;
898 m_log.Info ("[XMREngine]: tracecalls " + (m_TraceCalls ? "yes" : "no"));
899 break;
900
901 case "verbose":
902 if (args.Length > 2)
903 m_Verbose = (args[2][0] & 1) != 0;
904 m_log.Info ("[XMREngine]: verbose " + (m_Verbose ? "yes" : "no"));
905 break;
906
907 default:
908 m_log.Error ("[XMREngine]: unknown command " + args[1] + ", try 'xmr help'");
909 break;
910 }
911 }
912
913 // Not required when not using IScriptInstance
914 //
915 public IScriptWorkItem QueueEventHandler(object parms)
916 {
917 return null;
918 }
919
920 public Scene World
921 {
922 get { return m_Scene; }
923 }
924
925 public IScriptModule ScriptModule
926 {
927 get { return this; }
928 }
929
930 public void SaveAllState()
931 {
932 m_log.Error("[XMREngine]: XMREngine.SaveAllState() called!!");
933 }
934
935#pragma warning disable 0067
936 public event ScriptRemoved OnScriptRemoved;
937 public event ObjectRemoved OnObjectRemoved;
938#pragma warning restore 0067
939
940 // Events targeted at a specific script
941 // ... like listen() for an llListen() call
942 //
943 public bool PostScriptEvent(UUID itemID, EventParams parms)
944 {
945 XMRInstance instance = GetInstance (itemID);
946 if (instance == null) return false;
947
948 TraceCalls("[XMREngine]: XMREngine.PostScriptEvent({0},{1})", itemID.ToString(), parms.EventName);
949
950 instance.PostEvent(parms);
951 return true;
952 }
953
954 // Events targeted at all scripts in the given prim.
955 // localID = which prim
956 // parms = event to post
957 //
958 public bool PostObjectEvent (uint localID, EventParams parms)
959 {
960 SceneObjectPart part = m_Scene.GetSceneObjectPart(localID);
961
962 if (part == null)
963 return false;
964
965 TraceCalls("[XMREngine]: XMREngine.PostObjectEvent({0},{1})", localID.ToString(), parms.EventName);
966
967 // In SecondLife, attach events go to all scripts of all prims
968 // in a linked object. So here we duplicate that functionality,
969 // as all we ever get is a single attach event for the whole
970 // object.
971 if (parms.EventName == "attach")
972 {
973 bool posted = false;
974 foreach (SceneObjectPart primpart in part.ParentGroup.Parts)
975 {
976 posted |= PostPrimEvent (primpart, parms);
977 }
978 return posted;
979 }
980
981 // Other events go to just the scripts in that prim.
982 return PostPrimEvent (part, parms);
983 }
984
985 private bool PostPrimEvent (SceneObjectPart part, EventParams parms)
986 {
987 UUID partUUID = part.UUID;
988
989 // Get list of script instances running in the object.
990 XMRInstance[] objInstArray;
991 lock (m_InstancesDict)
992 {
993 if (!m_ObjectInstArray.TryGetValue (partUUID, out objInstArray))
994 return false;
995
996 if (objInstArray == null)
997 {
998 objInstArray = RebuildObjectInstArray (partUUID);
999 m_ObjectInstArray[partUUID] = objInstArray;
1000 }
1001 }
1002
1003 // Post event to all script instances in the object.
1004 if (objInstArray.Length <= 0) return false;
1005 foreach (XMRInstance inst in objInstArray)
1006 inst.PostEvent (parms);
1007
1008 return true;
1009 }
1010
1011 public DetectParams GetDetectParams(UUID itemID, int number)
1012 {
1013 XMRInstance instance = GetInstance (itemID);
1014 if (instance == null)
1015 return null;
1016 return instance.GetDetectParams(number);
1017 }
1018
1019 public void SetMinEventDelay(UUID itemID, double delay)
1020 {
1021 }
1022
1023 public int GetStartParameter(UUID itemID)
1024 {
1025 XMRInstance instance = GetInstance (itemID);
1026 if (instance == null)
1027 return 0;
1028 return instance.StartParam;
1029 }
1030
1031 // This is the "set running" method
1032 //
1033 public void SetScriptState(UUID itemID, bool state, bool self)
1034 {
1035 SetScriptState (itemID, state);
1036 }
1037 public void SetScriptState(UUID itemID, bool state)
1038 {
1039 XMRInstance instance = GetInstance (itemID);
1040 if (instance != null)
1041 instance.Running = state;
1042 }
1043
1044 // Control display of the "running" checkbox
1045 //
1046 public bool GetScriptState(UUID itemID)
1047 {
1048 XMRInstance instance = GetInstance (itemID);
1049 if (instance == null)
1050 return false;
1051 return instance.Running;
1052 }
1053
1054 public void SetState(UUID itemID, string newState)
1055 {
1056 TraceCalls("[XMREngine]: XMREngine.SetState({0},{1})", itemID.ToString(), newState);
1057 }
1058
1059 public void ApiResetScript(UUID itemID)
1060 {
1061 XMRInstance instance = GetInstance (itemID);
1062 if (instance != null)
1063 instance.ApiReset();
1064 }
1065
1066 public void ResetScript(UUID itemID)
1067 {
1068 XMRInstance instance = GetInstance (itemID);
1069 if (instance != null)
1070 {
1071 IUrlModule urlModule = m_Scene.RequestModuleInterface<IUrlModule>();
1072 if (urlModule != null)
1073 urlModule.ScriptRemoved(itemID);
1074
1075 instance.Reset();
1076 }
1077 }
1078
1079 public IConfig Config
1080 {
1081 get { return m_Config; }
1082 }
1083
1084 public IConfigSource ConfigSource
1085 {
1086 get { return m_ConfigSource; }
1087 }
1088
1089 public string ScriptEngineName
1090 {
1091 get { return "XMREngine"; }
1092 }
1093
1094 public IScriptApi GetApi(UUID itemID, string name)
1095 {
1096 FieldInfo fi;
1097 if (!m_XMRInstanceApiCtxFieldInfos.TryGetValue (name, out fi))
1098 return null;
1099 XMRInstance inst = GetInstance (itemID);
1100 if (inst == null) return null;
1101 return (IScriptApi)fi.GetValue (inst);
1102 }
1103
1104 /**
1105 * @brief Get script's current state as an XML string
1106 * - called by "Take", "Take Copy" and when object deleted (ie, moved to Trash)
1107 * This includes the .state file
1108 */
1109 public string GetXMLState(UUID itemID)
1110 {
1111 XMRInstance instance = GetInstance (itemID);
1112 if (instance == null)
1113 return String.Empty;
1114
1115 TraceCalls("[XMREngine]: XMREngine.GetXMLState({0})", itemID.ToString());
1116
1117 if (!instance.m_HasRun)
1118 return String.Empty;
1119
1120 XmlDocument doc = new XmlDocument();
1121
1122 /*
1123 * Set up <State Engine="XMREngine" UUID="itemID" Asset="assetID"> tag.
1124 */
1125 XmlElement stateN = doc.CreateElement("", "State", "");
1126 doc.AppendChild(stateN);
1127
1128 XmlAttribute engineA = doc.CreateAttribute("", "Engine", "");
1129 engineA.Value = ScriptEngineName;
1130 stateN.Attributes.Append(engineA);
1131
1132 XmlAttribute uuidA = doc.CreateAttribute("", "UUID", "");
1133 uuidA.Value = itemID.ToString();
1134 stateN.Attributes.Append(uuidA);
1135
1136 XmlAttribute assetA = doc.CreateAttribute("", "Asset", "");
1137 string assetID = instance.AssetID.ToString();
1138 assetA.Value = assetID;
1139 stateN.Attributes.Append(assetA);
1140
1141 // Get <ScriptState>...</ScriptState> item that hold's script's state.
1142 // This suspends the script if necessary then takes a snapshot.
1143 XmlElement scriptStateN = instance.GetExecutionState(doc);
1144 stateN.AppendChild(scriptStateN);
1145
1146 return doc.OuterXml;
1147 }
1148
1149 // Set script's current state from an XML string
1150 // - called just before a script is instantiated
1151 // So we write the .state file so the .state file will be seen when
1152 // the script is instantiated.
1153 public bool SetXMLState(UUID itemID, string xml)
1154 {
1155 XmlDocument doc = new XmlDocument();
1156
1157 try
1158 {
1159 doc.LoadXml(xml);
1160 }
1161 catch
1162 {
1163 return false;
1164 }
1165 TraceCalls("[XMREngine]: XMREngine.SetXMLState({0})", itemID.ToString());
1166
1167 // Make sure <State Engine="XMREngine"> so we know it is in our
1168 // format.
1169 XmlElement stateN = (XmlElement)doc.SelectSingleNode("State");
1170 if (stateN == null)
1171 return false;
1172
1173 if (stateN.GetAttribute("Engine") != ScriptEngineName)
1174 return false;
1175
1176 // <ScriptState>...</ScriptState> contains contents of .state file.
1177 XmlElement scriptStateN = (XmlElement)stateN.SelectSingleNode("ScriptState");
1178 if (scriptStateN == null)
1179 return false;
1180
1181 string sen = stateN.GetAttribute("Engine");
1182 if ((sen == null) || (sen != ScriptEngineName))
1183 return false;
1184
1185 XmlAttribute assetA = doc.CreateAttribute("", "Asset", "");
1186 assetA.Value = stateN.GetAttribute("Asset");
1187 scriptStateN.Attributes.Append(assetA);
1188
1189 // Write out the .state file with the <ScriptState ...>...</ScriptState> XML text
1190 string statePath = XMRInstance.GetStateFileName(m_ScriptBasePath, itemID);
1191 FileStream ss = File.Create(statePath);
1192 StreamWriter sw = new StreamWriter(ss);
1193 sw.Write(scriptStateN.OuterXml);
1194 sw.Close();
1195 ss.Close();
1196
1197 return true;
1198 }
1199
1200 public bool PostScriptEvent(UUID itemID, string name, Object[] p)
1201 {
1202 if (!m_Enabled)
1203 return false;
1204
1205 TraceCalls("[XMREngine]: XMREngine.PostScriptEvent({0},{1})", itemID.ToString(), name);
1206
1207 return PostScriptEvent(itemID, new EventParams(name, p, zeroDetectParams));
1208 }
1209
1210 public bool PostObjectEvent(UUID itemID, string name, Object[] p)
1211 {
1212 if (!m_Enabled)
1213 return false;
1214
1215 TraceCalls("[XMREngine]: XMREngine.PostObjectEvent({0},{1})", itemID.ToString(), name);
1216
1217 SceneObjectPart part = m_Scene.GetSceneObjectPart(itemID);
1218 if (part == null)
1219 return false;
1220
1221 return PostObjectEvent(part.LocalId, new EventParams(name, p, zeroDetectParams));
1222 }
1223
1224 // about the 3523rd entrypoint for a script to put itself to sleep
1225 public void SleepScript(UUID itemID, int delay)
1226 {
1227 XMRInstance instance = GetInstance (itemID);
1228 if (instance != null)
1229 instance.Sleep (delay);
1230 }
1231
1232 // Get a script instance loaded, compiling it if necessary
1233 //
1234 // localID = the object as a whole, may contain many scripts
1235 // itemID = this instance of the script in this object
1236 // script = script source code
1237 // startParam = value passed to 'on_rez' event handler
1238 // postOnRez = true to post an 'on_rez' event to script on load
1239 // defEngine = default script engine
1240 // stateSource = post this event to script on load
1241
1242 public void OnRezScript(uint localID, UUID itemID, string script,
1243 int startParam, bool postOnRez, string defEngine, int stateSource)
1244 {
1245 SceneObjectPart part = m_Scene.GetSceneObjectPart(localID);
1246 TaskInventoryItem item = part.Inventory.GetInventoryItem(itemID);
1247
1248 if (!m_LateInit)
1249 {
1250 m_LateInit = true;
1251 OneTimeLateInitialization ();
1252 }
1253
1254 TraceCalls("[XMREngine]: OnRezScript(...,{0},...)", itemID.ToString());
1255
1256 // Assume script uses the default engine, whatever that is.
1257 string engineName = defEngine;
1258
1259 // Very first line might contain "//" scriptengine ":".
1260 string firstline = "";
1261 if (script.StartsWith("//")) {
1262 int lineEnd = script.IndexOf('\n');
1263 if (lineEnd > 1) firstline = script.Substring(0, lineEnd).Trim();
1264 int colon = firstline.IndexOf(':');
1265 if (colon >= 2) {
1266 engineName = firstline.Substring(2, colon - 2).Trim();
1267 if (engineName == "") engineName = defEngine;
1268 }
1269 }
1270
1271 // Make sure the default or requested engine is us.
1272 if (engineName != ScriptEngineName) {
1273
1274 // Not us, if requested engine exists, silently ignore script and let
1275 // requested engine handle it.
1276 IScriptModule[] engines = m_Scene.RequestModuleInterfaces<IScriptModule> ();
1277 foreach (IScriptModule eng in engines)
1278 {
1279 if (eng.ScriptEngineName == engineName)
1280 return;
1281 }
1282
1283 // Requested engine not defined, warn on console.
1284 // Then we try to handle it if we're the default engine, else we ignore it.
1285 m_log.Warn ("[XMREngine]: " + itemID.ToString() + " requests undefined/disabled engine " + engineName);
1286 m_log.Info ("[XMREngine]: - " + part.GetWorldPosition ());
1287 m_log.Info ("[XMREngine]: first line: " + firstline);
1288 if (defEngine != ScriptEngineName)
1289 {
1290 m_log.Info ("[XMREngine]: leaving it to the default script engine (" + defEngine + ") to process it");
1291 return;
1292 }
1293 m_log.Info ("[XMREngine]: will attempt to processing it anyway as default script engine");
1294 }
1295
1296 // Put on object/instance lists.
1297 XMRInstance instance = (XMRInstance)Activator.CreateInstance (ScriptCodeGen.xmrInstSuperType);
1298 instance.m_LocalID = localID;
1299 instance.m_ItemID = itemID;
1300 instance.m_SourceCode = script;
1301 instance.m_StartParam = startParam;
1302 instance.m_PostOnRez = postOnRez;
1303 instance.m_StateSource = (StateSource)stateSource;
1304 instance.m_Part = part;
1305 instance.m_PartUUID = part.UUID;
1306 instance.m_Item = item;
1307 instance.m_DescName = part.Name + ":" + item.Name;
1308 instance.m_IState = XMRInstState.CONSTRUCT;
1309
1310 lock (m_InstancesDict)
1311 {
1312 m_LockedDict = "RegisterInstance";
1313
1314 // Insert on internal list of all scripts being handled by this engine instance.
1315 m_InstancesDict[instance.m_ItemID] = instance;
1316
1317 // Insert on internal list of all scripts being handled by this engine instance
1318 // that are part of the object.
1319 List<UUID> itemIDList;
1320 if (!m_ObjectItemList.TryGetValue(instance.m_PartUUID, out itemIDList))
1321 {
1322 itemIDList = new List<UUID>();
1323 m_ObjectItemList[instance.m_PartUUID] = itemIDList;
1324 }
1325 if (!itemIDList.Contains(instance.m_ItemID))
1326 {
1327 itemIDList.Add(instance.m_ItemID);
1328 m_ObjectInstArray[instance.m_PartUUID] = null;
1329 }
1330
1331 m_LockedDict = "~RegisterInstance";
1332 }
1333
1334 // Compile and load it.
1335 lock (m_ScriptErrors)
1336 m_ScriptErrors.Remove (instance.m_ItemID);
1337
1338 LoadThreadWork (instance);
1339 }
1340
1341 /**
1342 * @brief This routine instantiates one script.
1343 */
1344 private void LoadThreadWork (XMRInstance instance)
1345 {
1346 // Compile and load the script in memory.
1347
1348 ArrayList errors = new ArrayList();
1349 Exception initerr = null;
1350 try
1351 {
1352 instance.Initialize(this, m_ScriptBasePath, m_StackSize, m_HeapSize, errors);
1353 }
1354 catch (Exception e1)
1355 {
1356 initerr = e1;
1357 }
1358 if ((initerr != null) && !instance.m_ForceRecomp)
1359 {
1360 UUID itemID = instance.m_ItemID;
1361 Verbose ("[XMREngine]: {0}/{2} first load failed ({1}), retrying after recompile",
1362 itemID.ToString(), initerr.Message, instance.m_Item.AssetID.ToString());
1363 Verbose ("[XMREngine]:\n{0}", initerr.ToString ());
1364 initerr = null;
1365 errors = new ArrayList();
1366 instance.m_ForceRecomp = true;
1367 try
1368 {
1369 instance.Initialize(this, m_ScriptBasePath, m_StackSize, m_HeapSize, errors);
1370 }
1371 catch (Exception e2)
1372 {
1373 initerr = e2;
1374 }
1375 }
1376 if (initerr != null)
1377 {
1378 UUID itemID = instance.m_ItemID;
1379 Verbose ("[XMREngine]: Error starting script {0}/{2}: {1}",
1380 itemID.ToString(), initerr.Message, instance.m_Item.AssetID.ToString());
1381 if (initerr.Message != "compilation errors")
1382 {
1383 Verbose ("[XMREngine]: - " + instance.m_Part.GetWorldPosition () + " " + instance.m_DescName);
1384 Verbose ("[XMREngine]: exception:\n{0}", initerr.ToString());
1385 }
1386
1387 OnRemoveScript (0, itemID);
1388
1389 // Post errors where GetScriptErrors() can see them.
1390
1391 if (errors.Count == 0)
1392 errors.Add(initerr.Message);
1393 else
1394 {
1395 foreach (Object err in errors)
1396 {
1397 if (m_ScriptDebug)
1398 m_log.DebugFormat ("[XMREngine]: {0}", err.ToString());
1399 }
1400 }
1401
1402 lock (m_ScriptErrors)
1403 m_ScriptErrors[instance.m_ItemID] = errors;
1404
1405 return;
1406 }
1407
1408 // Tell GetScriptErrors() that we have finished compiling/loading
1409 // successfully (by posting a 0 element array).
1410 lock (m_ScriptErrors)
1411 {
1412 if (instance.m_IState != XMRInstState.CONSTRUCT) throw new Exception("bad state");
1413 m_ScriptErrors[instance.m_ItemID] = noScriptErrors;
1414 }
1415
1416 // Transition from CONSTRUCT->ONSTARTQ and give to RunScriptThread().
1417 // Put it on the start queue so it will run any queued event handlers,
1418 // such as state_entry() or on_rez(). If there aren't any queued, it
1419 // will just go to idle state when RunOne() tries to dequeue an event.
1420 lock (instance.m_QueueLock)
1421 {
1422 if (instance.m_IState != XMRInstState.CONSTRUCT)
1423 throw new Exception("bad state");
1424 instance.m_IState = XMRInstState.ONSTARTQ;
1425 if (!instance.m_Running)
1426 instance.EmptyEventQueues ();
1427 }
1428 QueueToStart(instance);
1429 }
1430
1431 public void OnRemoveScript(uint localID, UUID itemID)
1432 {
1433 TraceCalls("[XMREngine]: OnRemoveScript(...,{0})", itemID.ToString());
1434
1435 // Remove from our list of known scripts.
1436 // After this, no more events can queue because we won't be
1437 // able to translate the itemID to an XMRInstance pointer.
1438
1439 XMRInstance instance = null;
1440 lock (m_InstancesDict)
1441 {
1442 m_LockedDict = "OnRemoveScript:" + itemID.ToString();
1443
1444 // Tell the instance to free off everything it can.
1445
1446 if (!m_InstancesDict.TryGetValue(itemID, out instance))
1447 {
1448 m_LockedDict = "~OnRemoveScript";
1449 return;
1450 }
1451
1452 // Tell it to stop executing anything.
1453 instance.suspendOnCheckRunHold = true;
1454
1455 // Remove it from our list of known script instances
1456 // mostly so no more events can queue to it.
1457 m_InstancesDict.Remove(itemID);
1458
1459 List<UUID> itemIDList;
1460 if (m_ObjectItemList.TryGetValue (instance.m_PartUUID, out itemIDList))
1461 {
1462 itemIDList.Remove(itemID);
1463 if (itemIDList.Count == 0)
1464 {
1465 m_ObjectItemList.Remove(instance.m_PartUUID);
1466 m_ObjectInstArray.Remove(instance.m_PartUUID);
1467 }
1468 else
1469 m_ObjectInstArray[instance.m_PartUUID] = null;
1470 }
1471
1472 // Delete the .state file as any needed contents were fetched with GetXMLState()
1473 // and stored on the database server.
1474 string stateFileName = XMRInstance.GetStateFileName(m_ScriptBasePath, itemID);
1475 File.Delete(stateFileName);
1476
1477 ScriptRemoved handlerScriptRemoved = OnScriptRemoved;
1478 if (handlerScriptRemoved != null)
1479 handlerScriptRemoved(itemID);
1480
1481 m_LockedDict = "~~OnRemoveScript";
1482 }
1483
1484 // Free off its stack and fun things like that.
1485 // If it is running, abort it.
1486 instance.Dispose ();
1487 }
1488
1489 public void OnScriptReset(uint localID, UUID itemID)
1490 {
1491 TraceCalls("[XMREngine]: XMREngine.OnScriptReset({0},{1})", localID.ToString(), itemID.ToString());
1492 ResetScript(itemID);
1493 }
1494
1495 public void OnStartScript(uint localID, UUID itemID)
1496 {
1497 XMRInstance instance = GetInstance (itemID);
1498 if (instance != null)
1499 instance.Running = true;
1500 }
1501
1502 public void OnStopScript(uint localID, UUID itemID)
1503 {
1504 XMRInstance instance = GetInstance (itemID);
1505 if (instance != null)
1506 instance.Running = false;
1507 }
1508
1509 public void OnGetScriptRunning(IClientAPI controllingClient,
1510 UUID objectID, UUID itemID)
1511 {
1512 XMRInstance instance = GetInstance (itemID);
1513 if (instance != null)
1514 {
1515 TraceCalls("[XMREngine]: XMREngine.OnGetScriptRunning({0},{1})", objectID.ToString(), itemID.ToString());
1516
1517 IEventQueue eq = World.RequestModuleInterface<IEventQueue>();
1518 if (eq == null)
1519 {
1520 controllingClient.SendScriptRunningReply(objectID, itemID,
1521 instance.Running);
1522 }
1523 else
1524 {
1525 eq.Enqueue(EventQueueHelper.ScriptRunningReplyEvent(objectID,
1526 itemID, instance.Running, true),
1527 controllingClient.AgentId);
1528 }
1529 }
1530 }
1531
1532 public bool HasScript(UUID itemID, out bool running)
1533 {
1534 XMRInstance instance = GetInstance (itemID);
1535 if (instance == null)
1536 {
1537 running = true;
1538 return false;
1539 }
1540 running = instance.Running;
1541 return true;
1542 }
1543
1544 /**
1545 * @brief Called once per frame update to see if scripts have
1546 * any such work to do.
1547 */
1548 private void OnFrame ()
1549 {
1550 if (m_FrameUpdateList != null)
1551 {
1552 ThreadStart frameupdates;
1553 lock (m_FrameUpdateLock)
1554 {
1555 frameupdates = m_FrameUpdateList;
1556 m_FrameUpdateList = null;
1557 }
1558 frameupdates ();
1559 }
1560 }
1561
1562 /**
1563 * @brief Add a one-shot delegate to list of things to do
1564 * synchronized with frame updates.
1565 */
1566 public void AddOnFrameUpdate (ThreadStart thunk)
1567 {
1568 lock (m_FrameUpdateLock)
1569 m_FrameUpdateList += thunk;
1570 }
1571
1572 /**
1573 * @brief Gets called early as part of shutdown,
1574 * right after "Persisting changed objects" message.
1575 */
1576 public void OnShutdown()
1577 {
1578 TraceCalls("[XMREngine]: XMREngine.OnShutdown()");
1579 }
1580
1581 /**
1582 * @brief Queue an instance to the StartQueue so it will run.
1583 * This queue is used for instances that have just had
1584 * an event queued to them when they were previously
1585 * idle. It must only be called by the thread that
1586 * transitioned the thread to XMRInstState.ONSTARTQ so
1587 * we don't get two threads trying to queue the same
1588 * instance to the m_StartQueue at the same time.
1589 */
1590 public void QueueToStart(XMRInstance inst)
1591 {
1592 lock (m_StartQueue)
1593 {
1594 if (inst.m_IState != XMRInstState.ONSTARTQ) throw new Exception("bad state");
1595 m_StartQueue.InsertTail(inst);
1596 }
1597 WakeUpOne();
1598 }
1599
1600 public void QueueToTrunk(ThreadStart thds)
1601 {
1602 lock (m_WakeUpLock)
1603 m_ThunkQueue.Enqueue (thds);
1604 WakeUpOne();
1605 }
1606
1607 /**
1608 * @brief A script may be sleeping, in which case we wake it.
1609 */
1610 public void WakeFromSleep(XMRInstance inst)
1611 {
1612 // Remove from sleep queue unless someone else already woke it.
1613 lock (m_SleepQueue)
1614 {
1615 if (inst.m_IState != XMRInstState.ONSLEEPQ)
1616 return;
1617
1618 m_SleepQueue.Remove(inst);
1619 inst.m_IState = XMRInstState.REMDFROMSLPQ;
1620 }
1621
1622 // Put on end of list of scripts that are ready to run.
1623 lock (m_YieldQueue)
1624 {
1625 inst.m_IState = XMRInstState.ONYIELDQ;
1626 m_YieldQueue.InsertTail(inst);
1627 }
1628
1629
1630 // Make sure the OS thread is running so it will see the script.
1631 WakeUpOne();
1632 }
1633
1634 /**
1635 * @brief An instance has just finished running for now,
1636 * figure out what to do with it next.
1637 * @param inst = instance in question, not on any queue at the moment
1638 * @param newIState = its new state
1639 * @returns with instance inserted onto proper queue (if any)
1640 */
1641 public void HandleNewIState(XMRInstance inst, XMRInstState newIState)
1642 {
1643
1644 // RunOne() should have left the instance in RUNNING state.
1645 if (inst.m_IState != XMRInstState.RUNNING)
1646 throw new Exception("bad state");
1647
1648
1649 // Now see what RunOne() wants us to do with the instance next.
1650 switch (newIState)
1651 {
1652
1653 // Instance has set m_SleepUntil to when it wants to sleep until.
1654 // So insert instance in sleep queue by ascending wake time.
1655 // Then wake the timer thread if this is the new first entry
1656 // so it will reset its timer.
1657 case XMRInstState.ONSLEEPQ:
1658 lock (m_SleepQueue)
1659 {
1660 XMRInstance after;
1661
1662 inst.m_IState = XMRInstState.ONSLEEPQ;
1663 for (after = m_SleepQueue.PeekHead(); after != null; after = after.m_NextInst)
1664 {
1665 if (after.m_SleepUntil > inst.m_SleepUntil)
1666 break;
1667 }
1668 m_SleepQueue.InsertBefore(inst, after);
1669 if (m_SleepQueue.PeekHead() == inst)
1670 {
1671 Monitor.Pulse (m_SleepQueue);
1672 }
1673 }
1674 break;
1675
1676 // Instance just took a long time to run and got wacked by the
1677 // slicer. So put on end of yield queue to let someone else
1678 // run. If there is no one else, it will run again right away.
1679 case XMRInstState.ONYIELDQ:
1680 lock (m_YieldQueue)
1681 {
1682 inst.m_IState = XMRInstState.ONYIELDQ;
1683 m_YieldQueue.InsertTail(inst);
1684 }
1685 break;
1686
1687 // Instance finished executing an event handler. So if there is
1688 // another event queued for it, put it on the start queue so it
1689 // will process the new event. Otherwise, mark it idle and the
1690 // next event to queue to it will start it up.
1691 case XMRInstState.FINISHED:
1692 Monitor.Enter(inst.m_QueueLock);
1693 if (!inst.m_Suspended && (inst.m_EventQueue.Count > 0))
1694 {
1695 Monitor.Exit(inst.m_QueueLock);
1696 lock (m_StartQueue)
1697 {
1698 inst.m_IState = XMRInstState.ONSTARTQ;
1699 m_StartQueue.InsertTail (inst);
1700 }
1701 }
1702 else
1703 {
1704 inst.m_IState = XMRInstState.IDLE;
1705 Monitor.Exit(inst.m_QueueLock);
1706 }
1707 break;
1708
1709 // Its m_SuspendCount > 0.
1710 // Don't put it on any queue and it won't run.
1711 // Since it's not IDLE, even queuing an event won't start it.
1712 case XMRInstState.SUSPENDED:
1713 inst.m_IState = XMRInstState.SUSPENDED;
1714 break;
1715
1716 // It has been disposed of.
1717 // Just set the new state and all refs should theoretically drop off
1718 // as the instance is no longer in any list.
1719 case XMRInstState.DISPOSED:
1720 inst.m_IState = XMRInstState.DISPOSED;
1721 break;
1722
1723 // RunOne returned something bad.
1724 default:
1725 throw new Exception("bad new state");
1726 }
1727 }
1728
1729 /**
1730 * @brief Thread that moves instances from the Sleep queue to the Yield queue.
1731 */
1732 private void RunSleepThread()
1733 {
1734 double deltaTS;
1735 int deltaMS;
1736 XMRInstance inst;
1737
1738 while (true)
1739 {
1740 lock (m_SleepQueue)
1741 {
1742
1743 // Wait here until there is a script on the timer queue that has expired.
1744 while (true)
1745 {
1746 UpdateMyThread ();
1747 if (m_Exiting)
1748 {
1749 MyThreadExiting ();
1750 return;
1751 }
1752 inst = m_SleepQueue.PeekHead();
1753 if (inst == null)
1754 {
1755 Monitor.Wait (m_SleepQueue, Watchdog.DEFAULT_WATCHDOG_TIMEOUT_MS / 2);
1756 continue;
1757 }
1758 if (inst.m_IState != XMRInstState.ONSLEEPQ) throw new Exception("bad state");
1759 deltaTS = (inst.m_SleepUntil - DateTime.UtcNow).TotalMilliseconds;
1760 if (deltaTS <= 0.0)
1761 break;
1762 deltaMS = Int32.MaxValue;
1763 if (deltaTS < Int32.MaxValue)
1764 deltaMS = (int)deltaTS;
1765 if (deltaMS > Watchdog.DEFAULT_WATCHDOG_TIMEOUT_MS / 2)
1766 {
1767 deltaMS = Watchdog.DEFAULT_WATCHDOG_TIMEOUT_MS / 2;
1768 }
1769 Monitor.Wait (m_SleepQueue, deltaMS);
1770 }
1771
1772 // Remove the expired entry from the timer queue.
1773 m_SleepQueue.RemoveHead();
1774 inst.m_IState = XMRInstState.REMDFROMSLPQ;
1775 }
1776
1777 // Post the script to the yield queue so it will run and wake a script thread to run it.
1778 lock (m_YieldQueue)
1779 {
1780 inst.m_IState = XMRInstState.ONYIELDQ;
1781 m_YieldQueue.InsertTail(inst);
1782 }
1783 WakeUpOne ();
1784 }
1785 }
1786
1787 /**
1788 * @brief Thread that runs a time slicer.
1789 */
1790 public void Suspend(UUID itemID, int ms)
1791 {
1792 XMRInstance instance = GetInstance (itemID);
1793 if (instance != null)
1794 instance.Sleep(ms);
1795 }
1796
1797 public void Die(UUID itemID)
1798 {
1799 XMRInstance instance = GetInstance (itemID);
1800 if (instance != null)
1801 {
1802 TraceCalls("[XMREngine]: XMREngine.Die({0})", itemID.ToString());
1803 instance.Die();
1804 }
1805 }
1806
1807 /**
1808 * @brief Get specific script instance for which OnRezScript()
1809 * has been called for an XMREngine script, and that
1810 * OnRemoveScript() has not been called since.
1811 * @param itemID = as passed to OnRezScript() identifying a specific script instance
1812 * @returns null: not one of our scripts (maybe XEngine etc)
1813 * else: points to the script instance
1814 */
1815 public XMRInstance GetInstance(UUID itemID)
1816 {
1817 XMRInstance instance;
1818 lock (m_InstancesDict)
1819 {
1820 if (!m_InstancesDict.TryGetValue(itemID, out instance))
1821 instance = null;
1822 }
1823 return instance;
1824 }
1825
1826 // Called occasionally to write script state to .state file so the
1827 // script will restart from its last known state if the region crashes
1828 // and gets restarted.
1829 private void DoMaintenance(object source, ElapsedEventArgs e)
1830 {
1831 XMRInstance[] instanceArray;
1832
1833 lock (m_InstancesDict)
1834 instanceArray = System.Linq.Enumerable.ToArray(m_InstancesDict.Values);
1835
1836 foreach (XMRInstance ins in instanceArray)
1837 {
1838 // Don't save attachments
1839 if (ins.m_Part.ParentGroup.IsAttachment)
1840 continue;
1841 ins.GetExecutionState(new XmlDocument());
1842 }
1843 }
1844
1845 /**
1846 * @brief Retrieve errors generated by a previous call to OnRezScript().
1847 * We are guaranteed this routine will not be called before the
1848 * corresponding OnRezScript() has returned. It blocks until the
1849 * compile has completed.
1850 */
1851 public ArrayList GetScriptErrors(UUID itemID)
1852 {
1853 ArrayList errors;
1854
1855 lock (m_ScriptErrors)
1856 {
1857 while (!m_ScriptErrors.TryGetValue (itemID, out errors))
1858 {
1859 Monitor.Wait (m_ScriptErrors);
1860 }
1861 m_ScriptErrors.Remove (itemID);
1862 }
1863 return errors;
1864 }
1865
1866 /**
1867 * @brief Return a list of all script execution times.
1868 */
1869 public Dictionary<uint, float> GetObjectScriptsExecutionTimes ()
1870 {
1871 Dictionary<uint, float> topScripts = new Dictionary<uint, float> ();
1872 lock (m_InstancesDict)
1873 {
1874 foreach (XMRInstance instance in m_InstancesDict.Values)
1875 {
1876 uint rootLocalID = instance.m_Part.ParentGroup.LocalId;
1877 float oldTotal;
1878 if (!topScripts.TryGetValue (rootLocalID, out oldTotal))
1879 oldTotal = 0;
1880
1881 topScripts[rootLocalID] = (float)instance.m_CPUTime + oldTotal;
1882 }
1883 }
1884 return topScripts;
1885 }
1886
1887 /**
1888 * @brief A float the value is a representative execution time in
1889 * milliseconds of all scripts in the link set.
1890 * @param itemIDs = list of scripts in the link set
1891 * @returns milliseconds for all those scripts
1892 */
1893 public float GetScriptExecutionTime (List<UUID> itemIDs)
1894 {
1895 if ((itemIDs == null) || (itemIDs.Count == 0))
1896 return 0;
1897
1898 float time = 0;
1899 foreach (UUID itemID in itemIDs)
1900 {
1901 XMRInstance instance = GetInstance (itemID);
1902 if ((instance != null) && instance.Running)
1903 time += (float) instance.m_CPUTime;
1904 }
1905 return time;
1906 }
1907
1908 /**
1909 * @brief Block script from dequeuing events.
1910 */
1911 public void SuspendScript(UUID itemID)
1912 {
1913 XMRInstance instance = GetInstance (itemID);
1914 if (instance != null)
1915 {
1916 TraceCalls("[XMREngine]: XMREngine.SuspendScript({0})", itemID.ToString());
1917 instance.SuspendIt();
1918 }
1919 }
1920
1921 /**
1922 * @brief Allow script to dequeue events.
1923 */
1924 public void ResumeScript(UUID itemID)
1925 {
1926 XMRInstance instance = GetInstance (itemID);
1927 if (instance != null)
1928 {
1929 TraceCalls("[XMREngine]: XMREngine.ResumeScript({0})", itemID.ToString());
1930 instance.ResumeIt();
1931 }
1932 else
1933 {
1934 // probably an XEngine script
1935 }
1936 }
1937
1938 /**
1939 * @brief Rebuild m_ObjectInstArray[partUUID] from m_ObjectItemList[partUUID]
1940 * @param partUUID = which object in scene to rebuild for
1941 */
1942 private XMRInstance[] RebuildObjectInstArray (UUID partUUID)
1943 {
1944 List<UUID> itemIDList = m_ObjectItemList[partUUID];
1945 int n = 0;
1946 foreach (UUID itemID in itemIDList)
1947 {
1948 if (m_InstancesDict.ContainsKey(itemID))
1949 n ++;
1950 }
1951 XMRInstance[] a = new XMRInstance[n];
1952 n = 0;
1953 foreach (UUID itemID in itemIDList)
1954 {
1955 if (m_InstancesDict.TryGetValue (itemID, out a[n]))
1956 n ++;
1957 }
1958 m_ObjectInstArray[partUUID] = a;
1959 return a;
1960 }
1961
1962 public void TraceCalls (string format, params object[] args)
1963 {
1964 if (m_TraceCalls)
1965 m_log.DebugFormat (format, args);
1966 }
1967 public void Verbose (string format, params object[] args)
1968 {
1969 if (m_Verbose)
1970 m_log.DebugFormat (format, args);
1971 }
1972
1973 /**
1974 * @brief Manage our threads.
1975 */
1976 public static Thread StartMyThread (ThreadStart start, string name, ThreadPriority priority)
1977 {
1978 m_log.Debug ("[XMREngine]: starting thread " + name);
1979 Thread thread = new Thread (start);
1980 thread.Name = name;
1981 thread.Priority = priority;
1982 thread.IsBackground = true;
1983 thread.Start ();
1984
1985 Watchdog.ThreadWatchdogInfo info = new Watchdog.ThreadWatchdogInfo (thread, Watchdog.DEFAULT_WATCHDOG_TIMEOUT_MS, name);
1986 Watchdog.AddThread (info, name, true);
1987
1988 return thread;
1989 }
1990
1991 public static void UpdateMyThread ()
1992 {
1993 Watchdog.UpdateThread();
1994 }
1995
1996 public static void MyThreadExiting ()
1997 {
1998 Watchdog.RemoveThread(true);
1999 }
2000
2001 public void RunScriptThread(XMRScriptThread xthd)
2002 {
2003 XMRInstance inst;
2004 while (!m_Exiting)
2005 {
2006 Watchdog.UpdateThread();
2007
2008 /*
2009 * Handle 'xmr resume/suspend' commands.
2010 */
2011 if (m_SuspendScriptThreadFlag)
2012 {
2013 lock (m_WakeUpLock)
2014 {
2015 while (m_SuspendScriptThreadFlag &&
2016 !m_Exiting &&
2017 (m_ThunkQueue.Count == 0))
2018 {
2019 Monitor.Wait (m_WakeUpLock, Watchdog.DEFAULT_WATCHDOG_TIMEOUT_MS / 2);
2020 XMREngine.UpdateMyThread ();
2021 }
2022 }
2023 }
2024
2025 /*
2026 * Maybe there are some scripts waiting to be migrated in or out.
2027 */
2028 ThreadStart thunk = null;
2029 lock (m_WakeUpLock)
2030 {
2031 if (m_ThunkQueue.Count > 0)
2032 thunk = m_ThunkQueue.Dequeue ();
2033 }
2034 if (thunk != null)
2035 {
2036 inst = (XMRInstance)thunk.Target;
2037 thunk ();
2038 if (m_Exiting || m_SuspendScriptThreadFlag)
2039 continue;
2040 }
2041
2042 if (m_StartProcessing)
2043 {
2044 // If event just queued to any idle scripts
2045 // start them right away. But only start so
2046 // many so we can make some progress on yield
2047 // queue.
2048
2049 int numStarts;
2050 for (numStarts = 5; -- numStarts >= 0;)
2051 {
2052 lock (m_StartQueue)
2053 {
2054 inst = m_StartQueue.RemoveHead();
2055 }
2056 if (inst == null) break;
2057 if (inst.m_IState != XMRInstState.ONSTARTQ) throw new Exception("bad state");
2058 xthd.RunInstance (inst);
2059 if (m_Exiting || m_SuspendScriptThreadFlag)
2060 continue;
2061 }
2062
2063 // If there is something to run, run it
2064 // then rescan from the beginning in case
2065 // a lot of things have changed meanwhile.
2066 //
2067 // These are considered lower priority than
2068 // m_StartQueue as they have been taking at
2069 // least one quantum of CPU time and event
2070 // handlers are supposed to be quick.
2071
2072 lock (m_YieldQueue)
2073 {
2074 inst = m_YieldQueue.RemoveHead();
2075 }
2076 if (inst != null)
2077 {
2078 if (inst.m_IState != XMRInstState.ONYIELDQ) throw new Exception("bad state");
2079 xthd.RunInstance(inst);
2080 numStarts = -1;
2081 }
2082
2083 // If we left something dangling in the m_StartQueue or m_YieldQueue, go back to check it.
2084 if (m_Exiting || numStarts < 0)
2085 continue;
2086 }
2087
2088 // Nothing to do, sleep.
2089 lock (m_WakeUpLock)
2090 {
2091 if (!xthd.m_WakeUpThis && (m_WakeUpOne <= 0) && !m_Exiting)
2092 Monitor.Wait(m_WakeUpLock, Watchdog.DEFAULT_WATCHDOG_TIMEOUT_MS / 2);
2093
2094 xthd.m_WakeUpThis = false;
2095 if ((m_WakeUpOne > 0) && (--m_WakeUpOne > 0))
2096 Monitor.Pulse (m_WakeUpLock);
2097 }
2098 }
2099 Watchdog.RemoveThread(true);
2100 }
2101 }
2102}