diff options
author | David Walter Seikel | 2016-11-03 21:44:39 +1000 |
---|---|---|
committer | David Walter Seikel | 2016-11-03 21:44:39 +1000 |
commit | 134f86e8d5c414409631b25b8c6f0ee45fbd8631 (patch) | |
tree | 216b89d3fb89acfb81be1e440c25c41ab09fa96d /OpenSim/Region/ScriptEngine/XEngine/XEngine.cs | |
parent | More changing to production grid. Double oops. (diff) | |
download | opensim-SC_OLD-134f86e8d5c414409631b25b8c6f0ee45fbd8631.zip opensim-SC_OLD-134f86e8d5c414409631b25b8c6f0ee45fbd8631.tar.gz opensim-SC_OLD-134f86e8d5c414409631b25b8c6f0ee45fbd8631.tar.bz2 opensim-SC_OLD-134f86e8d5c414409631b25b8c6f0ee45fbd8631.tar.xz |
Initial update to OpenSim 0.8.2.1 source code.
Diffstat (limited to 'OpenSim/Region/ScriptEngine/XEngine/XEngine.cs')
-rwxr-xr-x[-rw-r--r--] | OpenSim/Region/ScriptEngine/XEngine/XEngine.cs | 609 |
1 files changed, 417 insertions, 192 deletions
diff --git a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs index 18569ca..78d4ee9 100644..100755 --- a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs +++ b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs | |||
@@ -42,22 +42,26 @@ using OpenMetaverse.StructuredData; | |||
42 | using log4net; | 42 | using log4net; |
43 | using Nini.Config; | 43 | using Nini.Config; |
44 | using Amib.Threading; | 44 | using Amib.Threading; |
45 | using Mono.Addins; | ||
45 | using OpenSim.Framework; | 46 | using OpenSim.Framework; |
46 | using OpenSim.Framework.Console; | 47 | using OpenSim.Framework.Console; |
47 | using OpenSim.Region.Framework.Scenes; | 48 | using OpenSim.Region.Framework.Scenes; |
48 | using OpenSim.Region.Framework.Interfaces; | 49 | using OpenSim.Region.Framework.Interfaces; |
50 | using OpenSim.Region.ScriptEngine.Interfaces; | ||
49 | using OpenSim.Region.ScriptEngine.Shared; | 51 | using OpenSim.Region.ScriptEngine.Shared; |
50 | using OpenSim.Region.ScriptEngine.Shared.CodeTools; | 52 | using OpenSim.Region.ScriptEngine.Shared.CodeTools; |
51 | using OpenSim.Region.ScriptEngine.Shared.Instance; | 53 | using OpenSim.Region.ScriptEngine.Shared.Instance; |
52 | using OpenSim.Region.ScriptEngine.Shared.Api; | 54 | using OpenSim.Region.ScriptEngine.Shared.Api; |
53 | using OpenSim.Region.ScriptEngine.Shared.Api.Plugins; | 55 | using OpenSim.Region.ScriptEngine.Shared.Api.Plugins; |
54 | using OpenSim.Region.ScriptEngine.Interfaces; | 56 | using OpenSim.Region.ScriptEngine.Shared.ScriptBase; |
57 | using OpenSim.Region.ScriptEngine.XEngine.ScriptBase; | ||
55 | using Timer = OpenSim.Region.ScriptEngine.Shared.Api.Plugins.Timer; | 58 | using Timer = OpenSim.Region.ScriptEngine.Shared.Api.Plugins.Timer; |
56 | 59 | ||
57 | using ScriptCompileQueue = OpenSim.Framework.LocklessQueue<object[]>; | 60 | using ScriptCompileQueue = OpenSim.Framework.LocklessQueue<object[]>; |
58 | 61 | ||
59 | namespace OpenSim.Region.ScriptEngine.XEngine | 62 | namespace OpenSim.Region.ScriptEngine.XEngine |
60 | { | 63 | { |
64 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "XEngine")] | ||
61 | public class XEngine : INonSharedRegionModule, IScriptModule, IScriptEngine | 65 | public class XEngine : INonSharedRegionModule, IScriptModule, IScriptEngine |
62 | { | 66 | { |
63 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 67 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
@@ -68,7 +72,13 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
68 | /// <remarks> | 72 | /// <remarks> |
69 | /// If DebugLevel >= 1, then we log every time that a script is started. | 73 | /// If DebugLevel >= 1, then we log every time that a script is started. |
70 | /// </remarks> | 74 | /// </remarks> |
71 | // public int DebugLevel { get; set; } | 75 | public int DebugLevel { get; set; } |
76 | |||
77 | /// <summary> | ||
78 | /// A parameter to allow us to notify the log if at least one script has a compilation that is not compatible | ||
79 | /// with ScriptStopStrategy. | ||
80 | /// </summary> | ||
81 | public bool HaveNotifiedLogOfScriptStopMistmatch { get; private set; } | ||
72 | 82 | ||
73 | private SmartThreadPool m_ThreadPool; | 83 | private SmartThreadPool m_ThreadPool; |
74 | private int m_MaxScriptQueue; | 84 | private int m_MaxScriptQueue; |
@@ -84,6 +94,12 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
84 | /// </summary> | 94 | /// </summary> |
85 | private int m_StartDelay; | 95 | private int m_StartDelay; |
86 | 96 | ||
97 | /// <summary> | ||
98 | /// Are we stopping scripts co-operatively by inserting checks in them at C# compile time (true) or aborting | ||
99 | /// their threads (false)? | ||
100 | /// </summary> | ||
101 | private bool m_coopTermination; | ||
102 | |||
87 | private int m_IdleTimeout; | 103 | private int m_IdleTimeout; |
88 | private int m_StackSize; | 104 | private int m_StackSize; |
89 | private int m_SleepTime; | 105 | private int m_SleepTime; |
@@ -93,7 +109,6 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
93 | private bool m_InitialStartup = true; | 109 | private bool m_InitialStartup = true; |
94 | private int m_ScriptFailCount; // Number of script fails since compile queue was last empty | 110 | private int m_ScriptFailCount; // Number of script fails since compile queue was last empty |
95 | private string m_ScriptErrorMessage; | 111 | private string m_ScriptErrorMessage; |
96 | private Dictionary<string, string> m_uniqueScripts = new Dictionary<string, string>(); | ||
97 | private bool m_AppDomainLoading; | 112 | private bool m_AppDomainLoading; |
98 | private Dictionary<UUID,ArrayList> m_ScriptErrors = | 113 | private Dictionary<UUID,ArrayList> m_ScriptErrors = |
99 | new Dictionary<UUID,ArrayList>(); | 114 | new Dictionary<UUID,ArrayList>(); |
@@ -175,6 +190,14 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
175 | get { return "XEngine"; } | 190 | get { return "XEngine"; } |
176 | } | 191 | } |
177 | 192 | ||
193 | public string ScriptClassName { get; private set; } | ||
194 | |||
195 | public string ScriptBaseClassName { get; private set; } | ||
196 | |||
197 | public ParameterInfo[] ScriptBaseClassParameters { get; private set; } | ||
198 | |||
199 | public string[] ScriptReferencedAssemblies { get; private set; } | ||
200 | |||
178 | public Scene World | 201 | public Scene World |
179 | { | 202 | { |
180 | get { return m_Scene; } | 203 | get { return m_Scene; } |
@@ -229,21 +252,36 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
229 | 252 | ||
230 | m_ScriptConfig = configSource.Configs["XEngine"]; | 253 | m_ScriptConfig = configSource.Configs["XEngine"]; |
231 | m_ConfigSource = configSource; | 254 | m_ConfigSource = configSource; |
255 | |||
256 | string rawScriptStopStrategy = m_ScriptConfig.GetString("ScriptStopStrategy", "co-op"); | ||
257 | |||
258 | m_log.InfoFormat("[XEngine]: Script stop strategy is {0}", rawScriptStopStrategy); | ||
259 | |||
260 | if (rawScriptStopStrategy == "co-op") | ||
261 | { | ||
262 | m_coopTermination = true; | ||
263 | ScriptClassName = "XEngineScript"; | ||
264 | ScriptBaseClassName = typeof(XEngineScriptBase).FullName; | ||
265 | ScriptBaseClassParameters = typeof(XEngineScriptBase).GetConstructor(new Type[] { typeof(WaitHandle) }).GetParameters(); | ||
266 | ScriptReferencedAssemblies = new string[] { Path.GetFileName(typeof(XEngineScriptBase).Assembly.Location) }; | ||
267 | } | ||
268 | else | ||
269 | { | ||
270 | ScriptClassName = "Script"; | ||
271 | ScriptBaseClassName = typeof(ScriptBaseClass).FullName; | ||
272 | } | ||
273 | |||
274 | // Console.WriteLine("ASSEMBLY NAME: {0}", ScriptReferencedAssemblies[0]); | ||
232 | } | 275 | } |
233 | 276 | ||
234 | public void AddRegion(Scene scene) | 277 | public void AddRegion(Scene scene) |
235 | { | 278 | { |
236 | if (m_ScriptConfig == null) | 279 | if (m_ScriptConfig == null) |
237 | return; | 280 | return; |
281 | |||
238 | m_ScriptFailCount = 0; | 282 | m_ScriptFailCount = 0; |
239 | m_ScriptErrorMessage = String.Empty; | 283 | m_ScriptErrorMessage = String.Empty; |
240 | 284 | ||
241 | if (m_ScriptConfig == null) | ||
242 | { | ||
243 | // m_log.ErrorFormat("[XEngine] No script configuration found. Scripts disabled"); | ||
244 | return; | ||
245 | } | ||
246 | |||
247 | m_Enabled = m_ScriptConfig.GetBoolean("Enabled", true); | 285 | m_Enabled = m_ScriptConfig.GetBoolean("Enabled", true); |
248 | 286 | ||
249 | if (!m_Enabled) | 287 | if (!m_Enabled) |
@@ -365,19 +403,19 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
365 | (module, cmdparams) => HandleScriptsAction(cmdparams, HandleStartScript)); | 403 | (module, cmdparams) => HandleScriptsAction(cmdparams, HandleStartScript)); |
366 | 404 | ||
367 | MainConsole.Instance.Commands.AddCommand( | 405 | MainConsole.Instance.Commands.AddCommand( |
368 | "Scripts", false, "debug scripts log", "debug scripts log <item-id> <log-level>", "Extra debug logging for a script", | 406 | "Debug", false, "debug scripts log", "debug scripts log <item-id> <log-level>", "Extra debug logging for a particular script.", |
369 | "Activates or deactivates extra debug logging for the given script.\n" | 407 | "Activates or deactivates extra debug logging for the given script.\n" |
370 | + "Level == 0, deactivate extra debug logging.\n" | 408 | + "Level == 0, deactivate extra debug logging.\n" |
371 | + "Level >= 1, log state changes.\n" | 409 | + "Level >= 1, log state changes.\n" |
372 | + "Level >= 2, log event invocations.\n", | 410 | + "Level >= 2, log event invocations.\n", |
373 | HandleDebugScriptLogCommand); | 411 | HandleDebugScriptLogCommand); |
374 | 412 | ||
375 | // MainConsole.Instance.Commands.AddCommand( | 413 | MainConsole.Instance.Commands.AddCommand( |
376 | // "Debug", false, "debug xengine", "debug xengine [<level>]", | 414 | "Debug", false, "debug xengine log", "debug xengine log [<level>]", |
377 | // "Turn on detailed xengine debugging.", | 415 | "Turn on detailed xengine debugging.", |
378 | // "If level <= 0, then no extra logging is done.\n" | 416 | "If level <= 0, then no extra logging is done.\n" |
379 | // + "If level >= 1, then we log every time that a script is started.", | 417 | + "If level >= 1, then we log every time that a script is started.", |
380 | // HandleDebugLevelCommand); | 418 | HandleDebugLevelCommand); |
381 | } | 419 | } |
382 | 420 | ||
383 | private void HandleDebugScriptLogCommand(string module, string[] args) | 421 | private void HandleDebugScriptLogCommand(string module, string[] args) |
@@ -420,26 +458,26 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
420 | /// </summary> | 458 | /// </summary> |
421 | /// <param name="module"></param> | 459 | /// <param name="module"></param> |
422 | /// <param name="args"></param> | 460 | /// <param name="args"></param> |
423 | // private void HandleDebugLevelCommand(string module, string[] args) | 461 | private void HandleDebugLevelCommand(string module, string[] args) |
424 | // { | 462 | { |
425 | // if (args.Length == 3) | 463 | if (args.Length >= 4) |
426 | // { | 464 | { |
427 | // int newDebug; | 465 | int newDebug; |
428 | // if (int.TryParse(args[2], out newDebug)) | 466 | if (ConsoleUtil.TryParseConsoleNaturalInt(MainConsole.Instance, args[3], out newDebug)) |
429 | // { | 467 | { |
430 | // DebugLevel = newDebug; | 468 | DebugLevel = newDebug; |
431 | // MainConsole.Instance.OutputFormat("Debug level set to {0}", newDebug); | 469 | MainConsole.Instance.OutputFormat("Debug level set to {0} in XEngine for region {1}", newDebug, m_Scene.Name); |
432 | // } | 470 | } |
433 | // } | 471 | } |
434 | // else if (args.Length == 2) | 472 | else if (args.Length == 3) |
435 | // { | 473 | { |
436 | // MainConsole.Instance.OutputFormat("Current debug level is {0}", DebugLevel); | 474 | MainConsole.Instance.OutputFormat("Current debug level is {0}", DebugLevel); |
437 | // } | 475 | } |
438 | // else | 476 | else |
439 | // { | 477 | { |
440 | // MainConsole.Instance.Output("Usage: debug xengine 0..1"); | 478 | MainConsole.Instance.Output("Usage: debug xengine log <level>"); |
441 | // } | 479 | } |
442 | // } | 480 | } |
443 | 481 | ||
444 | /// <summary> | 482 | /// <summary> |
445 | /// Parse the raw item id into a script instance from the command params if it's present. | 483 | /// Parse the raw item id into a script instance from the command params if it's present. |
@@ -459,7 +497,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
459 | /// <param name="instance"></param> | 497 | /// <param name="instance"></param> |
460 | /// <param name="keySelector">Basis on which to sort output. Can be null if no sort needs to take place</param> | 498 | /// <param name="keySelector">Basis on which to sort output. Can be null if no sort needs to take place</param> |
461 | private void HandleScriptsAction<TKey>( | 499 | private void HandleScriptsAction<TKey>( |
462 | string[] cmdparams, Action<IScriptInstance> action, Func<IScriptInstance, TKey> keySelector) | 500 | string[] cmdparams, Action<IScriptInstance> action, System.Func<IScriptInstance, TKey> keySelector) |
463 | { | 501 | { |
464 | if (!(MainConsole.Instance.ConsoleScene == null || MainConsole.Instance.ConsoleScene == m_Scene)) | 502 | if (!(MainConsole.Instance.ConsoleScene == null || MainConsole.Instance.ConsoleScene == m_Scene)) |
465 | return; | 503 | return; |
@@ -517,7 +555,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
517 | if (!(MainConsole.Instance.ConsoleScene == null || MainConsole.Instance.ConsoleScene == m_Scene)) | 555 | if (!(MainConsole.Instance.ConsoleScene == null || MainConsole.Instance.ConsoleScene == m_Scene)) |
518 | return; | 556 | return; |
519 | 557 | ||
520 | MainConsole.Instance.OutputFormat(GetStatusReport()); | 558 | MainConsole.Instance.Output(GetStatusReport()); |
521 | } | 559 | } |
522 | 560 | ||
523 | public string GetStatusReport() | 561 | public string GetStatusReport() |
@@ -539,7 +577,6 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
539 | } | 577 | } |
540 | 578 | ||
541 | sb.AppendFormat("Scripts loaded : {0}\n", scriptsLoaded); | 579 | sb.AppendFormat("Scripts loaded : {0}\n", scriptsLoaded); |
542 | sb.AppendFormat("Unique scripts : {0}\n", m_uniqueScripts.Count); | ||
543 | sb.AppendFormat("Scripts waiting for load : {0}\n", m_CompileQueue.Count); | 580 | sb.AppendFormat("Scripts waiting for load : {0}\n", m_CompileQueue.Count); |
544 | sb.AppendFormat("Max threads : {0}\n", m_ThreadPool.MaxThreads); | 581 | sb.AppendFormat("Max threads : {0}\n", m_ThreadPool.MaxThreads); |
545 | sb.AppendFormat("Min threads : {0}\n", m_ThreadPool.MinThreads); | 582 | sb.AppendFormat("Min threads : {0}\n", m_ThreadPool.MinThreads); |
@@ -616,7 +653,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
616 | sb.AppendFormat("Containing part UUID: {0}\n", instance.ObjectID); | 653 | sb.AppendFormat("Containing part UUID: {0}\n", instance.ObjectID); |
617 | sb.AppendFormat("Position : {0}\n", sop.AbsolutePosition); | 654 | sb.AppendFormat("Position : {0}\n", sop.AbsolutePosition); |
618 | 655 | ||
619 | MainConsole.Instance.OutputFormat(sb.ToString()); | 656 | MainConsole.Instance.Output(sb.ToString()); |
620 | } | 657 | } |
621 | 658 | ||
622 | private void HandleSuspendScript(IScriptInstance instance) | 659 | private void HandleSuspendScript(IScriptInstance instance) |
@@ -662,6 +699,8 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
662 | { | 699 | { |
663 | if (instance.Running) | 700 | if (instance.Running) |
664 | { | 701 | { |
702 | instance.StayStopped = true; // the script was stopped explicitly | ||
703 | |||
665 | instance.Stop(0); | 704 | instance.Stop(0); |
666 | 705 | ||
667 | SceneObjectPart sop = m_Scene.GetSceneObjectPart(instance.ObjectID); | 706 | SceneObjectPart sop = m_Scene.GetSceneObjectPart(instance.ObjectID); |
@@ -685,28 +724,23 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
685 | { | 724 | { |
686 | // Force a final state save | 725 | // Force a final state save |
687 | // | 726 | // |
688 | if (m_Assemblies.ContainsKey(instance.AssetID)) | 727 | try |
689 | { | 728 | { |
690 | string assembly = m_Assemblies[instance.AssetID]; | 729 | if (instance.StatePersistedHere) |
691 | 730 | instance.SaveState(); | |
692 | try | 731 | } |
693 | { | 732 | catch (Exception e) |
694 | instance.SaveState(assembly); | 733 | { |
695 | } | 734 | m_log.Error( |
696 | catch (Exception e) | 735 | string.Format( |
697 | { | 736 | "[XEngine]: Failed final state save for script {0}.{1}, item UUID {2}, prim UUID {3} in {4}. Exception ", |
698 | m_log.Error( | 737 | instance.PrimName, instance.ScriptName, instance.ItemID, instance.ObjectID, World.Name) |
699 | string.Format( | 738 | , e); |
700 | "[XEngine]: Failed final state save for script {0}.{1}, item UUID {2}, prim UUID {3} in {4}. Exception ", | ||
701 | instance.PrimName, instance.ScriptName, instance.ItemID, instance.ObjectID, World.Name) | ||
702 | , e); | ||
703 | } | ||
704 | } | 739 | } |
705 | 740 | ||
706 | // Clear the event queue and abort the instance thread | 741 | // Clear the event queue and abort the instance thread |
707 | // | 742 | // |
708 | instance.ClearQueue(); | 743 | instance.Stop(0, true); |
709 | instance.Stop(0); | ||
710 | 744 | ||
711 | // Release events, timer, etc | 745 | // Release events, timer, etc |
712 | // | 746 | // |
@@ -804,23 +838,23 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
804 | lock (m_Scripts) | 838 | lock (m_Scripts) |
805 | { | 839 | { |
806 | foreach (IScriptInstance instance in m_Scripts.Values) | 840 | foreach (IScriptInstance instance in m_Scripts.Values) |
807 | instances.Add(instance); | 841 | { |
842 | if (instance.StatePersistedHere) | ||
843 | { | ||
844 | // m_log.DebugFormat( | ||
845 | // "[XEngine]: Adding script {0}.{1}, item UUID {2}, prim UUID {3} in {4} for state persistence", | ||
846 | // instance.PrimName, instance.ScriptName, instance.ItemID, instance.ObjectID, World.Name); | ||
847 | |||
848 | instances.Add(instance); | ||
849 | } | ||
850 | } | ||
808 | } | 851 | } |
809 | 852 | ||
810 | foreach (IScriptInstance i in instances) | 853 | foreach (IScriptInstance i in instances) |
811 | { | 854 | { |
812 | string assembly = String.Empty; | ||
813 | |||
814 | lock (m_Scripts) | ||
815 | { | ||
816 | if (!m_Assemblies.ContainsKey(i.AssetID)) | ||
817 | continue; | ||
818 | assembly = m_Assemblies[i.AssetID]; | ||
819 | } | ||
820 | |||
821 | try | 855 | try |
822 | { | 856 | { |
823 | i.SaveState(assembly); | 857 | i.SaveState(); |
824 | } | 858 | } |
825 | catch (Exception e) | 859 | catch (Exception e) |
826 | { | 860 | { |
@@ -832,8 +866,6 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
832 | } | 866 | } |
833 | } | 867 | } |
834 | 868 | ||
835 | instances.Clear(); | ||
836 | |||
837 | if (saveTime > 0) | 869 | if (saveTime > 0) |
838 | m_ThreadPool.QueueWorkItem(new WorkItemCallback(this.DoBackup), | 870 | m_ThreadPool.QueueWorkItem(new WorkItemCallback(this.DoBackup), |
839 | new Object[] { saveTime }); | 871 | new Object[] { saveTime }); |
@@ -843,6 +875,14 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
843 | 875 | ||
844 | public void SaveAllState() | 876 | public void SaveAllState() |
845 | { | 877 | { |
878 | DoBackup(new object[] { 0 }); | ||
879 | } | ||
880 | |||
881 | public object DoMaintenance(object p) | ||
882 | { | ||
883 | object[] parms = (object[])p; | ||
884 | int sleepTime = (int)parms[0]; | ||
885 | |||
846 | foreach (IScriptInstance inst in m_Scripts.Values) | 886 | foreach (IScriptInstance inst in m_Scripts.Values) |
847 | { | 887 | { |
848 | if (inst.EventTime() > m_EventLimit) | 888 | if (inst.EventTime() > m_EventLimit) |
@@ -852,14 +892,6 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
852 | inst.Start(); | 892 | inst.Start(); |
853 | } | 893 | } |
854 | } | 894 | } |
855 | } | ||
856 | |||
857 | public object DoMaintenance(object p) | ||
858 | { | ||
859 | object[] parms = (object[])p; | ||
860 | int sleepTime = (int)parms[0]; | ||
861 | |||
862 | SaveAllState(); | ||
863 | 895 | ||
864 | System.Threading.Thread.Sleep(sleepTime); | 896 | System.Threading.Thread.Sleep(sleepTime); |
865 | 897 | ||
@@ -937,8 +969,6 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
937 | if (restOfFirstLine.StartsWith("c#") | 969 | if (restOfFirstLine.StartsWith("c#") |
938 | || restOfFirstLine.StartsWith("vb") | 970 | || restOfFirstLine.StartsWith("vb") |
939 | || restOfFirstLine.StartsWith("lsl") | 971 | || restOfFirstLine.StartsWith("lsl") |
940 | || restOfFirstLine.StartsWith("js") | ||
941 | || restOfFirstLine.StartsWith("yp") | ||
942 | || restOfFirstLine.Length == 0) | 972 | || restOfFirstLine.Length == 0) |
943 | warnRunningInXEngine = true; | 973 | warnRunningInXEngine = true; |
944 | 974 | ||
@@ -972,12 +1002,6 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
972 | if (engine != ScriptEngineName) | 1002 | if (engine != ScriptEngineName) |
973 | return; | 1003 | return; |
974 | 1004 | ||
975 | // If we've seen this exact script text before, use that reference instead | ||
976 | if (m_uniqueScripts.ContainsKey(script)) | ||
977 | script = m_uniqueScripts[script]; | ||
978 | else | ||
979 | m_uniqueScripts[script] = script; | ||
980 | |||
981 | Object[] parms = new Object[]{localID, itemID, script, startParam, postOnRez, (StateSource)stateSource}; | 1005 | Object[] parms = new Object[]{localID, itemID, script, startParam, postOnRez, (StateSource)stateSource}; |
982 | 1006 | ||
983 | if (stateSource == (int)StateSource.ScriptedRez) | 1007 | if (stateSource == (int)StateSource.ScriptedRez) |
@@ -991,11 +1015,12 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
991 | } | 1015 | } |
992 | else | 1016 | else |
993 | { | 1017 | { |
994 | m_CompileQueue.Enqueue(parms); | ||
995 | lock (m_CompileDict) | 1018 | lock (m_CompileDict) |
996 | { | ||
997 | m_CompileDict[itemID] = 0; | 1019 | m_CompileDict[itemID] = 0; |
998 | } | 1020 | |
1021 | // This must occur after the m_CompileDict so that an existing compile thread cannot hit the check | ||
1022 | // in DoOnRezScript() before m_CompileDict has been updated. | ||
1023 | m_CompileQueue.Enqueue(parms); | ||
999 | 1024 | ||
1000 | // m_log.DebugFormat("[XEngine]: Added script {0} to compile queue", itemID); | 1025 | // m_log.DebugFormat("[XEngine]: Added script {0} to compile queue", itemID); |
1001 | 1026 | ||
@@ -1017,49 +1042,81 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
1017 | 1042 | ||
1018 | public Object DoOnRezScriptQueue(Object dummy) | 1043 | public Object DoOnRezScriptQueue(Object dummy) |
1019 | { | 1044 | { |
1020 | if (m_InitialStartup) | 1045 | try |
1021 | { | 1046 | { |
1022 | // This delay exists to stop mono problems where script compilation and startup would stop the sim | 1047 | if (m_InitialStartup) |
1023 | // working properly for the session. | 1048 | { |
1024 | System.Threading.Thread.Sleep(m_StartDelay); | 1049 | // This delay exists to stop mono problems where script compilation and startup would stop the sim |
1050 | // working properly for the session. | ||
1051 | System.Threading.Thread.Sleep(m_StartDelay); | ||
1025 | 1052 | ||
1026 | m_log.InfoFormat("[XEngine]: Performing initial script startup on {0}", m_Scene.Name); | 1053 | m_log.InfoFormat("[XEngine]: Performing initial script startup on {0}", m_Scene.Name); |
1027 | } | 1054 | } |
1028 | 1055 | ||
1029 | object[] o; | 1056 | object[] o; |
1030 | 1057 | ||
1031 | int scriptsStarted = 0; | 1058 | int scriptsStarted = 0; |
1032 | 1059 | ||
1033 | while (m_CompileQueue.Dequeue(out o)) | 1060 | while (m_CompileQueue.Dequeue(out o)) |
1034 | { | ||
1035 | if (DoOnRezScript(o)) | ||
1036 | { | 1061 | { |
1037 | scriptsStarted++; | 1062 | try |
1063 | { | ||
1064 | if (DoOnRezScript(o)) | ||
1065 | { | ||
1066 | scriptsStarted++; | ||
1038 | 1067 | ||
1039 | if (m_InitialStartup) | 1068 | if (m_InitialStartup) |
1040 | if (scriptsStarted % 50 == 0) | 1069 | if (scriptsStarted % 50 == 0) |
1041 | m_log.InfoFormat( | 1070 | m_log.InfoFormat( |
1042 | "[XEngine]: Started {0} scripts in {1}", scriptsStarted, m_Scene.Name); | 1071 | "[XEngine]: Started {0} scripts in {1}", scriptsStarted, m_Scene.Name); |
1072 | } | ||
1073 | } | ||
1074 | catch (Exception e) | ||
1075 | { | ||
1076 | m_log.Error( | ||
1077 | string.Format( | ||
1078 | "[XEngine]: Failure in DoOnRezScriptQueue() for item {0} in {1}. Continuing. Exception ", | ||
1079 | o[1], m_Scene.Name), | ||
1080 | e); | ||
1081 | } | ||
1043 | } | 1082 | } |
1044 | } | ||
1045 | 1083 | ||
1046 | if (m_InitialStartup) | 1084 | if (m_InitialStartup) |
1047 | m_log.InfoFormat( | 1085 | m_log.InfoFormat( |
1048 | "[XEngine]: Completed starting {0} scripts on {1}", scriptsStarted, m_Scene.Name); | 1086 | "[XEngine]: Completed starting {0} scripts on {1}", scriptsStarted, m_Scene.Name); |
1049 | 1087 | ||
1050 | // NOTE: Despite having a lockless queue, this lock is required | 1088 | } |
1051 | // to make sure there is never no compile thread while there | 1089 | catch (Exception e) |
1052 | // are still scripts to compile. This could otherwise happen | 1090 | { |
1053 | // due to a race condition | 1091 | m_log.Error( |
1054 | // | 1092 | string.Format("[XEngine]: Failure in DoOnRezScriptQueue() in {0}. Exception ", m_Scene.Name), e); |
1055 | lock (m_CompileQueue) | 1093 | } |
1056 | m_CurrentCompile = null; | 1094 | finally |
1095 | { | ||
1096 | // FIXME: On failure we must trigger this even if the compile queue is not actually empty so that the | ||
1097 | // RegionReadyModule is not forever waiting. This event really needs a different name. | ||
1098 | m_Scene.EventManager.TriggerEmptyScriptCompileQueue(m_ScriptFailCount, | ||
1099 | m_ScriptErrorMessage); | ||
1057 | 1100 | ||
1058 | m_Scene.EventManager.TriggerEmptyScriptCompileQueue(m_ScriptFailCount, | 1101 | m_ScriptFailCount = 0; |
1059 | m_ScriptErrorMessage); | 1102 | m_InitialStartup = false; |
1060 | 1103 | ||
1061 | m_ScriptFailCount = 0; | 1104 | // NOTE: Despite having a lockless queue, this lock is required |
1062 | m_InitialStartup = false; | 1105 | // to make sure there is never no compile thread while there |
1106 | // are still scripts to compile. This could otherwise happen | ||
1107 | // due to a race condition | ||
1108 | // | ||
1109 | lock (m_CompileQueue) | ||
1110 | { | ||
1111 | m_CurrentCompile = null; | ||
1112 | |||
1113 | // This is to avoid a situation where the m_CompileQueue while loop above could complete but | ||
1114 | // OnRezScript() place a new script on the queue and check m_CurrentCompile = null before we hit | ||
1115 | // this section. | ||
1116 | if (m_CompileQueue.Count > 0) | ||
1117 | m_CurrentCompile = m_ThreadPool.QueueWorkItem(DoOnRezScriptQueue, null); | ||
1118 | } | ||
1119 | } | ||
1063 | 1120 | ||
1064 | return null; | 1121 | return null; |
1065 | } | 1122 | } |
@@ -1106,16 +1163,17 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
1106 | return false; | 1163 | return false; |
1107 | } | 1164 | } |
1108 | 1165 | ||
1109 | m_log.DebugFormat( | 1166 | if (DebugLevel > 0) |
1110 | "[XEngine] Loading script {0}.{1}, item UUID {2}, prim UUID {3} @ {4}.{5}", | 1167 | m_log.DebugFormat( |
1111 | part.ParentGroup.RootPart.Name, item.Name, itemID, part.UUID, | 1168 | "[XEngine]: Loading script {0}.{1}, item UUID {2}, prim UUID {3} @ {4}.{5}", |
1112 | part.ParentGroup.RootPart.AbsolutePosition, part.ParentGroup.Scene.RegionInfo.RegionName); | 1169 | part.ParentGroup.RootPart.Name, item.Name, itemID, part.UUID, |
1170 | part.ParentGroup.RootPart.AbsolutePosition, part.ParentGroup.Scene.RegionInfo.RegionName); | ||
1113 | 1171 | ||
1114 | UUID assetID = item.AssetID; | 1172 | UUID assetID = item.AssetID; |
1115 | 1173 | ||
1116 | ScenePresence presence = m_Scene.GetScenePresence(item.OwnerID); | 1174 | ScenePresence presence = m_Scene.GetScenePresence(item.OwnerID); |
1117 | 1175 | ||
1118 | string assembly = ""; | 1176 | string assemblyPath = ""; |
1119 | 1177 | ||
1120 | Culture.SetCurrentCulture(); | 1178 | Culture.SetCurrentCulture(); |
1121 | 1179 | ||
@@ -1127,11 +1185,16 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
1127 | { | 1185 | { |
1128 | lock (m_AddingAssemblies) | 1186 | lock (m_AddingAssemblies) |
1129 | { | 1187 | { |
1130 | m_Compiler.PerformScriptCompile(script, assetID.ToString(), item.OwnerID, out assembly, out linemap); | 1188 | m_Compiler.PerformScriptCompile(script, assetID.ToString(), item.OwnerID, out assemblyPath, out linemap); |
1131 | if (!m_AddingAssemblies.ContainsKey(assembly)) { | 1189 | |
1132 | m_AddingAssemblies[assembly] = 1; | 1190 | // m_log.DebugFormat( |
1191 | // "[XENGINE]: Found assembly path {0} onrez {1} in {2}", | ||
1192 | // assemblyPath, item.ItemID, World.Name); | ||
1193 | |||
1194 | if (!m_AddingAssemblies.ContainsKey(assemblyPath)) { | ||
1195 | m_AddingAssemblies[assemblyPath] = 1; | ||
1133 | } else { | 1196 | } else { |
1134 | m_AddingAssemblies[assembly]++; | 1197 | m_AddingAssemblies[assemblyPath]++; |
1135 | } | 1198 | } |
1136 | } | 1199 | } |
1137 | 1200 | ||
@@ -1177,7 +1240,9 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
1177 | } | 1240 | } |
1178 | catch (Exception e) | 1241 | catch (Exception e) |
1179 | { | 1242 | { |
1180 | // m_log.ErrorFormat("[XEngine]: Exception when rezzing script {0}{1}", e.Message, e.StackTrace); | 1243 | // m_log.ErrorFormat( |
1244 | // "[XEngine]: Exception when rezzing script with item ID {0}, {1}{2}", | ||
1245 | // itemID, e.Message, e.StackTrace); | ||
1181 | 1246 | ||
1182 | // try | 1247 | // try |
1183 | // { | 1248 | // { |
@@ -1274,19 +1339,144 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
1274 | m_ScriptFailCount++; | 1339 | m_ScriptFailCount++; |
1275 | lock (m_AddingAssemblies) | 1340 | lock (m_AddingAssemblies) |
1276 | { | 1341 | { |
1277 | m_AddingAssemblies[assembly]--; | 1342 | m_AddingAssemblies[assemblyPath]--; |
1278 | } | 1343 | } |
1279 | return false; | 1344 | return false; |
1280 | } | 1345 | } |
1281 | } | 1346 | } |
1282 | m_DomainScripts[appDomain].Add(itemID); | 1347 | m_DomainScripts[appDomain].Add(itemID); |
1283 | 1348 | ||
1349 | IScript scriptObj = null; | ||
1350 | EventWaitHandle coopSleepHandle; | ||
1351 | bool coopTerminationForThisScript; | ||
1352 | |||
1353 | // Set up assembly name to point to the appropriate scriptEngines directory | ||
1354 | AssemblyName assemblyName = new AssemblyName(Path.GetFileNameWithoutExtension(assemblyPath)); | ||
1355 | assemblyName.CodeBase = Path.GetDirectoryName(assemblyPath); | ||
1356 | |||
1357 | if (m_coopTermination) | ||
1358 | { | ||
1359 | try | ||
1360 | { | ||
1361 | coopSleepHandle = new XEngineEventWaitHandle(false, EventResetMode.AutoReset); | ||
1362 | |||
1363 | scriptObj | ||
1364 | = (IScript)m_AppDomains[appDomain].CreateInstanceAndUnwrap( | ||
1365 | assemblyName.FullName, | ||
1366 | "SecondLife.XEngineScript", | ||
1367 | false, | ||
1368 | BindingFlags.Default, | ||
1369 | null, | ||
1370 | new object[] { coopSleepHandle }, | ||
1371 | null, | ||
1372 | null); | ||
1373 | |||
1374 | coopTerminationForThisScript = true; | ||
1375 | } | ||
1376 | catch (TypeLoadException) | ||
1377 | { | ||
1378 | coopSleepHandle = null; | ||
1379 | |||
1380 | try | ||
1381 | { | ||
1382 | scriptObj | ||
1383 | = (IScript)m_AppDomains[appDomain].CreateInstanceAndUnwrap( | ||
1384 | assemblyName.FullName, | ||
1385 | "SecondLife.Script", | ||
1386 | false, | ||
1387 | BindingFlags.Default, | ||
1388 | null, | ||
1389 | null, | ||
1390 | null, | ||
1391 | null); | ||
1392 | } | ||
1393 | catch (Exception e2) | ||
1394 | { | ||
1395 | m_log.Error( | ||
1396 | string.Format( | ||
1397 | "[XENGINE]: Could not load previous SecondLife.Script from assembly {0} in {1}. Not starting. Exception ", | ||
1398 | assemblyName.FullName, World.Name), | ||
1399 | e2); | ||
1400 | |||
1401 | return false; | ||
1402 | } | ||
1403 | |||
1404 | coopTerminationForThisScript = false; | ||
1405 | } | ||
1406 | } | ||
1407 | else | ||
1408 | { | ||
1409 | try | ||
1410 | { | ||
1411 | scriptObj | ||
1412 | = (IScript)m_AppDomains[appDomain].CreateInstanceAndUnwrap( | ||
1413 | assemblyName.FullName, | ||
1414 | "SecondLife.Script", | ||
1415 | false, | ||
1416 | BindingFlags.Default, | ||
1417 | null, | ||
1418 | null, | ||
1419 | null, | ||
1420 | null); | ||
1421 | |||
1422 | coopSleepHandle = null; | ||
1423 | coopTerminationForThisScript = false; | ||
1424 | } | ||
1425 | catch (TypeLoadException) | ||
1426 | { | ||
1427 | coopSleepHandle = new XEngineEventWaitHandle(false, EventResetMode.AutoReset); | ||
1428 | |||
1429 | try | ||
1430 | { | ||
1431 | scriptObj | ||
1432 | = (IScript)m_AppDomains[appDomain].CreateInstanceAndUnwrap( | ||
1433 | assemblyName.FullName, | ||
1434 | "SecondLife.XEngineScript", | ||
1435 | false, | ||
1436 | BindingFlags.Default, | ||
1437 | null, | ||
1438 | new object[] { coopSleepHandle }, | ||
1439 | null, | ||
1440 | null); | ||
1441 | } | ||
1442 | catch (Exception e2) | ||
1443 | { | ||
1444 | m_log.Error( | ||
1445 | string.Format( | ||
1446 | "[XENGINE]: Could not load previous SecondLife.XEngineScript from assembly {0} in {1}. Not starting. Exception ", | ||
1447 | assemblyName.FullName, World.Name), | ||
1448 | e2); | ||
1449 | |||
1450 | return false; | ||
1451 | } | ||
1452 | |||
1453 | coopTerminationForThisScript = true; | ||
1454 | } | ||
1455 | } | ||
1456 | |||
1457 | if (m_coopTermination != coopTerminationForThisScript && !HaveNotifiedLogOfScriptStopMistmatch) | ||
1458 | { | ||
1459 | // Notify the log that there is at least one script compile that doesn't match the | ||
1460 | // ScriptStopStrategy. Operator has to manually delete old DLLs - we can't do this on Windows | ||
1461 | // once the assembly has been loaded evne if the instantiation of a class was unsuccessful. | ||
1462 | m_log.WarnFormat( | ||
1463 | "[XEngine]: At least one existing compiled script DLL in {0} has {1} as ScriptStopStrategy whereas config setting is {2}." | ||
1464 | + "\nContinuing with script compiled strategy but to remove this message please set [XEngine] DeleteScriptsOnStartup = true for one simulator session to remove old script DLLs (script state will not be lost).", | ||
1465 | World.Name, coopTerminationForThisScript ? "co-op" : "abort", m_coopTermination ? "co-op" : "abort"); | ||
1466 | |||
1467 | HaveNotifiedLogOfScriptStopMistmatch = true; | ||
1468 | } | ||
1469 | |||
1284 | instance = new ScriptInstance(this, part, | 1470 | instance = new ScriptInstance(this, part, |
1285 | itemID, assetID, assembly, | 1471 | item, |
1286 | m_AppDomains[appDomain], | 1472 | startParam, postOnRez, |
1287 | part.ParentGroup.RootPart.Name, | 1473 | m_MaxScriptQueue); |
1288 | item.Name, startParam, postOnRez, | 1474 | |
1289 | stateSource, m_MaxScriptQueue); | 1475 | if ( |
1476 | !instance.Load( | ||
1477 | scriptObj, coopSleepHandle, assemblyPath, | ||
1478 | Path.Combine(ScriptEnginePath, World.RegionInfo.RegionID.ToString()), stateSource, coopTerminationForThisScript)) | ||
1479 | return false; | ||
1290 | 1480 | ||
1291 | // if (DebugLevel >= 1) | 1481 | // if (DebugLevel >= 1) |
1292 | // m_log.DebugFormat( | 1482 | // m_log.DebugFormat( |
@@ -1317,11 +1507,11 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
1317 | } | 1507 | } |
1318 | 1508 | ||
1319 | if (!m_Assemblies.ContainsKey(assetID)) | 1509 | if (!m_Assemblies.ContainsKey(assetID)) |
1320 | m_Assemblies[assetID] = assembly; | 1510 | m_Assemblies[assetID] = assemblyPath; |
1321 | 1511 | ||
1322 | lock (m_AddingAssemblies) | 1512 | lock (m_AddingAssemblies) |
1323 | { | 1513 | { |
1324 | m_AddingAssemblies[assembly]--; | 1514 | m_AddingAssemblies[assemblyPath]--; |
1325 | } | 1515 | } |
1326 | 1516 | ||
1327 | if (instance != null) | 1517 | if (instance != null) |
@@ -1359,11 +1549,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
1359 | m_Scripts.Remove(itemID); | 1549 | m_Scripts.Remove(itemID); |
1360 | } | 1550 | } |
1361 | 1551 | ||
1362 | instance.ClearQueue(); | 1552 | instance.Stop(m_WaitForEventCompletionOnScriptStop, true); |
1363 | |||
1364 | instance.Stop(m_WaitForEventCompletionOnScriptStop); | ||
1365 | |||
1366 | // bool objectRemoved = false; | ||
1367 | 1553 | ||
1368 | lock (m_PrimObjects) | 1554 | lock (m_PrimObjects) |
1369 | { | 1555 | { |
@@ -1376,14 +1562,13 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
1376 | 1562 | ||
1377 | // If there are no more scripts, remove prim | 1563 | // If there are no more scripts, remove prim |
1378 | if (m_PrimObjects[localID].Count == 0) | 1564 | if (m_PrimObjects[localID].Count == 0) |
1379 | { | ||
1380 | m_PrimObjects.Remove(localID); | 1565 | m_PrimObjects.Remove(localID); |
1381 | // objectRemoved = true; | ||
1382 | } | ||
1383 | } | 1566 | } |
1384 | } | 1567 | } |
1385 | 1568 | ||
1386 | instance.RemoveState(); | 1569 | if (instance.StatePersistedHere) |
1570 | instance.RemoveState(); | ||
1571 | |||
1387 | instance.DestroyScriptInstance(); | 1572 | instance.DestroyScriptInstance(); |
1388 | 1573 | ||
1389 | m_DomainScripts[instance.AppDomain].Remove(instance.ItemID); | 1574 | m_DomainScripts[instance.AppDomain].Remove(instance.ItemID); |
@@ -1489,7 +1674,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
1489 | startInfo.MaxWorkerThreads = maxThreads; | 1674 | startInfo.MaxWorkerThreads = maxThreads; |
1490 | startInfo.MinWorkerThreads = minThreads; | 1675 | startInfo.MinWorkerThreads = minThreads; |
1491 | startInfo.ThreadPriority = threadPriority;; | 1676 | startInfo.ThreadPriority = threadPriority;; |
1492 | startInfo.StackSize = stackSize; | 1677 | startInfo.MaxStackSize = stackSize; |
1493 | startInfo.StartSuspended = true; | 1678 | startInfo.StartSuspended = true; |
1494 | 1679 | ||
1495 | m_ThreadPool = new SmartThreadPool(startInfo); | 1680 | m_ThreadPool = new SmartThreadPool(startInfo); |
@@ -1516,7 +1701,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
1516 | 1701 | ||
1517 | IScriptInstance instance = (ScriptInstance) parms; | 1702 | IScriptInstance instance = (ScriptInstance) parms; |
1518 | 1703 | ||
1519 | //m_log.DebugFormat("[XEngine]: Processing event for {0}", instance); | 1704 | // m_log.DebugFormat("[XEngine]: Processing event for {0}", instance); |
1520 | 1705 | ||
1521 | return instance.EventProcessor(); | 1706 | return instance.EventProcessor(); |
1522 | } | 1707 | } |
@@ -1681,9 +1866,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
1681 | public bool GetScriptState(UUID itemID) | 1866 | public bool GetScriptState(UUID itemID) |
1682 | { | 1867 | { |
1683 | IScriptInstance instance = GetInstance(itemID); | 1868 | IScriptInstance instance = GetInstance(itemID); |
1684 | if (instance != null) | 1869 | return instance != null && instance.Running; |
1685 | return instance.Running; | ||
1686 | return false; | ||
1687 | } | 1870 | } |
1688 | 1871 | ||
1689 | public void ApiResetScript(UUID itemID) | 1872 | public void ApiResetScript(UUID itemID) |
@@ -1691,6 +1874,12 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
1691 | IScriptInstance instance = GetInstance(itemID); | 1874 | IScriptInstance instance = GetInstance(itemID); |
1692 | if (instance != null) | 1875 | if (instance != null) |
1693 | instance.ApiResetScript(); | 1876 | instance.ApiResetScript(); |
1877 | |||
1878 | // Send the new number of threads that are in use by the thread | ||
1879 | // pool, I believe that by adding them to the locations where the | ||
1880 | // script is changing states that I will catch all changes to the | ||
1881 | // thread pool | ||
1882 | m_Scene.setThreadCount(m_ThreadPool.InUseThreads); | ||
1694 | } | 1883 | } |
1695 | 1884 | ||
1696 | public void ResetScript(UUID itemID) | 1885 | public void ResetScript(UUID itemID) |
@@ -1698,6 +1887,12 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
1698 | IScriptInstance instance = GetInstance(itemID); | 1887 | IScriptInstance instance = GetInstance(itemID); |
1699 | if (instance != null) | 1888 | if (instance != null) |
1700 | instance.ResetScript(m_WaitForEventCompletionOnScriptStop); | 1889 | instance.ResetScript(m_WaitForEventCompletionOnScriptStop); |
1890 | |||
1891 | // Send the new number of threads that are in use by the thread | ||
1892 | // pool, I believe that by adding them to the locations where the | ||
1893 | // script is changing states that I will catch all changes to the | ||
1894 | // thread pool | ||
1895 | m_Scene.setThreadCount(m_ThreadPool.InUseThreads); | ||
1701 | } | 1896 | } |
1702 | 1897 | ||
1703 | public void StartScript(UUID itemID) | 1898 | public void StartScript(UUID itemID) |
@@ -1707,6 +1902,12 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
1707 | instance.Start(); | 1902 | instance.Start(); |
1708 | else | 1903 | else |
1709 | m_runFlags.AddOrUpdate(itemID, true, 240); | 1904 | m_runFlags.AddOrUpdate(itemID, true, 240); |
1905 | |||
1906 | // Send the new number of threads that are in use by the thread | ||
1907 | // pool, I believe that by adding them to the locations where the | ||
1908 | // script is changing states that I will catch all changes to the | ||
1909 | // thread pool | ||
1910 | m_Scene.setThreadCount(m_ThreadPool.InUseThreads); | ||
1710 | } | 1911 | } |
1711 | 1912 | ||
1712 | public void StopScript(UUID itemID) | 1913 | public void StopScript(UUID itemID) |
@@ -1714,17 +1915,29 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
1714 | IScriptInstance instance = GetInstance(itemID); | 1915 | IScriptInstance instance = GetInstance(itemID); |
1715 | 1916 | ||
1716 | if (instance != null) | 1917 | if (instance != null) |
1918 | { | ||
1919 | lock (instance.EventQueue) | ||
1920 | instance.StayStopped = true; // the script was stopped explicitly | ||
1921 | |||
1717 | instance.Stop(m_WaitForEventCompletionOnScriptStop); | 1922 | instance.Stop(m_WaitForEventCompletionOnScriptStop); |
1923 | } | ||
1718 | else | 1924 | else |
1925 | { | ||
1926 | // m_log.DebugFormat("[XENGINE]: Could not find script with ID {0} to stop in {1}", itemID, World.Name); | ||
1719 | m_runFlags.AddOrUpdate(itemID, false, 240); | 1927 | m_runFlags.AddOrUpdate(itemID, false, 240); |
1928 | } | ||
1929 | |||
1930 | // Send the new number of threads that are in use by the thread | ||
1931 | // pool, I believe that by adding them to the locations where the | ||
1932 | // script is changing states that I will catch all changes to the | ||
1933 | // thread pool | ||
1934 | m_Scene.setThreadCount(m_ThreadPool.InUseThreads); | ||
1720 | } | 1935 | } |
1721 | 1936 | ||
1722 | public DetectParams GetDetectParams(UUID itemID, int idx) | 1937 | public DetectParams GetDetectParams(UUID itemID, int idx) |
1723 | { | 1938 | { |
1724 | IScriptInstance instance = GetInstance(itemID); | 1939 | IScriptInstance instance = GetInstance(itemID); |
1725 | if (instance != null) | 1940 | return instance != null ? instance.GetDetectParams(idx) : null; |
1726 | return instance.GetDetectParams(idx); | ||
1727 | return null; | ||
1728 | } | 1941 | } |
1729 | 1942 | ||
1730 | public void SetMinEventDelay(UUID itemID, double delay) | 1943 | public void SetMinEventDelay(UUID itemID, double delay) |
@@ -1737,9 +1950,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
1737 | public UUID GetDetectID(UUID itemID, int idx) | 1950 | public UUID GetDetectID(UUID itemID, int idx) |
1738 | { | 1951 | { |
1739 | IScriptInstance instance = GetInstance(itemID); | 1952 | IScriptInstance instance = GetInstance(itemID); |
1740 | if (instance != null) | 1953 | return instance != null ? instance.GetDetectID(idx) : UUID.Zero; |
1741 | return instance.GetDetectID(idx); | ||
1742 | return UUID.Zero; | ||
1743 | } | 1954 | } |
1744 | 1955 | ||
1745 | public void SetState(UUID itemID, string newState) | 1956 | public void SetState(UUID itemID, string newState) |
@@ -1753,9 +1964,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
1753 | public int GetStartParameter(UUID itemID) | 1964 | public int GetStartParameter(UUID itemID) |
1754 | { | 1965 | { |
1755 | IScriptInstance instance = GetInstance(itemID); | 1966 | IScriptInstance instance = GetInstance(itemID); |
1756 | if (instance == null) | 1967 | return instance == null ? 0 : instance.StartParam; |
1757 | return 0; | ||
1758 | return instance.StartParam; | ||
1759 | } | 1968 | } |
1760 | 1969 | ||
1761 | public void OnShutdown() | 1970 | public void OnShutdown() |
@@ -1789,9 +1998,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
1789 | public IScriptApi GetApi(UUID itemID, string name) | 1998 | public IScriptApi GetApi(UUID itemID, string name) |
1790 | { | 1999 | { |
1791 | IScriptInstance instance = GetInstance(itemID); | 2000 | IScriptInstance instance = GetInstance(itemID); |
1792 | if (instance == null) | 2001 | return instance == null ? null : instance.GetApi(name); |
1793 | return null; | ||
1794 | return instance.GetApi(name); | ||
1795 | } | 2002 | } |
1796 | 2003 | ||
1797 | public void OnGetScriptRunning(IClientAPI controllingClient, UUID objectID, UUID itemID) | 2004 | public void OnGetScriptRunning(IClientAPI controllingClient, UUID objectID, UUID itemID) |
@@ -2090,7 +2297,8 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
2090 | catch (IOException ex) | 2297 | catch (IOException ex) |
2091 | { | 2298 | { |
2092 | // if there already exists a file at that location, it may be locked. | 2299 | // if there already exists a file at that location, it may be locked. |
2093 | m_log.ErrorFormat("[XEngine]: Linemap file {0} already exists! {1}", mappath, ex.Message); | 2300 | m_log.Error( |
2301 | string.Format("[XEngine]: Linemap file {0} could not be written. Exception ", mappath), ex); | ||
2094 | } | 2302 | } |
2095 | } | 2303 | } |
2096 | } | 2304 | } |
@@ -2116,6 +2324,9 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
2116 | m_log.ErrorFormat("[XEngine]: Error whilst writing state file {0}, {1}", statepath, ex.Message); | 2324 | m_log.ErrorFormat("[XEngine]: Error whilst writing state file {0}, {1}", statepath, ex.Message); |
2117 | } | 2325 | } |
2118 | 2326 | ||
2327 | // m_log.DebugFormat( | ||
2328 | // "[XEngine]: Wrote state for script item with ID {0} at {1} in {2}", itemID, statepath, m_Scene.Name); | ||
2329 | |||
2119 | return true; | 2330 | return true; |
2120 | } | 2331 | } |
2121 | 2332 | ||
@@ -2137,7 +2348,6 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
2137 | 2348 | ||
2138 | public Dictionary<uint, float> GetObjectScriptsExecutionTimes() | 2349 | public Dictionary<uint, float> GetObjectScriptsExecutionTimes() |
2139 | { | 2350 | { |
2140 | long tickNow = Util.EnvironmentTickCount(); | ||
2141 | Dictionary<uint, float> topScripts = new Dictionary<uint, float>(); | 2351 | Dictionary<uint, float> topScripts = new Dictionary<uint, float>(); |
2142 | 2352 | ||
2143 | lock (m_Scripts) | 2353 | lock (m_Scripts) |
@@ -2147,7 +2357,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
2147 | if (!topScripts.ContainsKey(si.LocalID)) | 2357 | if (!topScripts.ContainsKey(si.LocalID)) |
2148 | topScripts[si.RootLocalID] = 0; | 2358 | topScripts[si.RootLocalID] = 0; |
2149 | 2359 | ||
2150 | topScripts[si.RootLocalID] += CalculateAdjustedExectionTime(si, tickNow); | 2360 | topScripts[si.RootLocalID] += GetExectionTime(si); |
2151 | } | 2361 | } |
2152 | } | 2362 | } |
2153 | 2363 | ||
@@ -2161,7 +2371,6 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
2161 | return 0.0f; | 2371 | return 0.0f; |
2162 | } | 2372 | } |
2163 | float time = 0.0f; | 2373 | float time = 0.0f; |
2164 | long tickNow = Util.EnvironmentTickCount(); | ||
2165 | IScriptInstance si; | 2374 | IScriptInstance si; |
2166 | // Calculate the time for all scripts that this engine is executing | 2375 | // Calculate the time for all scripts that this engine is executing |
2167 | // Ignore any others | 2376 | // Ignore any others |
@@ -2170,36 +2379,15 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
2170 | si = GetInstance(id); | 2379 | si = GetInstance(id); |
2171 | if (si != null && si.Running) | 2380 | if (si != null && si.Running) |
2172 | { | 2381 | { |
2173 | time += CalculateAdjustedExectionTime(si, tickNow); | 2382 | time += GetExectionTime(si); |
2174 | } | 2383 | } |
2175 | } | 2384 | } |
2176 | return time; | 2385 | return time; |
2177 | } | 2386 | } |
2178 | 2387 | ||
2179 | private float CalculateAdjustedExectionTime(IScriptInstance si, long tickNow) | 2388 | private float GetExectionTime(IScriptInstance si) |
2180 | { | 2389 | { |
2181 | long ticksElapsed = tickNow - si.MeasurementPeriodTickStart; | 2390 | return (float)si.ExecutionTime.GetSumTime().TotalMilliseconds; |
2182 | |||
2183 | // Avoid divide by zero | ||
2184 | if (ticksElapsed == 0) | ||
2185 | ticksElapsed = 1; | ||
2186 | |||
2187 | // Scale execution time to the ideal 55 fps frame time for these reasons. | ||
2188 | // | ||
2189 | // 1) XEngine does not execute scripts per frame, unlike other script engines. Hence, there is no | ||
2190 | // 'script execution time per frame', which is the original purpose of this value. | ||
2191 | // | ||
2192 | // 2) Giving the raw execution times is misleading since scripts start at different times, making | ||
2193 | // it impossible to compare scripts. | ||
2194 | // | ||
2195 | // 3) Scaling the raw execution time to the time that the script has been running is better but | ||
2196 | // is still misleading since a script that has just been rezzed may appear to have been running | ||
2197 | // for much longer. | ||
2198 | // | ||
2199 | // 4) Hence, we scale execution time to an idealised frame time (55 fps). This is also not perfect | ||
2200 | // since the figure does not represent actual execution time and very hard running scripts will | ||
2201 | // never exceed 18ms (though this is a very high number for script execution so is a warning sign). | ||
2202 | return ((float)si.MeasurementPeriodExecutionTime / ticksElapsed) * 18.1818f; | ||
2203 | } | 2391 | } |
2204 | 2392 | ||
2205 | public void SuspendScript(UUID itemID) | 2393 | public void SuspendScript(UUID itemID) |
@@ -2211,6 +2399,12 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
2211 | instance.Suspend(); | 2399 | instance.Suspend(); |
2212 | // else | 2400 | // else |
2213 | // m_log.DebugFormat("[XEngine]: Could not find script with ID {0} to resume", itemID); | 2401 | // m_log.DebugFormat("[XEngine]: Could not find script with ID {0} to resume", itemID); |
2402 | |||
2403 | // Send the new number of threads that are in use by the thread | ||
2404 | // pool, I believe that by adding them to the locations where the | ||
2405 | // script is changing states that I will catch all changes to the | ||
2406 | // thread pool | ||
2407 | m_Scene.setThreadCount(m_ThreadPool.InUseThreads); | ||
2214 | } | 2408 | } |
2215 | 2409 | ||
2216 | public void ResumeScript(UUID itemID) | 2410 | public void ResumeScript(UUID itemID) |
@@ -2222,6 +2416,12 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
2222 | instance.Resume(); | 2416 | instance.Resume(); |
2223 | // else | 2417 | // else |
2224 | // m_log.DebugFormat("[XEngine]: Could not find script with ID {0} to resume", itemID); | 2418 | // m_log.DebugFormat("[XEngine]: Could not find script with ID {0} to resume", itemID); |
2419 | |||
2420 | // Send the new number of threads that are in use by the thread | ||
2421 | // pool, I believe that by adding them to the locations where the | ||
2422 | // script is changing states that I will catch all changes to the | ||
2423 | // thread pool | ||
2424 | m_Scene.setThreadCount(m_ThreadPool.InUseThreads); | ||
2225 | } | 2425 | } |
2226 | 2426 | ||
2227 | public bool HasScript(UUID itemID, out bool running) | 2427 | public bool HasScript(UUID itemID, out bool running) |
@@ -2235,5 +2435,30 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
2235 | running = instance.Running; | 2435 | running = instance.Running; |
2236 | return true; | 2436 | return true; |
2237 | } | 2437 | } |
2438 | |||
2439 | public void SleepScript(UUID itemID, int delay) | ||
2440 | { | ||
2441 | IScriptInstance instance = GetInstance(itemID); | ||
2442 | if (instance == null) | ||
2443 | return; | ||
2444 | |||
2445 | instance.ExecutionTimer.Stop(); | ||
2446 | try | ||
2447 | { | ||
2448 | if (instance.CoopWaitHandle != null) | ||
2449 | { | ||
2450 | if (instance.CoopWaitHandle.WaitOne(delay)) | ||
2451 | throw new ScriptCoopStopException(); | ||
2452 | } | ||
2453 | else | ||
2454 | { | ||
2455 | Thread.Sleep(delay); | ||
2456 | } | ||
2457 | } | ||
2458 | finally | ||
2459 | { | ||
2460 | instance.ExecutionTimer.Start(); | ||
2461 | } | ||
2462 | } | ||
2238 | } | 2463 | } |
2239 | } | 2464 | } |