clockwerk-opensim – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 vero 1 /*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27  
28 using System;
29 using System.Collections;
30 using System.Collections.Generic;
31 using System.Globalization;
32 using System.IO;
33 using System.Linq;
34 using System.Reflection;
35 using System.Security;
36 using System.Security.Policy;
37 using System.Text;
38 using System.Threading;
39 using System.Xml;
40 using OpenMetaverse;
41 using OpenMetaverse.StructuredData;
42 using log4net;
43 using Nini.Config;
44 using Amib.Threading;
45 using OpenSim.Framework;
46 using OpenSim.Framework.Console;
47 using OpenSim.Region.Framework.Scenes;
48 using OpenSim.Region.Framework.Interfaces;
49 using OpenSim.Region.ScriptEngine.Interfaces;
50 using OpenSim.Region.ScriptEngine.Shared;
51 using OpenSim.Region.ScriptEngine.Shared.CodeTools;
52 using OpenSim.Region.ScriptEngine.Shared.Instance;
53 using OpenSim.Region.ScriptEngine.Shared.Api;
54 using OpenSim.Region.ScriptEngine.Shared.Api.Plugins;
55 using OpenSim.Region.ScriptEngine.Shared.ScriptBase;
56 using OpenSim.Region.ScriptEngine.XEngine.ScriptBase;
57 using Timer = OpenSim.Region.ScriptEngine.Shared.Api.Plugins.Timer;
58  
59 using ScriptCompileQueue = OpenSim.Framework.LocklessQueue<object[]>;
60  
61 namespace OpenSim.Region.ScriptEngine.XEngine
62 {
63 public class XEngine : INonSharedRegionModule, IScriptModule, IScriptEngine
64 {
65 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
66  
67 /// <summary>
68 /// Control the printing of certain debug messages.
69 /// </summary>
70 /// <remarks>
71 /// If DebugLevel >= 1, then we log every time that a script is started.
72 /// </remarks>
73 // public int DebugLevel { get; set; }
74  
75 private SmartThreadPool m_ThreadPool;
76 private int m_MaxScriptQueue;
77 private Scene m_Scene;
78 private IConfig m_ScriptConfig = null;
79 private IConfigSource m_ConfigSource = null;
80 private ICompiler m_Compiler;
81 private int m_MinThreads;
82 private int m_MaxThreads;
83  
84 /// <summary>
85 /// Amount of time to delay before starting.
86 /// </summary>
87 private int m_StartDelay;
88  
89 /// <summary>
90 /// Are we stopping scripts co-operatively by inserting checks in them at C# compile time (true) or aborting
91 /// their threads (false)?
92 /// </summary>
93 private bool m_coopTermination;
94  
95 private int m_IdleTimeout;
96 private int m_StackSize;
97 private int m_SleepTime;
98 private int m_SaveTime;
99 private ThreadPriority m_Prio;
100 private bool m_Enabled = false;
101 private bool m_InitialStartup = true;
102 private int m_ScriptFailCount; // Number of script fails since compile queue was last empty
103 private string m_ScriptErrorMessage;
104 private Dictionary<string, string> m_uniqueScripts = new Dictionary<string, string>();
105 private bool m_AppDomainLoading;
106 private Dictionary<UUID,ArrayList> m_ScriptErrors =
107 new Dictionary<UUID,ArrayList>();
108  
109 // disable warning: need to keep a reference to XEngine.EventManager
110 // alive to avoid it being garbage collected
111 #pragma warning disable 414
112 private EventManager m_EventManager;
113 #pragma warning restore 414
114 private IXmlRpcRouter m_XmlRpcRouter;
115 private int m_EventLimit;
116 private bool m_KillTimedOutScripts;
117  
118 /// <summary>
119 /// Number of milliseconds we will wait for a script event to complete on script stop before we forcibly abort
120 /// its thread.
121 /// </summary>
122 /// <remarks>
123 /// It appears that if a script thread is aborted whilst it is holding ReaderWriterLockSlim (possibly the write
124 /// lock) then the lock is not properly released. This causes mono 2.6, 2.10 and possibly
125 /// later to crash, sometimes with symptoms such as a leap to 100% script usage and a vm thead dump showing
126 /// all threads waiting on release of ReaderWriterLockSlim write thread which none of the threads listed
127 /// actually hold.
128 ///
129 /// Pausing for event completion reduces the risk of this happening. However, it may be that aborting threads
130 /// is not a mono issue per se but rather a risky activity in itself in an AppDomain that is not immediately
131 /// shutting down.
132 /// </remarks>
133 private int m_WaitForEventCompletionOnScriptStop = 1000;
134  
135 private string m_ScriptEnginesPath = null;
136  
137 private ExpiringCache<UUID, bool> m_runFlags = new ExpiringCache<UUID, bool>();
138  
139 /// <summary>
140 /// Is the entire simulator in the process of shutting down?
141 /// </summary>
142 private bool m_SimulatorShuttingDown;
143  
144 private static List<XEngine> m_ScriptEngines =
145 new List<XEngine>();
146  
147 // Maps the local id to the script inventory items in it
148  
149 private Dictionary<uint, List<UUID> > m_PrimObjects =
150 new Dictionary<uint, List<UUID> >();
151  
152 // Maps the UUID above to the script instance
153  
154 private Dictionary<UUID, IScriptInstance> m_Scripts =
155 new Dictionary<UUID, IScriptInstance>();
156  
157 // Maps the asset ID to the assembly
158  
159 private Dictionary<UUID, string> m_Assemblies =
160 new Dictionary<UUID, string>();
161  
162 private Dictionary<string, int> m_AddingAssemblies =
163 new Dictionary<string, int>();
164  
165 // This will list AppDomains by script asset
166  
167 private Dictionary<UUID, AppDomain> m_AppDomains =
168 new Dictionary<UUID, AppDomain>();
169  
170 // List the scripts running in each appdomain
171  
172 private Dictionary<UUID, List<UUID> > m_DomainScripts =
173 new Dictionary<UUID, List<UUID> >();
174  
175 private ScriptCompileQueue m_CompileQueue = new ScriptCompileQueue();
176 IWorkItemResult m_CurrentCompile = null;
177 private Dictionary<UUID, int> m_CompileDict = new Dictionary<UUID, int>();
178  
179 private ScriptEngineConsoleCommands m_consoleCommands;
180  
181 public string ScriptEngineName
182 {
183 get { return "XEngine"; }
184 }
185  
186 public string ScriptClassName { get; private set; }
187  
188 public string ScriptBaseClassName { get; private set; }
189  
190 public ParameterInfo[] ScriptBaseClassParameters { get; private set; }
191  
192 public string[] ScriptReferencedAssemblies { get; private set; }
193  
194 public Scene World
195 {
196 get { return m_Scene; }
197 }
198  
199 public static List<XEngine> ScriptEngines
200 {
201 get { return m_ScriptEngines; }
202 }
203  
204 public IScriptModule ScriptModule
205 {
206 get { return this; }
207 }
208  
209 // private struct RezScriptParms
210 // {
211 // uint LocalID;
212 // UUID ItemID;
213 // string Script;
214 // }
215  
216 public IConfig Config
217 {
218 get { return m_ScriptConfig; }
219 }
220  
221 public string ScriptEnginePath
222 {
223 get { return m_ScriptEnginesPath; }
224 }
225  
226 public IConfigSource ConfigSource
227 {
228 get { return m_ConfigSource; }
229 }
230  
231 /// <summary>
232 /// Event fired after the script engine has finished removing a script.
233 /// </summary>
234 public event ScriptRemoved OnScriptRemoved;
235  
236 /// <summary>
237 /// Event fired after the script engine has finished removing a script from an object.
238 /// </summary>
239 public event ObjectRemoved OnObjectRemoved;
240  
241 public void Initialise(IConfigSource configSource)
242 {
243 if (configSource.Configs["XEngine"] == null)
244 return;
245  
246 m_ScriptConfig = configSource.Configs["XEngine"];
247 m_ConfigSource = configSource;
248  
249 string rawScriptStopStrategy = m_ScriptConfig.GetString("ScriptStopStrategy", "coop");
250  
251 m_log.InfoFormat("[XEngine]: Script stop strategy is {0}", rawScriptStopStrategy);
252  
253 if (rawScriptStopStrategy == "co-op")
254 {
255 m_coopTermination = true;
256 ScriptClassName = "XEngineScript";
257 ScriptBaseClassName = typeof(XEngineScriptBase).FullName;
258 ScriptBaseClassParameters = typeof(XEngineScriptBase).GetConstructor(new Type[] { typeof(WaitHandle) }).GetParameters();
259 ScriptReferencedAssemblies = new string[] { Path.GetFileName(typeof(XEngineScriptBase).Assembly.Location) };
260 }
261 else
262 {
263 ScriptClassName = "Script";
264 ScriptBaseClassName = typeof(ScriptBaseClass).FullName;
265 }
266  
267 // Console.WriteLine("ASSEMBLY NAME: {0}", ScriptReferencedAssemblies[0]);
268 }
269  
270 public void AddRegion(Scene scene)
271 {
272 if (m_ScriptConfig == null)
273 return;
274  
275 m_ScriptFailCount = 0;
276 m_ScriptErrorMessage = String.Empty;
277  
278 m_Enabled = m_ScriptConfig.GetBoolean("Enabled", true);
279  
280 if (!m_Enabled)
281 return;
282  
283 AppDomain.CurrentDomain.AssemblyResolve +=
284 OnAssemblyResolve;
285  
286 m_Scene = scene;
287 m_log.InfoFormat("[XEngine]: Initializing scripts in region {0}", m_Scene.RegionInfo.RegionName);
288  
289 m_MinThreads = m_ScriptConfig.GetInt("MinThreads", 2);
290 m_MaxThreads = m_ScriptConfig.GetInt("MaxThreads", 100);
291 m_IdleTimeout = m_ScriptConfig.GetInt("IdleTimeout", 60);
292 string priority = m_ScriptConfig.GetString("Priority", "BelowNormal");
293 m_StartDelay = m_ScriptConfig.GetInt("StartDelay", 15000);
294 m_MaxScriptQueue = m_ScriptConfig.GetInt("MaxScriptEventQueue",300);
295 m_StackSize = m_ScriptConfig.GetInt("ThreadStackSize", 262144);
296 m_SleepTime = m_ScriptConfig.GetInt("MaintenanceInterval", 10) * 1000;
297 m_AppDomainLoading = m_ScriptConfig.GetBoolean("AppDomainLoading", true);
298  
299 m_EventLimit = m_ScriptConfig.GetInt("EventLimit", 30);
300 m_KillTimedOutScripts = m_ScriptConfig.GetBoolean("KillTimedOutScripts", false);
301 m_SaveTime = m_ScriptConfig.GetInt("SaveInterval", 120) * 1000;
302 m_WaitForEventCompletionOnScriptStop
303 = m_ScriptConfig.GetInt("WaitForEventCompletionOnScriptStop", m_WaitForEventCompletionOnScriptStop);
304  
305 m_ScriptEnginesPath = m_ScriptConfig.GetString("ScriptEnginesPath", "ScriptEngines");
306  
307 m_Prio = ThreadPriority.BelowNormal;
308 switch (priority)
309 {
310 case "Lowest":
311 m_Prio = ThreadPriority.Lowest;
312 break;
313 case "BelowNormal":
314 m_Prio = ThreadPriority.BelowNormal;
315 break;
316 case "Normal":
317 m_Prio = ThreadPriority.Normal;
318 break;
319 case "AboveNormal":
320 m_Prio = ThreadPriority.AboveNormal;
321 break;
322 case "Highest":
323 m_Prio = ThreadPriority.Highest;
324 break;
325 default:
326 m_log.ErrorFormat("[XEngine] Invalid thread priority: '{0}'. Assuming BelowNormal", priority);
327 break;
328 }
329  
330 lock (m_ScriptEngines)
331 {
332 m_ScriptEngines.Add(this);
333 }
334  
335 // Needs to be here so we can queue the scripts that need starting
336 //
337 m_Scene.EventManager.OnRezScript += OnRezScript;
338  
339 // Complete basic setup of the thread pool
340 //
341 SetupEngine(m_MinThreads, m_MaxThreads, m_IdleTimeout, m_Prio,
342 m_MaxScriptQueue, m_StackSize);
343  
344 m_Scene.StackModuleInterface<IScriptModule>(this);
345  
346 m_XmlRpcRouter = m_Scene.RequestModuleInterface<IXmlRpcRouter>();
347 if (m_XmlRpcRouter != null)
348 {
349 OnScriptRemoved += m_XmlRpcRouter.ScriptRemoved;
350 OnObjectRemoved += m_XmlRpcRouter.ObjectRemoved;
351 }
352  
353 m_consoleCommands = new ScriptEngineConsoleCommands(this);
354 m_consoleCommands.RegisterCommands();
355  
356 MainConsole.Instance.Commands.AddCommand(
357 "Scripts", false, "xengine status", "xengine status", "Show status information",
358 "Show status information on the script engine.",
359 HandleShowStatus);
360  
361 MainConsole.Instance.Commands.AddCommand(
362 "Scripts", false, "scripts show", "scripts show [<script-item-uuid>+]", "Show script information",
363 "Show information on all scripts known to the script engine.\n"
364 + "If one or more <script-item-uuid>s are given then only information on that script will be shown.",
365 HandleShowScripts);
366  
367 MainConsole.Instance.Commands.AddCommand(
368 "Scripts", false, "show scripts", "show scripts [<script-item-uuid>+]", "Show script information",
369 "Synonym for scripts show command", HandleShowScripts);
370  
371 MainConsole.Instance.Commands.AddCommand(
372 "Scripts", false, "scripts suspend", "scripts suspend [<script-item-uuid>+]", "Suspends all running scripts",
373 "Suspends all currently running scripts. This only suspends event delivery, it will not suspend a"
374 + " script that is currently processing an event.\n"
375 + "Suspended scripts will continue to accumulate events but won't process them.\n"
376 + "If one or more <script-item-uuid>s are given then only that script will be suspended. Otherwise, all suitable scripts are suspended.",
377 (module, cmdparams) => HandleScriptsAction(cmdparams, HandleSuspendScript));
378  
379 MainConsole.Instance.Commands.AddCommand(
380 "Scripts", false, "scripts resume", "scripts resume [<script-item-uuid>+]", "Resumes all suspended scripts",
381 "Resumes all currently suspended scripts.\n"
382 + "Resumed scripts will process all events accumulated whilst suspended.\n"
383 + "If one or more <script-item-uuid>s are given then only that script will be resumed. Otherwise, all suitable scripts are resumed.",
384 (module, cmdparams) => HandleScriptsAction(cmdparams, HandleResumeScript));
385  
386 MainConsole.Instance.Commands.AddCommand(
387 "Scripts", false, "scripts stop", "scripts stop [<script-item-uuid>+]", "Stops all running scripts",
388 "Stops all running scripts.\n"
389 + "If one or more <script-item-uuid>s are given then only that script will be stopped. Otherwise, all suitable scripts are stopped.",
390 (module, cmdparams) => HandleScriptsAction(cmdparams, HandleStopScript));
391  
392 MainConsole.Instance.Commands.AddCommand(
393 "Scripts", false, "scripts start", "scripts start [<script-item-uuid>+]", "Starts all stopped scripts",
394 "Starts all stopped scripts.\n"
395 + "If one or more <script-item-uuid>s are given then only that script will be started. Otherwise, all suitable scripts are started.",
396 (module, cmdparams) => HandleScriptsAction(cmdparams, HandleStartScript));
397  
398 MainConsole.Instance.Commands.AddCommand(
399 "Debug", false, "debug scripts log", "debug scripts log <item-id> <log-level>", "Extra debug logging for a particular script.",
400 "Activates or deactivates extra debug logging for the given script.\n"
401 + "Level == 0, deactivate extra debug logging.\n"
402 + "Level >= 1, log state changes.\n"
403 + "Level >= 2, log event invocations.\n",
404 HandleDebugScriptLogCommand);
405  
406 // MainConsole.Instance.Commands.AddCommand(
407 // "Debug", false, "debug xengine", "debug xengine [<level>]",
408 // "Turn on detailed xengine debugging.",
409 // "If level <= 0, then no extra logging is done.\n"
410 // + "If level >= 1, then we log every time that a script is started.",
411 // HandleDebugLevelCommand);
412 }
413  
414 private void HandleDebugScriptLogCommand(string module, string[] args)
415 {
416 if (!(MainConsole.Instance.ConsoleScene == null || MainConsole.Instance.ConsoleScene == m_Scene))
417 return;
418  
419 if (args.Length != 5)
420 {
421 MainConsole.Instance.Output("Usage: debug script log <item-id> <log-level>");
422 return;
423 }
424  
425 UUID itemId;
426  
427 if (!ConsoleUtil.TryParseConsoleUuid(MainConsole.Instance, args[3], out itemId))
428 return;
429  
430 int newLevel;
431  
432 if (!ConsoleUtil.TryParseConsoleInt(MainConsole.Instance, args[4], out newLevel))
433 return;
434  
435 IScriptInstance si;
436  
437 lock (m_Scripts)
438 {
439 // XXX: We can't give the user feedback on a bad item id because this may apply to a different script
440 // engine
441 if (!m_Scripts.TryGetValue(itemId, out si))
442 return;
443 }
444  
445 si.DebugLevel = newLevel;
446 MainConsole.Instance.OutputFormat("Set debug level of {0} {1} to {2}", si.ScriptName, si.ItemID, newLevel);
447 }
448  
449 /// <summary>
450 /// Change debug level
451 /// </summary>
452 /// <param name="module"></param>
453 /// <param name="args"></param>
454 // private void HandleDebugLevelCommand(string module, string[] args)
455 // {
456 // if (args.Length == 3)
457 // {
458 // int newDebug;
459 // if (int.TryParse(args[2], out newDebug))
460 // {
461 // DebugLevel = newDebug;
462 // MainConsole.Instance.OutputFormat("Debug level set to {0}", newDebug);
463 // }
464 // }
465 // else if (args.Length == 2)
466 // {
467 // MainConsole.Instance.OutputFormat("Current debug level is {0}", DebugLevel);
468 // }
469 // else
470 // {
471 // MainConsole.Instance.Output("Usage: debug xengine 0..1");
472 // }
473 // }
474  
475 /// <summary>
476 /// Parse the raw item id into a script instance from the command params if it's present.
477 /// </summary>
478 /// <param name="cmdparams"></param>
479 /// <param name="instance"></param>
480 /// <param name="comparer">Basis on which to sort output. Can be null if no sort needs to take place</param>
481 private void HandleScriptsAction(string[] cmdparams, Action<IScriptInstance> action)
482 {
483 HandleScriptsAction<object>(cmdparams, action, null);
484 }
485  
486 /// <summary>
487 /// Parse the raw item id into a script instance from the command params if it's present.
488 /// </summary>
489 /// <param name="cmdparams"></param>
490 /// <param name="instance"></param>
491 /// <param name="keySelector">Basis on which to sort output. Can be null if no sort needs to take place</param>
492 private void HandleScriptsAction<TKey>(
493 string[] cmdparams, Action<IScriptInstance> action, System.Func<IScriptInstance, TKey> keySelector)
494 {
495 if (!(MainConsole.Instance.ConsoleScene == null || MainConsole.Instance.ConsoleScene == m_Scene))
496 return;
497  
498 lock (m_Scripts)
499 {
500 string rawItemId;
501 UUID itemId = UUID.Zero;
502  
503 if (cmdparams.Length == 2)
504 {
505 IEnumerable<IScriptInstance> scripts = m_Scripts.Values;
506  
507 if (keySelector != null)
508 scripts = scripts.OrderBy<IScriptInstance, TKey>(keySelector);
509  
510 foreach (IScriptInstance instance in scripts)
511 action(instance);
512  
513 return;
514 }
515  
516 for (int i = 2; i < cmdparams.Length; i++)
517 {
518 rawItemId = cmdparams[i];
519  
520 if (!UUID.TryParse(rawItemId, out itemId))
521 {
522 MainConsole.Instance.OutputFormat("ERROR: {0} is not a valid UUID", rawItemId);
523 continue;
524 }
525  
526 if (itemId != UUID.Zero)
527 {
528 IScriptInstance instance = GetInstance(itemId);
529 if (instance == null)
530 {
531 // Commented out for now since this will cause false reports on simulators with more than
532 // one scene where the current command line set region is 'root' (which causes commands to
533 // go to both regions... (sigh)
534 // MainConsole.Instance.OutputFormat("Error - No item found with id {0}", itemId);
535 continue;
536 }
537 else
538 {
539 action(instance);
540 }
541 }
542 }
543 }
544 }
545  
546 private void HandleShowStatus(string module, string[] cmdparams)
547 {
548 if (!(MainConsole.Instance.ConsoleScene == null || MainConsole.Instance.ConsoleScene == m_Scene))
549 return;
550  
551 MainConsole.Instance.Output(GetStatusReport());
552 }
553  
554 public string GetStatusReport()
555 {
556 StringBuilder sb = new StringBuilder();
557 sb.AppendFormat("Status of XEngine instance for {0}\n", m_Scene.RegionInfo.RegionName);
558  
559 long scriptsLoaded, eventsQueued = 0, eventsProcessed = 0;
560  
561 lock (m_Scripts)
562 {
563 scriptsLoaded = m_Scripts.Count;
564  
565 foreach (IScriptInstance si in m_Scripts.Values)
566 {
567 eventsQueued += si.EventsQueued;
568 eventsProcessed += si.EventsProcessed;
569 }
570 }
571  
572 sb.AppendFormat("Scripts loaded : {0}\n", scriptsLoaded);
573 sb.AppendFormat("Unique scripts : {0}\n", m_uniqueScripts.Count);
574 sb.AppendFormat("Scripts waiting for load : {0}\n", m_CompileQueue.Count);
575 sb.AppendFormat("Max threads : {0}\n", m_ThreadPool.MaxThreads);
576 sb.AppendFormat("Min threads : {0}\n", m_ThreadPool.MinThreads);
577 sb.AppendFormat("Allocated threads : {0}\n", m_ThreadPool.ActiveThreads);
578 sb.AppendFormat("In use threads : {0}\n", m_ThreadPool.InUseThreads);
579 sb.AppendFormat("Work items waiting : {0}\n", m_ThreadPool.WaitingCallbacks);
580 // sb.AppendFormat("Assemblies loaded : {0}\n", m_Assemblies.Count);
581 sb.AppendFormat("Events queued : {0}\n", eventsQueued);
582 sb.AppendFormat("Events processed : {0}\n", eventsProcessed);
583  
584 SensorRepeat sr = AsyncCommandManager.GetSensorRepeatPlugin(this);
585 sb.AppendFormat("Sensors : {0}\n", sr != null ? sr.SensorsCount : 0);
586  
587 Dataserver ds = AsyncCommandManager.GetDataserverPlugin(this);
588 sb.AppendFormat("Dataserver requests : {0}\n", ds != null ? ds.DataserverRequestsCount : 0);
589  
590 Timer t = AsyncCommandManager.GetTimerPlugin(this);
591 sb.AppendFormat("Timers : {0}\n", t != null ? t.TimersCount : 0);
592  
593 Listener l = AsyncCommandManager.GetListenerPlugin(this);
594 sb.AppendFormat("Listeners : {0}\n", l != null ? l.ListenerCount : 0);
595  
596 return sb.ToString();
597 }
598  
599 public void HandleShowScripts(string module, string[] cmdparams)
600 {
601 if (!(MainConsole.Instance.ConsoleScene == null || MainConsole.Instance.ConsoleScene == m_Scene))
602 return;
603  
604 if (cmdparams.Length == 2)
605 {
606 lock (m_Scripts)
607 {
608 MainConsole.Instance.OutputFormat(
609 "Showing {0} scripts in {1}", m_Scripts.Count, m_Scene.RegionInfo.RegionName);
610 }
611 }
612  
613 HandleScriptsAction<long>(cmdparams, HandleShowScript, si => si.EventsProcessed);
614 }
615  
616 private void HandleShowScript(IScriptInstance instance)
617 {
618 SceneObjectPart sop = m_Scene.GetSceneObjectPart(instance.ObjectID);
619 string status;
620  
621 if (instance.ShuttingDown)
622 {
623 status = "shutting down";
624 }
625 else if (instance.Suspended)
626 {
627 status = "suspended";
628 }
629 else if (!instance.Running)
630 {
631 status = "stopped";
632 }
633 else
634 {
635 status = "running";
636 }
637  
638 StringBuilder sb = new StringBuilder();
639  
640 sb.AppendFormat("Script name : {0}\n", instance.ScriptName);
641 sb.AppendFormat("Status : {0}\n", status);
642 sb.AppendFormat("Queued events : {0}\n", instance.EventsQueued);
643 sb.AppendFormat("Processed events : {0}\n", instance.EventsProcessed);
644 sb.AppendFormat("Item UUID : {0}\n", instance.ItemID);
645 sb.AppendFormat("Asset UUID : {0}\n", instance.AssetID);
646 sb.AppendFormat("Containing part name: {0}\n", instance.PrimName);
647 sb.AppendFormat("Containing part UUID: {0}\n", instance.ObjectID);
648 sb.AppendFormat("Position : {0}\n", sop.AbsolutePosition);
649  
650 MainConsole.Instance.Output(sb.ToString());
651 }
652  
653 private void HandleSuspendScript(IScriptInstance instance)
654 {
655 if (!instance.Suspended)
656 {
657 instance.Suspend();
658  
659 SceneObjectPart sop = m_Scene.GetSceneObjectPart(instance.ObjectID);
660 MainConsole.Instance.OutputFormat(
661 "Suspended {0}.{1}, item UUID {2}, prim UUID {3} @ {4}",
662 instance.PrimName, instance.ScriptName, instance.ItemID, instance.ObjectID, sop.AbsolutePosition);
663 }
664 }
665  
666 private void HandleResumeScript(IScriptInstance instance)
667 {
668 if (instance.Suspended)
669 {
670 instance.Resume();
671  
672 SceneObjectPart sop = m_Scene.GetSceneObjectPart(instance.ObjectID);
673 MainConsole.Instance.OutputFormat(
674 "Resumed {0}.{1}, item UUID {2}, prim UUID {3} @ {4}",
675 instance.PrimName, instance.ScriptName, instance.ItemID, instance.ObjectID, sop.AbsolutePosition);
676 }
677 }
678  
679 private void HandleStartScript(IScriptInstance instance)
680 {
681 if (!instance.Running)
682 {
683 instance.Start();
684  
685 SceneObjectPart sop = m_Scene.GetSceneObjectPart(instance.ObjectID);
686 MainConsole.Instance.OutputFormat(
687 "Started {0}.{1}, item UUID {2}, prim UUID {3} @ {4}",
688 instance.PrimName, instance.ScriptName, instance.ItemID, instance.ObjectID, sop.AbsolutePosition);
689 }
690 }
691  
692 private void HandleStopScript(IScriptInstance instance)
693 {
694 if (instance.Running)
695 {
696 instance.Stop(0);
697  
698 SceneObjectPart sop = m_Scene.GetSceneObjectPart(instance.ObjectID);
699 MainConsole.Instance.OutputFormat(
700 "Stopped {0}.{1}, item UUID {2}, prim UUID {3} @ {4}",
701 instance.PrimName, instance.ScriptName, instance.ItemID, instance.ObjectID, sop.AbsolutePosition);
702 }
703 }
704  
705 public void RemoveRegion(Scene scene)
706 {
707 if (!m_Enabled)
708 return;
709  
710 lock (m_Scripts)
711 {
712 m_log.InfoFormat(
713 "[XEngine]: Shutting down {0} scripts in {1}", m_Scripts.Count, m_Scene.RegionInfo.RegionName);
714  
715 foreach (IScriptInstance instance in m_Scripts.Values)
716 {
717 // Force a final state save
718 //
719 if (m_Assemblies.ContainsKey(instance.AssetID))
720 {
721 string assembly = m_Assemblies[instance.AssetID];
722  
723 try
724 {
725 instance.SaveState(assembly);
726 }
727 catch (Exception e)
728 {
729 m_log.Error(
730 string.Format(
731 "[XEngine]: Failed final state save for script {0}.{1}, item UUID {2}, prim UUID {3} in {4}. Exception ",
732 instance.PrimName, instance.ScriptName, instance.ItemID, instance.ObjectID, World.Name)
733 , e);
734 }
735 }
736  
737 // Clear the event queue and abort the instance thread
738 //
739 instance.ClearQueue();
740 instance.Stop(0);
741  
742 // Release events, timer, etc
743 //
744 instance.DestroyScriptInstance();
745  
746 // Unload scripts and app domains.
747 // Must be done explicitly because they have infinite
748 // lifetime.
749 // However, don't bother to do this if the simulator is shutting
750 // down since it takes a long time with many scripts.
751 if (!m_SimulatorShuttingDown)
752 {
753 m_DomainScripts[instance.AppDomain].Remove(instance.ItemID);
754 if (m_DomainScripts[instance.AppDomain].Count == 0)
755 {
756 m_DomainScripts.Remove(instance.AppDomain);
757 UnloadAppDomain(instance.AppDomain);
758 }
759 }
760 }
761  
762 m_Scripts.Clear();
763 m_PrimObjects.Clear();
764 m_Assemblies.Clear();
765 m_DomainScripts.Clear();
766 }
767 lock (m_ScriptEngines)
768 {
769 m_ScriptEngines.Remove(this);
770 }
771 }
772  
773 public void RegionLoaded(Scene scene)
774 {
775 if (!m_Enabled)
776 return;
777  
778 m_EventManager = new EventManager(this);
779  
780 m_Compiler = new Compiler(this);
781  
782 m_Scene.EventManager.OnRemoveScript += OnRemoveScript;
783 m_Scene.EventManager.OnScriptReset += OnScriptReset;
784 m_Scene.EventManager.OnStartScript += OnStartScript;
785 m_Scene.EventManager.OnStopScript += OnStopScript;
786 m_Scene.EventManager.OnGetScriptRunning += OnGetScriptRunning;
787 m_Scene.EventManager.OnShutdown += OnShutdown;
788  
789 // If region ready has been triggered, then the region had no scripts to compile and completed its other
790 // work.
791 m_Scene.EventManager.OnRegionReadyStatusChange += s => { if (s.Ready) m_InitialStartup = false; };
792  
793 if (m_SleepTime > 0)
794 {
795 m_ThreadPool.QueueWorkItem(new WorkItemCallback(this.DoMaintenance),
796 new Object[]{ m_SleepTime });
797 }
798  
799 if (m_SaveTime > 0)
800 {
801 m_ThreadPool.QueueWorkItem(new WorkItemCallback(this.DoBackup),
802 new Object[] { m_SaveTime });
803 }
804 }
805  
806 public void StartProcessing()
807 {
808 m_ThreadPool.Start();
809 }
810  
811 public void Close()
812 {
813 if (!m_Enabled)
814 return;
815  
816 lock (m_ScriptEngines)
817 {
818 if (m_ScriptEngines.Contains(this))
819 m_ScriptEngines.Remove(this);
820 }
821 }
822  
823 public object DoBackup(object o)
824 {
825 Object[] p = (Object[])o;
826 int saveTime = (int)p[0];
827  
828 if (saveTime > 0)
829 System.Threading.Thread.Sleep(saveTime);
830  
831 // m_log.Debug("[XEngine] Backing up script states");
832  
833 List<IScriptInstance> instances = new List<IScriptInstance>();
834  
835 lock (m_Scripts)
836 {
837 foreach (IScriptInstance instance in m_Scripts.Values)
838 instances.Add(instance);
839 }
840  
841 foreach (IScriptInstance i in instances)
842 {
843 string assembly = String.Empty;
844  
845 lock (m_Scripts)
846 {
847 if (!m_Assemblies.ContainsKey(i.AssetID))
848 continue;
849 assembly = m_Assemblies[i.AssetID];
850 }
851  
852 try
853 {
854 i.SaveState(assembly);
855 }
856 catch (Exception e)
857 {
858 m_log.Error(
859 string.Format(
860 "[XEngine]: Failed to save state of script {0}.{1}, item UUID {2}, prim UUID {3} in {4}. Exception ",
861 i.PrimName, i.ScriptName, i.ItemID, i.ObjectID, World.Name)
862 , e);
863 }
864 }
865  
866 instances.Clear();
867  
868 if (saveTime > 0)
869 m_ThreadPool.QueueWorkItem(new WorkItemCallback(this.DoBackup),
870 new Object[] { saveTime });
871  
872 return 0;
873 }
874  
875 public void SaveAllState()
876 {
877 foreach (IScriptInstance inst in m_Scripts.Values)
878 {
879 if (inst.EventTime() > m_EventLimit)
880 {
881 inst.Stop(100);
882 if (!m_KillTimedOutScripts)
883 inst.Start();
884 }
885 }
886 }
887  
888 public object DoMaintenance(object p)
889 {
890 object[] parms = (object[])p;
891 int sleepTime = (int)parms[0];
892  
893 SaveAllState();
894  
895 System.Threading.Thread.Sleep(sleepTime);
896  
897 m_ThreadPool.QueueWorkItem(new WorkItemCallback(this.DoMaintenance),
898 new Object[]{ sleepTime });
899  
900 return 0;
901 }
902  
903 public Type ReplaceableInterface
904 {
905 get { return null; }
906 }
907  
908 public string Name
909 {
910 get { return "XEngine"; }
911 }
912  
913 public void OnRezScript(uint localID, UUID itemID, string script, int startParam, bool postOnRez, string engine, int stateSource)
914 {
915 // m_log.DebugFormat(
916 // "[XEngine]: OnRezScript event triggered for script {0}, startParam {1}, postOnRez {2}, engine {3}, stateSource {4}, script\n{5}",
917 // itemID, startParam, postOnRez, engine, stateSource, script);
918  
919 if (script.StartsWith("//MRM:"))
920 return;
921  
922 List<IScriptModule> engines = new List<IScriptModule>(m_Scene.RequestModuleInterfaces<IScriptModule>());
923  
924 List<string> names = new List<string>();
925 foreach (IScriptModule m in engines)
926 names.Add(m.ScriptEngineName);
927  
928 int lineEnd = script.IndexOf('\n');
929  
930 if (lineEnd > 1)
931 {
932 string firstline = script.Substring(0, lineEnd).Trim();
933  
934 int colon = firstline.IndexOf(':');
935 if (firstline.Length > 2 && firstline.Substring(0, 2) == "//" && colon != -1)
936 {
937 string engineName = firstline.Substring(2, colon - 2);
938  
939 if (names.Contains(engineName))
940 {
941 engine = engineName;
942 script = "//" + script.Substring(colon + 1);
943 }
944 else
945 {
946 if (engine == ScriptEngineName)
947 {
948 // If we are falling back on XEngine as the default engine, then only complain to the user
949 // if a script language has been explicitly set and it's one that we recognize or there are
950 // no non-whitespace characters after the colon.
951 //
952 // If the script is
953 // explicitly not allowed or the script is not in LSL then the user will be informed by a later compiler message.
954 //
955 // If the colon ends the line then we'll risk the false positive as this is more likely
956 // to signal a real scriptengine line where the user wants to use the default compile language.
957 //
958 // This avoids the overwhelming number of false positives where we're in this code because
959 // there's a colon in a comment in the first line of a script for entirely
960 // unrelated reasons (e.g. vim settings).
961 //
962 // TODO: A better fix would be to deprecate simple : detection and look for some less likely
963 // string to begin the comment (like #! in unix shell scripts).
964 bool warnRunningInXEngine = false;
965 string restOfFirstLine = firstline.Substring(colon + 1);
966  
967 // FIXME: These are hardcoded because they are currently hardcoded in Compiler.cs
968 if (restOfFirstLine.StartsWith("c#")
969 || restOfFirstLine.StartsWith("vb")
970 || restOfFirstLine.StartsWith("lsl")
971 || restOfFirstLine.Length == 0)
972 warnRunningInXEngine = true;
973  
974 if (warnRunningInXEngine)
975 {
976 SceneObjectPart part =
977 m_Scene.GetSceneObjectPart(
978 localID);
979  
980 TaskInventoryItem item =
981 part.Inventory.GetInventoryItem(itemID);
982  
983 ScenePresence presence =
984 m_Scene.GetScenePresence(
985 item.OwnerID);
986  
987 if (presence != null)
988 {
989 presence.ControllingClient.SendAgentAlertMessage(
990 "Selected engine unavailable. "+
991 "Running script on "+
992 ScriptEngineName,
993 false);
994 }
995 }
996 }
997 }
998 }
999 }
1000  
1001 if (engine != ScriptEngineName)
1002 return;
1003  
1004 // If we've seen this exact script text before, use that reference instead
1005 if (m_uniqueScripts.ContainsKey(script))
1006 script = m_uniqueScripts[script];
1007 else
1008 m_uniqueScripts[script] = script;
1009  
1010 Object[] parms = new Object[]{localID, itemID, script, startParam, postOnRez, (StateSource)stateSource};
1011  
1012 if (stateSource == (int)StateSource.ScriptedRez)
1013 {
1014 lock (m_CompileDict)
1015 {
1016 m_CompileDict[itemID] = 0;
1017 }
1018  
1019 DoOnRezScript(parms);
1020 }
1021 else
1022 {
1023 m_CompileQueue.Enqueue(parms);
1024 lock (m_CompileDict)
1025 {
1026 m_CompileDict[itemID] = 0;
1027 }
1028  
1029 // m_log.DebugFormat("[XEngine]: Added script {0} to compile queue", itemID);
1030  
1031 if (m_CurrentCompile == null)
1032 {
1033 // NOTE: Although we use a lockless queue, the lock here
1034 // is required. It ensures that there are never two
1035 // compile threads running, which, due to a race
1036 // conndition, might otherwise happen
1037 //
1038 lock (m_CompileQueue)
1039 {
1040 if (m_CurrentCompile == null)
1041 m_CurrentCompile = m_ThreadPool.QueueWorkItem(DoOnRezScriptQueue, null);
1042 }
1043 }
1044 }
1045 }
1046  
1047 public Object DoOnRezScriptQueue(Object dummy)
1048 {
1049 if (m_InitialStartup)
1050 {
1051 // This delay exists to stop mono problems where script compilation and startup would stop the sim
1052 // working properly for the session.
1053 System.Threading.Thread.Sleep(m_StartDelay);
1054  
1055 m_log.InfoFormat("[XEngine]: Performing initial script startup on {0}", m_Scene.Name);
1056 }
1057  
1058 object[] o;
1059  
1060 int scriptsStarted = 0;
1061  
1062 while (m_CompileQueue.Dequeue(out o))
1063 {
1064 if (DoOnRezScript(o))
1065 {
1066 scriptsStarted++;
1067  
1068 if (m_InitialStartup)
1069 if (scriptsStarted % 50 == 0)
1070 m_log.InfoFormat(
1071 "[XEngine]: Started {0} scripts in {1}", scriptsStarted, m_Scene.Name);
1072 }
1073 }
1074  
1075 if (m_InitialStartup)
1076 m_log.InfoFormat(
1077 "[XEngine]: Completed starting {0} scripts on {1}", scriptsStarted, m_Scene.Name);
1078  
1079 // NOTE: Despite having a lockless queue, this lock is required
1080 // to make sure there is never no compile thread while there
1081 // are still scripts to compile. This could otherwise happen
1082 // due to a race condition
1083 //
1084 lock (m_CompileQueue)
1085 m_CurrentCompile = null;
1086  
1087 m_Scene.EventManager.TriggerEmptyScriptCompileQueue(m_ScriptFailCount,
1088 m_ScriptErrorMessage);
1089  
1090 m_ScriptFailCount = 0;
1091 m_InitialStartup = false;
1092  
1093 return null;
1094 }
1095  
1096 private bool DoOnRezScript(object[] parms)
1097 {
1098 Object[] p = parms;
1099 uint localID = (uint)p[0];
1100 UUID itemID = (UUID)p[1];
1101 string script =(string)p[2];
1102 int startParam = (int)p[3];
1103 bool postOnRez = (bool)p[4];
1104 StateSource stateSource = (StateSource)p[5];
1105  
1106 // m_log.DebugFormat("[XEngine]: DoOnRezScript called for script {0}", itemID);
1107  
1108 lock (m_CompileDict)
1109 {
1110 if (!m_CompileDict.ContainsKey(itemID))
1111 return false;
1112 m_CompileDict.Remove(itemID);
1113 }
1114  
1115 // Get the asset ID of the script, so we can check if we
1116 // already have it.
1117  
1118 // We must look for the part outside the m_Scripts lock because GetSceneObjectPart later triggers the
1119 // m_parts lock on SOG. At the same time, a scene object that is being deleted will take the m_parts lock
1120 // and then later on try to take the m_scripts lock in this class when it calls OnRemoveScript()
1121 SceneObjectPart part = m_Scene.GetSceneObjectPart(localID);
1122 if (part == null)
1123 {
1124 m_log.ErrorFormat("[Script]: SceneObjectPart with localID {0} unavailable. Script NOT started.", localID);
1125 m_ScriptErrorMessage += "SceneObjectPart unavailable. Script NOT started.\n";
1126 m_ScriptFailCount++;
1127 return false;
1128 }
1129  
1130 TaskInventoryItem item = part.Inventory.GetInventoryItem(itemID);
1131 if (item == null)
1132 {
1133 m_ScriptErrorMessage += "Can't find script inventory item.\n";
1134 m_ScriptFailCount++;
1135 return false;
1136 }
1137  
1138 m_log.DebugFormat(
1139 "[XEngine]: Loading script {0}.{1}, item UUID {2}, prim UUID {3} @ {4}.{5}",
1140 part.ParentGroup.RootPart.Name, item.Name, itemID, part.UUID,
1141 part.ParentGroup.RootPart.AbsolutePosition, part.ParentGroup.Scene.RegionInfo.RegionName);
1142  
1143 UUID assetID = item.AssetID;
1144  
1145 ScenePresence presence = m_Scene.GetScenePresence(item.OwnerID);
1146  
1147 string assemblyPath = "";
1148  
1149 Culture.SetCurrentCulture();
1150  
1151 Dictionary<KeyValuePair<int, int>, KeyValuePair<int, int>> linemap;
1152  
1153 lock (m_ScriptErrors)
1154 {
1155 try
1156 {
1157 lock (m_AddingAssemblies)
1158 {
1159 m_Compiler.PerformScriptCompile(script, assetID.ToString(), item.OwnerID, out assemblyPath, out linemap);
1160  
1161 if (!m_AddingAssemblies.ContainsKey(assemblyPath)) {
1162 m_AddingAssemblies[assemblyPath] = 1;
1163 } else {
1164 m_AddingAssemblies[assemblyPath]++;
1165 }
1166 }
1167  
1168 string[] warnings = m_Compiler.GetWarnings();
1169  
1170 if (warnings != null && warnings.Length != 0)
1171 {
1172 foreach (string warning in warnings)
1173 {
1174 if (!m_ScriptErrors.ContainsKey(itemID))
1175 m_ScriptErrors[itemID] = new ArrayList();
1176  
1177 m_ScriptErrors[itemID].Add(warning);
1178 // try
1179 // {
1180 // // DISPLAY WARNING INWORLD
1181 // string text = "Warning:\n" + warning;
1182 // if (text.Length > 1000)
1183 // text = text.Substring(0, 1000);
1184 // if (!ShowScriptSaveResponse(item.OwnerID,
1185 // assetID, text, true))
1186 // {
1187 // if (presence != null && (!postOnRez))
1188 // presence.ControllingClient.SendAgentAlertMessage("Script saved with warnings, check debug window!", false);
1189 //
1190 // World.SimChat(Utils.StringToBytes(text),
1191 // ChatTypeEnum.DebugChannel, 2147483647,
1192 // part.AbsolutePosition,
1193 // part.Name, part.UUID, false);
1194 // }
1195 // }
1196 // catch (Exception e2) // LEGIT: User Scripting
1197 // {
1198 // m_log.Error("[XEngine]: " +
1199 // "Error displaying warning in-world: " +
1200 // e2.ToString());
1201 // m_log.Error("[XEngine]: " +
1202 // "Warning:\r\n" +
1203 // warning);
1204 // }
1205 }
1206 }
1207 }
1208 catch (Exception e)
1209 {
1210 // m_log.ErrorFormat(
1211 // "[XEngine]: Exception when rezzing script with item ID {0}, {1}{2}",
1212 // itemID, e.Message, e.StackTrace);
1213  
1214 // try
1215 // {
1216 if (!m_ScriptErrors.ContainsKey(itemID))
1217 m_ScriptErrors[itemID] = new ArrayList();
1218 // DISPLAY ERROR INWORLD
1219 // m_ScriptErrorMessage += "Failed to compile script in object: '" + part.ParentGroup.RootPart.Name + "' Script name: '" + item.Name + "' Error message: " + e.Message.ToString();
1220 //
1221 m_ScriptFailCount++;
1222 m_ScriptErrors[itemID].Add(e.Message.ToString());
1223 // string text = "Error compiling script '" + item.Name + "':\n" + e.Message.ToString();
1224 // if (text.Length > 1000)
1225 // text = text.Substring(0, 1000);
1226 // if (!ShowScriptSaveResponse(item.OwnerID,
1227 // assetID, text, false))
1228 // {
1229 // if (presence != null && (!postOnRez))
1230 // presence.ControllingClient.SendAgentAlertMessage("Script saved with errors, check debug window!", false);
1231 // World.SimChat(Utils.StringToBytes(text),
1232 // ChatTypeEnum.DebugChannel, 2147483647,
1233 // part.AbsolutePosition,
1234 // part.Name, part.UUID, false);
1235 // }
1236 // }
1237 // catch (Exception e2) // LEGIT: User Scripting
1238 // {
1239 // m_log.Error("[XEngine]: "+
1240 // "Error displaying error in-world: " +
1241 // e2.ToString());
1242 // m_log.Error("[XEngine]: " +
1243 // "Errormessage: Error compiling script:\r\n" +
1244 // e.Message.ToString());
1245 // }
1246  
1247 return false;
1248 }
1249 }
1250  
1251 ScriptInstance instance = null;
1252 lock (m_Scripts)
1253 {
1254 // Create the object record
1255 if ((!m_Scripts.ContainsKey(itemID)) ||
1256 (m_Scripts[itemID].AssetID != assetID))
1257 {
1258 UUID appDomain = assetID;
1259  
1260 if (part.ParentGroup.IsAttachment)
1261 appDomain = part.ParentGroup.RootPart.UUID;
1262  
1263 if (!m_AppDomains.ContainsKey(appDomain))
1264 {
1265 try
1266 {
1267 AppDomainSetup appSetup = new AppDomainSetup();
1268 appSetup.PrivateBinPath = Path.Combine(
1269 m_ScriptEnginesPath,
1270 m_Scene.RegionInfo.RegionID.ToString());
1271  
1272 Evidence baseEvidence = AppDomain.CurrentDomain.Evidence;
1273 Evidence evidence = new Evidence(baseEvidence);
1274  
1275 AppDomain sandbox;
1276 if (m_AppDomainLoading)
1277 {
1278 sandbox = AppDomain.CreateDomain(
1279 m_Scene.RegionInfo.RegionID.ToString(),
1280 evidence, appSetup);
1281 sandbox.AssemblyResolve +=
1282 new ResolveEventHandler(
1283 AssemblyResolver.OnAssemblyResolve);
1284 }
1285 else
1286 {
1287 sandbox = AppDomain.CurrentDomain;
1288 }
1289  
1290 //PolicyLevel sandboxPolicy = PolicyLevel.CreateAppDomainLevel();
1291 //AllMembershipCondition sandboxMembershipCondition = new AllMembershipCondition();
1292 //PermissionSet sandboxPermissionSet = sandboxPolicy.GetNamedPermissionSet("Internet");
1293 //PolicyStatement sandboxPolicyStatement = new PolicyStatement(sandboxPermissionSet);
1294 //CodeGroup sandboxCodeGroup = new UnionCodeGroup(sandboxMembershipCondition, sandboxPolicyStatement);
1295 //sandboxPolicy.RootCodeGroup = sandboxCodeGroup;
1296 //sandbox.SetAppDomainPolicy(sandboxPolicy);
1297  
1298 m_AppDomains[appDomain] = sandbox;
1299  
1300 m_DomainScripts[appDomain] = new List<UUID>();
1301 }
1302 catch (Exception e)
1303 {
1304 m_log.ErrorFormat("[XEngine] Exception creating app domain:\n {0}", e.ToString());
1305 m_ScriptErrorMessage += "Exception creating app domain:\n";
1306 m_ScriptFailCount++;
1307 lock (m_AddingAssemblies)
1308 {
1309 m_AddingAssemblies[assemblyPath]--;
1310 }
1311 return false;
1312 }
1313 }
1314 m_DomainScripts[appDomain].Add(itemID);
1315  
1316 Assembly scriptAssembly = m_AppDomains[appDomain].Load(Path.GetFileNameWithoutExtension(assemblyPath));
1317 bool recompile = false;
1318  
1319 if (m_coopTermination)
1320 {
1321 Type scriptType = scriptAssembly.GetType("SecondLife.XEngineScript");
1322  
1323 if (scriptType == null)
1324 recompile = true;
1325 }
1326 else
1327 {
1328 Type scriptType = scriptAssembly.GetType("SecondLife.Script");
1329  
1330 if (scriptType == null)
1331 recompile = true;
1332 }
1333  
1334 // If we are loading all scripts into the same AppDomain, then we can't reload the DLL in this
1335 // simulator session if the script halt strategy has been changed. Instead, we'll continue with
1336 // the existing DLL and the new one will be used in the next simulator session.
1337 if (recompile)
1338 m_Compiler.PerformScriptCompile(script, assetID.ToString(), item.OwnerID, true, out assemblyPath, out linemap);
1339  
1340 instance = new ScriptInstance(this, part,
1341 item,
1342 startParam, postOnRez,
1343 m_MaxScriptQueue);
1344  
1345 if (!instance.Load(m_AppDomains[appDomain], scriptAssembly, stateSource))
1346 return false;
1347  
1348 // if (DebugLevel >= 1)
1349 // m_log.DebugFormat(
1350 // "[XEngine] Loaded script {0}.{1}, item UUID {2}, prim UUID {3} @ {4}.{5}",
1351 // part.ParentGroup.RootPart.Name, item.Name, itemID, part.UUID,
1352 // part.ParentGroup.RootPart.AbsolutePosition, part.ParentGroup.Scene.RegionInfo.RegionName);
1353  
1354 if (presence != null)
1355 {
1356 ShowScriptSaveResponse(item.OwnerID,
1357 assetID, "Compile successful", true);
1358 }
1359  
1360 instance.AppDomain = appDomain;
1361 instance.LineMap = linemap;
1362  
1363 m_Scripts[itemID] = instance;
1364 }
1365 }
1366  
1367 lock (m_PrimObjects)
1368 {
1369 if (!m_PrimObjects.ContainsKey(localID))
1370 m_PrimObjects[localID] = new List<UUID>();
1371  
1372 if (!m_PrimObjects[localID].Contains(itemID))
1373 m_PrimObjects[localID].Add(itemID);
1374 }
1375  
1376 if (!m_Assemblies.ContainsKey(assetID))
1377 m_Assemblies[assetID] = assemblyPath;
1378  
1379 lock (m_AddingAssemblies)
1380 {
1381 m_AddingAssemblies[assemblyPath]--;
1382 }
1383  
1384 if (instance != null)
1385 instance.Init();
1386  
1387 bool runIt;
1388 if (m_runFlags.TryGetValue(itemID, out runIt))
1389 {
1390 if (!runIt)
1391 StopScript(itemID);
1392 m_runFlags.Remove(itemID);
1393 }
1394  
1395 return true;
1396 }
1397  
1398 public void OnRemoveScript(uint localID, UUID itemID)
1399 {
1400 // If it's not yet been compiled, make sure we don't try
1401 lock (m_CompileDict)
1402 {
1403 if (m_CompileDict.ContainsKey(itemID))
1404 m_CompileDict.Remove(itemID);
1405 }
1406  
1407 IScriptInstance instance = null;
1408  
1409 lock (m_Scripts)
1410 {
1411 // Do we even have it?
1412 if (!m_Scripts.ContainsKey(itemID))
1413 return;
1414  
1415 instance = m_Scripts[itemID];
1416 m_Scripts.Remove(itemID);
1417 }
1418  
1419 instance.ClearQueue();
1420  
1421 instance.Stop(m_WaitForEventCompletionOnScriptStop);
1422  
1423 // bool objectRemoved = false;
1424  
1425 lock (m_PrimObjects)
1426 {
1427 // Remove the script from it's prim
1428 if (m_PrimObjects.ContainsKey(localID))
1429 {
1430 // Remove inventory item record
1431 if (m_PrimObjects[localID].Contains(itemID))
1432 m_PrimObjects[localID].Remove(itemID);
1433  
1434 // If there are no more scripts, remove prim
1435 if (m_PrimObjects[localID].Count == 0)
1436 {
1437 m_PrimObjects.Remove(localID);
1438 // objectRemoved = true;
1439 }
1440 }
1441 }
1442  
1443 instance.RemoveState();
1444 instance.DestroyScriptInstance();
1445  
1446 m_DomainScripts[instance.AppDomain].Remove(instance.ItemID);
1447 if (m_DomainScripts[instance.AppDomain].Count == 0)
1448 {
1449 m_DomainScripts.Remove(instance.AppDomain);
1450 UnloadAppDomain(instance.AppDomain);
1451 }
1452  
1453 ObjectRemoved handlerObjectRemoved = OnObjectRemoved;
1454 if (handlerObjectRemoved != null)
1455 handlerObjectRemoved(instance.ObjectID);
1456  
1457 ScriptRemoved handlerScriptRemoved = OnScriptRemoved;
1458 if (handlerScriptRemoved != null)
1459 handlerScriptRemoved(itemID);
1460 }
1461  
1462 public void OnScriptReset(uint localID, UUID itemID)
1463 {
1464 ResetScript(itemID);
1465 }
1466  
1467 public void OnStartScript(uint localID, UUID itemID)
1468 {
1469 StartScript(itemID);
1470 }
1471  
1472 public void OnStopScript(uint localID, UUID itemID)
1473 {
1474 StopScript(itemID);
1475 }
1476  
1477 private void CleanAssemblies()
1478 {
1479 List<UUID> assetIDList = new List<UUID>(m_Assemblies.Keys);
1480  
1481 foreach (IScriptInstance i in m_Scripts.Values)
1482 {
1483 if (assetIDList.Contains(i.AssetID))
1484 assetIDList.Remove(i.AssetID);
1485 }
1486  
1487 lock (m_AddingAssemblies)
1488 {
1489 foreach (UUID assetID in assetIDList)
1490 {
1491 // Do not remove assembly files if another instance of the script
1492 // is currently initialising
1493 if (!m_AddingAssemblies.ContainsKey(m_Assemblies[assetID])
1494 || m_AddingAssemblies[m_Assemblies[assetID]] == 0)
1495 {
1496 // m_log.DebugFormat("[XEngine] Removing unreferenced assembly {0}", m_Assemblies[assetID]);
1497 try
1498 {
1499 if (File.Exists(m_Assemblies[assetID]))
1500 File.Delete(m_Assemblies[assetID]);
1501  
1502 if (File.Exists(m_Assemblies[assetID]+".text"))
1503 File.Delete(m_Assemblies[assetID]+".text");
1504  
1505 if (File.Exists(m_Assemblies[assetID]+".mdb"))
1506 File.Delete(m_Assemblies[assetID]+".mdb");
1507  
1508 if (File.Exists(m_Assemblies[assetID]+".map"))
1509 File.Delete(m_Assemblies[assetID]+".map");
1510 }
1511 catch (Exception)
1512 {
1513 }
1514 m_Assemblies.Remove(assetID);
1515 }
1516 }
1517 }
1518 }
1519  
1520 private void UnloadAppDomain(UUID id)
1521 {
1522 if (m_AppDomains.ContainsKey(id))
1523 {
1524 AppDomain domain = m_AppDomains[id];
1525 m_AppDomains.Remove(id);
1526  
1527 if (domain != AppDomain.CurrentDomain)
1528 AppDomain.Unload(domain);
1529 domain = null;
1530 // m_log.DebugFormat("[XEngine] Unloaded app domain {0}", id.ToString());
1531 }
1532 }
1533  
1534 //
1535 // Start processing
1536 //
1537 private void SetupEngine(int minThreads, int maxThreads,
1538 int idleTimeout, ThreadPriority threadPriority,
1539 int maxScriptQueue, int stackSize)
1540 {
1541 m_MaxScriptQueue = maxScriptQueue;
1542  
1543 STPStartInfo startInfo = new STPStartInfo();
1544 startInfo.ThreadPoolName = "XEngine";
1545 startInfo.IdleTimeout = idleTimeout * 1000; // convert to seconds as stated in .ini
1546 startInfo.MaxWorkerThreads = maxThreads;
1547 startInfo.MinWorkerThreads = minThreads;
1548 startInfo.ThreadPriority = threadPriority;;
1549 startInfo.MaxStackSize = stackSize;
1550 startInfo.StartSuspended = true;
1551  
1552 m_ThreadPool = new SmartThreadPool(startInfo);
1553 }
1554  
1555 //
1556 // Used by script instances to queue event handler jobs
1557 //
1558 public IScriptWorkItem QueueEventHandler(object parms)
1559 {
1560 return new XWorkItem(m_ThreadPool.QueueWorkItem(
1561 new WorkItemCallback(this.ProcessEventHandler),
1562 parms));
1563 }
1564  
1565 /// <summary>
1566 /// Process a previously posted script event.
1567 /// </summary>
1568 /// <param name="parms"></param>
1569 /// <returns></returns>
1570 private object ProcessEventHandler(object parms)
1571 {
1572 Culture.SetCurrentCulture();
1573  
1574 IScriptInstance instance = (ScriptInstance) parms;
1575  
1576 //m_log.DebugFormat("[XEngine]: Processing event for {0}", instance);
1577  
1578 return instance.EventProcessor();
1579 }
1580  
1581 /// <summary>
1582 /// Post event to an entire prim
1583 /// </summary>
1584 /// <param name="localID"></param>
1585 /// <param name="p"></param>
1586 /// <returns></returns>
1587 public bool PostObjectEvent(uint localID, EventParams p)
1588 {
1589 bool result = false;
1590 List<UUID> uuids = null;
1591  
1592 lock (m_PrimObjects)
1593 {
1594 if (!m_PrimObjects.ContainsKey(localID))
1595 return false;
1596  
1597 uuids = m_PrimObjects[localID];
1598  
1599 foreach (UUID itemID in uuids)
1600 {
1601 IScriptInstance instance = null;
1602 try
1603 {
1604 if (m_Scripts.ContainsKey(itemID))
1605 instance = m_Scripts[itemID];
1606 }
1607 catch { /* ignore race conditions */ }
1608  
1609 if (instance != null)
1610 {
1611 instance.PostEvent(p);
1612 result = true;
1613 }
1614 }
1615 }
1616  
1617 return result;
1618 }
1619  
1620 /// <summary>
1621 /// Post an event to a single script
1622 /// </summary>
1623 /// <param name="itemID"></param>
1624 /// <param name="p"></param>
1625 /// <returns></returns>
1626 public bool PostScriptEvent(UUID itemID, EventParams p)
1627 {
1628 if (m_Scripts.ContainsKey(itemID))
1629 {
1630 IScriptInstance instance = m_Scripts[itemID];
1631 if (instance != null)
1632 instance.PostEvent(p);
1633 return true;
1634 }
1635 return false;
1636 }
1637  
1638 public bool PostScriptEvent(UUID itemID, string name, Object[] p)
1639 {
1640 Object[] lsl_p = new Object[p.Length];
1641 for (int i = 0; i < p.Length ; i++)
1642 {
1643 if (p[i] is int)
1644 lsl_p[i] = new LSL_Types.LSLInteger((int)p[i]);
1645 else if (p[i] is string)
1646 lsl_p[i] = new LSL_Types.LSLString((string)p[i]);
1647 else if (p[i] is Vector3)
1648 lsl_p[i] = new LSL_Types.Vector3((Vector3)p[i]);
1649 else if (p[i] is Quaternion)
1650 lsl_p[i] = new LSL_Types.Quaternion((Quaternion)p[i]);
1651 else if (p[i] is float)
1652 lsl_p[i] = new LSL_Types.LSLFloat((float)p[i]);
1653 else
1654 lsl_p[i] = p[i];
1655 }
1656  
1657 return PostScriptEvent(itemID, new EventParams(name, lsl_p, new DetectParams[0]));
1658 }
1659  
1660 public bool PostObjectEvent(UUID itemID, string name, Object[] p)
1661 {
1662 SceneObjectPart part = m_Scene.GetSceneObjectPart(itemID);
1663 if (part == null)
1664 return false;
1665  
1666 Object[] lsl_p = new Object[p.Length];
1667 for (int i = 0; i < p.Length ; i++)
1668 {
1669 if (p[i] is int)
1670 lsl_p[i] = new LSL_Types.LSLInteger((int)p[i]);
1671 else if (p[i] is string)
1672 lsl_p[i] = new LSL_Types.LSLString((string)p[i]);
1673 else if (p[i] is Vector3)
1674 lsl_p[i] = new LSL_Types.Vector3((Vector3)p[i]);
1675 else if (p[i] is Quaternion)
1676 lsl_p[i] = new LSL_Types.Quaternion((Quaternion)p[i]);
1677 else if (p[i] is float)
1678 lsl_p[i] = new LSL_Types.LSLFloat((float)p[i]);
1679 else
1680 lsl_p[i] = p[i];
1681 }
1682  
1683 return PostObjectEvent(part.LocalId, new EventParams(name, lsl_p, new DetectParams[0]));
1684 }
1685  
1686 public Assembly OnAssemblyResolve(object sender,
1687 ResolveEventArgs args)
1688 {
1689 if (!(sender is System.AppDomain))
1690 return null;
1691  
1692 string[] pathList = new string[] {"bin", m_ScriptEnginesPath,
1693 Path.Combine(m_ScriptEnginesPath,
1694 m_Scene.RegionInfo.RegionID.ToString())};
1695  
1696 string assemblyName = args.Name;
1697 if (assemblyName.IndexOf(",") != -1)
1698 assemblyName = args.Name.Substring(0, args.Name.IndexOf(","));
1699  
1700 foreach (string s in pathList)
1701 {
1702 string path = Path.Combine(Directory.GetCurrentDirectory(),
1703 Path.Combine(s, assemblyName))+".dll";
1704  
1705 // Console.WriteLine("[XEngine]: Trying to resolve {0}", path);
1706  
1707 if (File.Exists(path))
1708 return Assembly.LoadFrom(path);
1709 }
1710  
1711 return null;
1712 }
1713  
1714 private IScriptInstance GetInstance(UUID itemID)
1715 {
1716 IScriptInstance instance;
1717 lock (m_Scripts)
1718 {
1719 if (!m_Scripts.ContainsKey(itemID))
1720 return null;
1721 instance = m_Scripts[itemID];
1722 }
1723 return instance;
1724 }
1725  
1726 public void SetScriptState(UUID itemID, bool running)
1727 {
1728 IScriptInstance instance = GetInstance(itemID);
1729 if (instance != null)
1730 {
1731 if (running)
1732 instance.Start();
1733 else
1734 instance.Stop(100);
1735 }
1736 }
1737  
1738 public bool GetScriptState(UUID itemID)
1739 {
1740 IScriptInstance instance = GetInstance(itemID);
1741 return instance != null && instance.Running;
1742 }
1743  
1744 public void ApiResetScript(UUID itemID)
1745 {
1746 IScriptInstance instance = GetInstance(itemID);
1747 if (instance != null)
1748 instance.ApiResetScript();
1749 }
1750  
1751 public void ResetScript(UUID itemID)
1752 {
1753 IScriptInstance instance = GetInstance(itemID);
1754 if (instance != null)
1755 instance.ResetScript(m_WaitForEventCompletionOnScriptStop);
1756 }
1757  
1758 public void StartScript(UUID itemID)
1759 {
1760 IScriptInstance instance = GetInstance(itemID);
1761 if (instance != null)
1762 instance.Start();
1763 else
1764 m_runFlags.AddOrUpdate(itemID, true, 240);
1765 }
1766  
1767 public void StopScript(UUID itemID)
1768 {
1769 IScriptInstance instance = GetInstance(itemID);
1770  
1771 if (instance != null)
1772 {
1773 instance.Stop(m_WaitForEventCompletionOnScriptStop);
1774 }
1775 else
1776 {
1777 // m_log.DebugFormat("[XENGINE]: Could not find script with ID {0} to stop in {1}", itemID, World.Name);
1778 m_runFlags.AddOrUpdate(itemID, false, 240);
1779 }
1780 }
1781  
1782 public DetectParams GetDetectParams(UUID itemID, int idx)
1783 {
1784 IScriptInstance instance = GetInstance(itemID);
1785 return instance != null ? instance.GetDetectParams(idx) : null;
1786 }
1787  
1788 public void SetMinEventDelay(UUID itemID, double delay)
1789 {
1790 IScriptInstance instance = GetInstance(itemID);
1791 if (instance != null)
1792 instance.MinEventDelay = delay;
1793 }
1794  
1795 public UUID GetDetectID(UUID itemID, int idx)
1796 {
1797 IScriptInstance instance = GetInstance(itemID);
1798 return instance != null ? instance.GetDetectID(idx) : UUID.Zero;
1799 }
1800  
1801 public void SetState(UUID itemID, string newState)
1802 {
1803 IScriptInstance instance = GetInstance(itemID);
1804 if (instance == null)
1805 return;
1806 instance.SetState(newState);
1807 }
1808  
1809 public int GetStartParameter(UUID itemID)
1810 {
1811 IScriptInstance instance = GetInstance(itemID);
1812 return instance == null ? 0 : instance.StartParam;
1813 }
1814  
1815 public void OnShutdown()
1816 {
1817 m_SimulatorShuttingDown = true;
1818  
1819 List<IScriptInstance> instances = new List<IScriptInstance>();
1820  
1821 lock (m_Scripts)
1822 {
1823 foreach (IScriptInstance instance in m_Scripts.Values)
1824 instances.Add(instance);
1825 }
1826  
1827 foreach (IScriptInstance i in instances)
1828 {
1829 // Stop the script, even forcibly if needed. Then flag
1830 // it as shutting down and restore the previous run state
1831 // for serialization, so the scripts don't come back
1832 // dead after region restart
1833 //
1834 bool prevRunning = i.Running;
1835 i.Stop(50);
1836 i.ShuttingDown = true;
1837 i.Running = prevRunning;
1838 }
1839  
1840 DoBackup(new Object[] {0});
1841 }
1842  
1843 public IScriptApi GetApi(UUID itemID, string name)
1844 {
1845 IScriptInstance instance = GetInstance(itemID);
1846 return instance == null ? null : instance.GetApi(name);
1847 }
1848  
1849 public void OnGetScriptRunning(IClientAPI controllingClient, UUID objectID, UUID itemID)
1850 {
1851 IScriptInstance instance = GetInstance(itemID);
1852 if (instance == null)
1853 return;
1854 IEventQueue eq = World.RequestModuleInterface<IEventQueue>();
1855 if (eq == null)
1856 {
1857 controllingClient.SendScriptRunningReply(objectID, itemID,
1858 GetScriptState(itemID));
1859 }
1860 else
1861 {
1862 eq.Enqueue(eq.ScriptRunningEvent(objectID, itemID, GetScriptState(itemID), true),
1863 controllingClient.AgentId);
1864 }
1865 }
1866  
1867 public string GetXMLState(UUID itemID)
1868 {
1869 // m_log.DebugFormat("[XEngine]: Getting XML state for script instance {0}", itemID);
1870  
1871 IScriptInstance instance = GetInstance(itemID);
1872 if (instance == null)
1873 {
1874 // m_log.DebugFormat("[XEngine]: Found no script instance for {0}, returning empty string", itemID);
1875 return "";
1876 }
1877  
1878 string xml = instance.GetXMLState();
1879  
1880 XmlDocument sdoc = new XmlDocument();
1881 bool loadedState = true;
1882 try
1883 {
1884 sdoc.LoadXml(xml);
1885 }
1886 catch (System.Xml.XmlException)
1887 {
1888 loadedState = false;
1889 }
1890  
1891 XmlNodeList rootL = null;
1892 XmlNode rootNode = null;
1893 if (loadedState)
1894 {
1895 rootL = sdoc.GetElementsByTagName("ScriptState");
1896 rootNode = rootL[0];
1897 }
1898  
1899 // Create <State UUID="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx">
1900 XmlDocument doc = new XmlDocument();
1901 XmlElement stateData = doc.CreateElement("", "State", "");
1902 XmlAttribute stateID = doc.CreateAttribute("", "UUID", "");
1903 stateID.Value = itemID.ToString();
1904 stateData.Attributes.Append(stateID);
1905 XmlAttribute assetID = doc.CreateAttribute("", "Asset", "");
1906 assetID.Value = instance.AssetID.ToString();
1907 stateData.Attributes.Append(assetID);
1908 XmlAttribute engineName = doc.CreateAttribute("", "Engine", "");
1909 engineName.Value = ScriptEngineName;
1910 stateData.Attributes.Append(engineName);
1911 doc.AppendChild(stateData);
1912  
1913 XmlNode xmlstate = null;
1914  
1915 // Add <ScriptState>...</ScriptState>
1916 if (loadedState)
1917 {
1918 xmlstate = doc.ImportNode(rootNode, true);
1919 }
1920 else
1921 {
1922 xmlstate = doc.CreateElement("", "ScriptState", "");
1923 }
1924  
1925 stateData.AppendChild(xmlstate);
1926  
1927 string assemName = instance.GetAssemblyName();
1928  
1929 string fn = Path.GetFileName(assemName);
1930  
1931 string assem = String.Empty;
1932  
1933 if (File.Exists(assemName + ".text"))
1934 {
1935 FileInfo tfi = new FileInfo(assemName + ".text");
1936  
1937 if (tfi != null)
1938 {
1939 Byte[] tdata = new Byte[tfi.Length];
1940  
1941 try
1942 {
1943 using (FileStream tfs = File.Open(assemName + ".text",
1944 FileMode.Open, FileAccess.Read))
1945 {
1946 tfs.Read(tdata, 0, tdata.Length);
1947 }
1948  
1949 assem = Encoding.ASCII.GetString(tdata);
1950 }
1951 catch (Exception e)
1952 {
1953 m_log.ErrorFormat(
1954 "[XEngine]: Unable to open script textfile {0}{1}, reason: {2}",
1955 assemName, ".text", e.Message);
1956 }
1957 }
1958 }
1959 else
1960 {
1961 FileInfo fi = new FileInfo(assemName);
1962  
1963 if (fi != null)
1964 {
1965 Byte[] data = new Byte[fi.Length];
1966  
1967 try
1968 {
1969 using (FileStream fs = File.Open(assemName, FileMode.Open, FileAccess.Read))
1970 {
1971 fs.Read(data, 0, data.Length);
1972 }
1973  
1974 assem = System.Convert.ToBase64String(data);
1975 }
1976 catch (Exception e)
1977 {
1978 m_log.ErrorFormat(
1979 "[XEngine]: Unable to open script assembly {0}, reason: {1}", assemName, e.Message);
1980 }
1981 }
1982 }
1983  
1984 string map = String.Empty;
1985  
1986 if (File.Exists(fn + ".map"))
1987 {
1988 using (FileStream mfs = File.Open(fn + ".map", FileMode.Open, FileAccess.Read))
1989 {
1990 using (StreamReader msr = new StreamReader(mfs))
1991 {
1992 map = msr.ReadToEnd();
1993 }
1994 }
1995 }
1996  
1997 XmlElement assemblyData = doc.CreateElement("", "Assembly", "");
1998 XmlAttribute assemblyName = doc.CreateAttribute("", "Filename", "");
1999  
2000 assemblyName.Value = fn;
2001 assemblyData.Attributes.Append(assemblyName);
2002  
2003 assemblyData.InnerText = assem;
2004  
2005 stateData.AppendChild(assemblyData);
2006  
2007 XmlElement mapData = doc.CreateElement("", "LineMap", "");
2008 XmlAttribute mapName = doc.CreateAttribute("", "Filename", "");
2009  
2010 mapName.Value = fn + ".map";
2011 mapData.Attributes.Append(mapName);
2012  
2013 mapData.InnerText = map;
2014  
2015 stateData.AppendChild(mapData);
2016  
2017 // m_log.DebugFormat("[XEngine]: Got XML state for {0}", itemID);
2018  
2019 return doc.InnerXml;
2020 }
2021  
2022 private bool ShowScriptSaveResponse(UUID ownerID, UUID assetID, string text, bool compiled)
2023 {
2024 return false;
2025 }
2026  
2027 public bool SetXMLState(UUID itemID, string xml)
2028 {
2029 // m_log.DebugFormat("[XEngine]: Writing state for script item with ID {0}", itemID);
2030  
2031 if (xml == String.Empty)
2032 return false;
2033  
2034 XmlDocument doc = new XmlDocument();
2035  
2036 try
2037 {
2038 doc.LoadXml(xml);
2039 }
2040 catch (Exception)
2041 {
2042 m_log.Error("[XEngine]: Exception decoding XML data from region transfer");
2043 return false;
2044 }
2045  
2046 XmlNodeList rootL = doc.GetElementsByTagName("State");
2047 if (rootL.Count < 1)
2048 return false;
2049  
2050 XmlElement rootE = (XmlElement)rootL[0];
2051  
2052 if (rootE.GetAttribute("Engine") != ScriptEngineName)
2053 return false;
2054  
2055 // On rez from inventory, that ID will have changed. It was only
2056 // advisory anyway. So we don't check it anymore.
2057 //
2058 // if (rootE.GetAttribute("UUID") != itemID.ToString())
2059 // return;
2060  
2061 XmlNodeList stateL = rootE.GetElementsByTagName("ScriptState");
2062  
2063 if (stateL.Count != 1)
2064 return false;
2065  
2066 XmlElement stateE = (XmlElement)stateL[0];
2067  
2068 if (World.m_trustBinaries)
2069 {
2070 XmlNodeList assemL = rootE.GetElementsByTagName("Assembly");
2071  
2072 if (assemL.Count != 1)
2073 return false;
2074  
2075 XmlElement assemE = (XmlElement)assemL[0];
2076  
2077 string fn = assemE.GetAttribute("Filename");
2078 string base64 = assemE.InnerText;
2079  
2080 string path = Path.Combine(m_ScriptEnginesPath, World.RegionInfo.RegionID.ToString());
2081 path = Path.Combine(path, fn);
2082  
2083 if (!File.Exists(path))
2084 {
2085 Byte[] filedata = Convert.FromBase64String(base64);
2086  
2087 try
2088 {
2089 using (FileStream fs = File.Create(path))
2090 {
2091 // m_log.DebugFormat("[XEngine]: Writing assembly file {0}", path);
2092  
2093 fs.Write(filedata, 0, filedata.Length);
2094 }
2095 }
2096 catch (IOException ex)
2097 {
2098 // if there already exists a file at that location, it may be locked.
2099 m_log.ErrorFormat("[XEngine]: Error whilst writing assembly file {0}, {1}", path, ex.Message);
2100 }
2101  
2102 string textpath = path + ".text";
2103 try
2104 {
2105 using (FileStream fs = File.Create(textpath))
2106 {
2107 using (StreamWriter sw = new StreamWriter(fs))
2108 {
2109 // m_log.DebugFormat("[XEngine]: Writing .text file {0}", textpath);
2110  
2111 sw.Write(base64);
2112 }
2113 }
2114 }
2115 catch (IOException ex)
2116 {
2117 // if there already exists a file at that location, it may be locked.
2118 m_log.ErrorFormat("[XEngine]: Error whilst writing .text file {0}, {1}", textpath, ex.Message);
2119 }
2120 }
2121  
2122 XmlNodeList mapL = rootE.GetElementsByTagName("LineMap");
2123 if (mapL.Count > 0)
2124 {
2125 XmlElement mapE = (XmlElement)mapL[0];
2126  
2127 string mappath = Path.Combine(m_ScriptEnginesPath, World.RegionInfo.RegionID.ToString());
2128 mappath = Path.Combine(mappath, mapE.GetAttribute("Filename"));
2129  
2130 try
2131 {
2132 using (FileStream mfs = File.Create(mappath))
2133 {
2134 using (StreamWriter msw = new StreamWriter(mfs))
2135 {
2136 // m_log.DebugFormat("[XEngine]: Writing linemap file {0}", mappath);
2137  
2138 msw.Write(mapE.InnerText);
2139 }
2140 }
2141 }
2142 catch (IOException ex)
2143 {
2144 // if there already exists a file at that location, it may be locked.
2145 m_log.ErrorFormat("[XEngine]: Linemap file {0} already exists! {1}", mappath, ex.Message);
2146 }
2147 }
2148 }
2149  
2150 string statepath = Path.Combine(m_ScriptEnginesPath, World.RegionInfo.RegionID.ToString());
2151 statepath = Path.Combine(statepath, itemID.ToString() + ".state");
2152  
2153 try
2154 {
2155 using (FileStream sfs = File.Create(statepath))
2156 {
2157 using (StreamWriter ssw = new StreamWriter(sfs))
2158 {
2159 // m_log.DebugFormat("[XEngine]: Writing state file {0}", statepath);
2160  
2161 ssw.Write(stateE.OuterXml);
2162 }
2163 }
2164 }
2165 catch (IOException ex)
2166 {
2167 // if there already exists a file at that location, it may be locked.
2168 m_log.ErrorFormat("[XEngine]: Error whilst writing state file {0}, {1}", statepath, ex.Message);
2169 }
2170  
2171 return true;
2172 }
2173  
2174 public ArrayList GetScriptErrors(UUID itemID)
2175 {
2176 System.Threading.Thread.Sleep(1000);
2177  
2178 lock (m_ScriptErrors)
2179 {
2180 if (m_ScriptErrors.ContainsKey(itemID))
2181 {
2182 ArrayList ret = m_ScriptErrors[itemID];
2183 m_ScriptErrors.Remove(itemID);
2184 return ret;
2185 }
2186 return new ArrayList();
2187 }
2188 }
2189  
2190 public Dictionary<uint, float> GetObjectScriptsExecutionTimes()
2191 {
2192 long tickNow = Util.EnvironmentTickCount();
2193 Dictionary<uint, float> topScripts = new Dictionary<uint, float>();
2194  
2195 lock (m_Scripts)
2196 {
2197 foreach (IScriptInstance si in m_Scripts.Values)
2198 {
2199 if (!topScripts.ContainsKey(si.LocalID))
2200 topScripts[si.RootLocalID] = 0;
2201  
2202 topScripts[si.RootLocalID] += CalculateAdjustedExectionTime(si, tickNow);
2203 }
2204 }
2205  
2206 return topScripts;
2207 }
2208  
2209 public float GetScriptExecutionTime(List<UUID> itemIDs)
2210 {
2211 if (itemIDs == null|| itemIDs.Count == 0)
2212 {
2213 return 0.0f;
2214 }
2215 float time = 0.0f;
2216 long tickNow = Util.EnvironmentTickCount();
2217 IScriptInstance si;
2218 // Calculate the time for all scripts that this engine is executing
2219 // Ignore any others
2220 foreach (UUID id in itemIDs)
2221 {
2222 si = GetInstance(id);
2223 if (si != null && si.Running)
2224 {
2225 time += CalculateAdjustedExectionTime(si, tickNow);
2226 }
2227 }
2228 return time;
2229 }
2230  
2231 private float CalculateAdjustedExectionTime(IScriptInstance si, long tickNow)
2232 {
2233 long ticksElapsed = tickNow - si.MeasurementPeriodTickStart;
2234  
2235 // Avoid divide by zero
2236 if (ticksElapsed == 0)
2237 ticksElapsed = 1;
2238  
2239 // Scale execution time to the ideal 55 fps frame time for these reasons.
2240 //
2241 // 1) XEngine does not execute scripts per frame, unlike other script engines. Hence, there is no
2242 // 'script execution time per frame', which is the original purpose of this value.
2243 //
2244 // 2) Giving the raw execution times is misleading since scripts start at different times, making
2245 // it impossible to compare scripts.
2246 //
2247 // 3) Scaling the raw execution time to the time that the script has been running is better but
2248 // is still misleading since a script that has just been rezzed may appear to have been running
2249 // for much longer.
2250 //
2251 // 4) Hence, we scale execution time to an idealised frame time (55 fps). This is also not perfect
2252 // since the figure does not represent actual execution time and very hard running scripts will
2253 // never exceed 18ms (though this is a very high number for script execution so is a warning sign).
2254 return ((float)si.MeasurementPeriodExecutionTime / ticksElapsed) * 18.1818f;
2255 }
2256  
2257 public void SuspendScript(UUID itemID)
2258 {
2259 // m_log.DebugFormat("[XEngine]: Received request to suspend script with ID {0}", itemID);
2260  
2261 IScriptInstance instance = GetInstance(itemID);
2262 if (instance != null)
2263 instance.Suspend();
2264 // else
2265 // m_log.DebugFormat("[XEngine]: Could not find script with ID {0} to resume", itemID);
2266 }
2267  
2268 public void ResumeScript(UUID itemID)
2269 {
2270 // m_log.DebugFormat("[XEngine]: Received request to resume script with ID {0}", itemID);
2271  
2272 IScriptInstance instance = GetInstance(itemID);
2273 if (instance != null)
2274 instance.Resume();
2275 // else
2276 // m_log.DebugFormat("[XEngine]: Could not find script with ID {0} to resume", itemID);
2277 }
2278  
2279 public bool HasScript(UUID itemID, out bool running)
2280 {
2281 running = true;
2282  
2283 IScriptInstance instance = GetInstance(itemID);
2284 if (instance == null)
2285 return false;
2286  
2287 running = instance.Running;
2288 return true;
2289 }
2290 }
2291 }