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