aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs
diff options
context:
space:
mode:
authorDavid Walter Seikel2016-11-03 21:44:39 +1000
committerDavid Walter Seikel2016-11-03 21:44:39 +1000
commit134f86e8d5c414409631b25b8c6f0ee45fbd8631 (patch)
tree216b89d3fb89acfb81be1e440c25c41ab09fa96d /OpenSim/Region/ScriptEngine/XEngine/XEngine.cs
parentMore changing to production grid. Double oops. (diff)
downloadopensim-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.cs609
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;
42using log4net; 42using log4net;
43using Nini.Config; 43using Nini.Config;
44using Amib.Threading; 44using Amib.Threading;
45using Mono.Addins;
45using OpenSim.Framework; 46using OpenSim.Framework;
46using OpenSim.Framework.Console; 47using OpenSim.Framework.Console;
47using OpenSim.Region.Framework.Scenes; 48using OpenSim.Region.Framework.Scenes;
48using OpenSim.Region.Framework.Interfaces; 49using OpenSim.Region.Framework.Interfaces;
50using OpenSim.Region.ScriptEngine.Interfaces;
49using OpenSim.Region.ScriptEngine.Shared; 51using OpenSim.Region.ScriptEngine.Shared;
50using OpenSim.Region.ScriptEngine.Shared.CodeTools; 52using OpenSim.Region.ScriptEngine.Shared.CodeTools;
51using OpenSim.Region.ScriptEngine.Shared.Instance; 53using OpenSim.Region.ScriptEngine.Shared.Instance;
52using OpenSim.Region.ScriptEngine.Shared.Api; 54using OpenSim.Region.ScriptEngine.Shared.Api;
53using OpenSim.Region.ScriptEngine.Shared.Api.Plugins; 55using OpenSim.Region.ScriptEngine.Shared.Api.Plugins;
54using OpenSim.Region.ScriptEngine.Interfaces; 56using OpenSim.Region.ScriptEngine.Shared.ScriptBase;
57using OpenSim.Region.ScriptEngine.XEngine.ScriptBase;
55using Timer = OpenSim.Region.ScriptEngine.Shared.Api.Plugins.Timer; 58using Timer = OpenSim.Region.ScriptEngine.Shared.Api.Plugins.Timer;
56 59
57using ScriptCompileQueue = OpenSim.Framework.LocklessQueue<object[]>; 60using ScriptCompileQueue = OpenSim.Framework.LocklessQueue<object[]>;
58 61
59namespace OpenSim.Region.ScriptEngine.XEngine 62namespace 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}