diff options
Diffstat (limited to '')
-rwxr-xr-x[-rw-r--r--] | OpenSim/Region/ScriptEngine/XEngine/XEngine.cs | 529 |
1 files changed, 400 insertions, 129 deletions
diff --git a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs index 1831c39..466c190 100644..100755 --- a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs +++ b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs | |||
@@ -43,6 +43,7 @@ using OpenMetaverse.StructuredData; | |||
43 | using log4net; | 43 | using log4net; |
44 | using Nini.Config; | 44 | using Nini.Config; |
45 | using Amib.Threading; | 45 | using Amib.Threading; |
46 | using Mono.Addins; | ||
46 | using OpenSim.Framework; | 47 | using OpenSim.Framework; |
47 | using OpenSim.Framework.Console; | 48 | using OpenSim.Framework.Console; |
48 | using OpenSim.Region.Framework.Scenes; | 49 | using OpenSim.Region.Framework.Scenes; |
@@ -61,6 +62,7 @@ using ScriptCompileQueue = OpenSim.Framework.LocklessQueue<object[]>; | |||
61 | 62 | ||
62 | namespace OpenSim.Region.ScriptEngine.XEngine | 63 | namespace OpenSim.Region.ScriptEngine.XEngine |
63 | { | 64 | { |
65 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "XEngine")] | ||
64 | public class XEngine : INonSharedRegionModule, IScriptModule, IScriptEngine | 66 | public class XEngine : INonSharedRegionModule, IScriptModule, IScriptEngine |
65 | { | 67 | { |
66 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 68 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
@@ -71,7 +73,13 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
71 | /// <remarks> | 73 | /// <remarks> |
72 | /// If DebugLevel >= 1, then we log every time that a script is started. | 74 | /// If DebugLevel >= 1, then we log every time that a script is started. |
73 | /// </remarks> | 75 | /// </remarks> |
74 | // public int DebugLevel { get; set; } | 76 | public int DebugLevel { get; set; } |
77 | |||
78 | /// <summary> | ||
79 | /// A parameter to allow us to notify the log if at least one script has a compilation that is not compatible | ||
80 | /// with ScriptStopStrategy. | ||
81 | /// </summary> | ||
82 | public bool HaveNotifiedLogOfScriptStopMistmatch { get; private set; } | ||
75 | 83 | ||
76 | private SmartThreadPool m_ThreadPool; | 84 | private SmartThreadPool m_ThreadPool; |
77 | private int m_MaxScriptQueue; | 85 | private int m_MaxScriptQueue; |
@@ -87,6 +95,12 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
87 | /// </summary> | 95 | /// </summary> |
88 | private int m_StartDelay; | 96 | private int m_StartDelay; |
89 | 97 | ||
98 | /// <summary> | ||
99 | /// Are we stopping scripts co-operatively by inserting checks in them at C# compile time (true) or aborting | ||
100 | /// their threads (false)? | ||
101 | /// </summary> | ||
102 | private bool m_coopTermination; | ||
103 | |||
90 | private int m_IdleTimeout; | 104 | private int m_IdleTimeout; |
91 | private int m_StackSize; | 105 | private int m_StackSize; |
92 | private int m_SleepTime; | 106 | private int m_SleepTime; |
@@ -96,7 +110,6 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
96 | private bool m_InitialStartup = true; | 110 | private bool m_InitialStartup = true; |
97 | private int m_ScriptFailCount; // Number of script fails since compile queue was last empty | 111 | private int m_ScriptFailCount; // Number of script fails since compile queue was last empty |
98 | private string m_ScriptErrorMessage; | 112 | private string m_ScriptErrorMessage; |
99 | private Dictionary<string, string> m_uniqueScripts = new Dictionary<string, string>(); | ||
100 | private bool m_AppDomainLoading; | 113 | private bool m_AppDomainLoading; |
101 | private Dictionary<UUID,ArrayList> m_ScriptErrors = | 114 | private Dictionary<UUID,ArrayList> m_ScriptErrors = |
102 | new Dictionary<UUID,ArrayList>(); | 115 | new Dictionary<UUID,ArrayList>(); |
@@ -308,12 +321,13 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
308 | m_ScriptConfig = configSource.Configs["XEngine"]; | 321 | m_ScriptConfig = configSource.Configs["XEngine"]; |
309 | m_ConfigSource = configSource; | 322 | m_ConfigSource = configSource; |
310 | 323 | ||
311 | string rawScriptStopStrategy = m_ScriptConfig.GetString("ScriptStopStrategy", "abort"); | 324 | string rawScriptStopStrategy = m_ScriptConfig.GetString("ScriptStopStrategy", "co-op"); |
312 | 325 | ||
313 | m_log.InfoFormat("[XEngine]: Script stop strategy is {0}", rawScriptStopStrategy); | 326 | m_log.InfoFormat("[XEngine]: Script stop strategy is {0}", rawScriptStopStrategy); |
314 | 327 | ||
315 | if (rawScriptStopStrategy == "co-op") | 328 | if (rawScriptStopStrategy == "co-op") |
316 | { | 329 | { |
330 | m_coopTermination = true; | ||
317 | ScriptClassName = "XEngineScript"; | 331 | ScriptClassName = "XEngineScript"; |
318 | ScriptBaseClassName = typeof(XEngineScriptBase).FullName; | 332 | ScriptBaseClassName = typeof(XEngineScriptBase).FullName; |
319 | ScriptBaseClassParameters = typeof(XEngineScriptBase).GetConstructor(new Type[] { typeof(WaitHandle) }).GetParameters(); | 333 | ScriptBaseClassParameters = typeof(XEngineScriptBase).GetConstructor(new Type[] { typeof(WaitHandle) }).GetParameters(); |
@@ -457,19 +471,19 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
457 | (module, cmdparams) => HandleScriptsAction(cmdparams, HandleStartScript)); | 471 | (module, cmdparams) => HandleScriptsAction(cmdparams, HandleStartScript)); |
458 | 472 | ||
459 | MainConsole.Instance.Commands.AddCommand( | 473 | MainConsole.Instance.Commands.AddCommand( |
460 | "Scripts", false, "debug scripts log", "debug scripts log <item-id> <log-level>", "Extra debug logging for a script", | 474 | "Debug", false, "debug scripts log", "debug scripts log <item-id> <log-level>", "Extra debug logging for a particular script.", |
461 | "Activates or deactivates extra debug logging for the given script.\n" | 475 | "Activates or deactivates extra debug logging for the given script.\n" |
462 | + "Level == 0, deactivate extra debug logging.\n" | 476 | + "Level == 0, deactivate extra debug logging.\n" |
463 | + "Level >= 1, log state changes.\n" | 477 | + "Level >= 1, log state changes.\n" |
464 | + "Level >= 2, log event invocations.\n", | 478 | + "Level >= 2, log event invocations.\n", |
465 | HandleDebugScriptLogCommand); | 479 | HandleDebugScriptLogCommand); |
466 | 480 | ||
467 | // MainConsole.Instance.Commands.AddCommand( | 481 | MainConsole.Instance.Commands.AddCommand( |
468 | // "Debug", false, "debug xengine", "debug xengine [<level>]", | 482 | "Debug", false, "debug xengine log", "debug xengine log [<level>]", |
469 | // "Turn on detailed xengine debugging.", | 483 | "Turn on detailed xengine debugging.", |
470 | // "If level <= 0, then no extra logging is done.\n" | 484 | "If level <= 0, then no extra logging is done.\n" |
471 | // + "If level >= 1, then we log every time that a script is started.", | 485 | + "If level >= 1, then we log every time that a script is started.", |
472 | // HandleDebugLevelCommand); | 486 | HandleDebugLevelCommand); |
473 | } | 487 | } |
474 | 488 | ||
475 | private void HandleDebugScriptLogCommand(string module, string[] args) | 489 | private void HandleDebugScriptLogCommand(string module, string[] args) |
@@ -512,26 +526,26 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
512 | /// </summary> | 526 | /// </summary> |
513 | /// <param name="module"></param> | 527 | /// <param name="module"></param> |
514 | /// <param name="args"></param> | 528 | /// <param name="args"></param> |
515 | // private void HandleDebugLevelCommand(string module, string[] args) | 529 | private void HandleDebugLevelCommand(string module, string[] args) |
516 | // { | 530 | { |
517 | // if (args.Length == 3) | 531 | if (args.Length >= 4) |
518 | // { | 532 | { |
519 | // int newDebug; | 533 | int newDebug; |
520 | // if (int.TryParse(args[2], out newDebug)) | 534 | if (ConsoleUtil.TryParseConsoleNaturalInt(MainConsole.Instance, args[3], out newDebug)) |
521 | // { | 535 | { |
522 | // DebugLevel = newDebug; | 536 | DebugLevel = newDebug; |
523 | // MainConsole.Instance.OutputFormat("Debug level set to {0}", newDebug); | 537 | MainConsole.Instance.OutputFormat("Debug level set to {0} in XEngine for region {1}", newDebug, m_Scene.Name); |
524 | // } | 538 | } |
525 | // } | 539 | } |
526 | // else if (args.Length == 2) | 540 | else if (args.Length == 3) |
527 | // { | 541 | { |
528 | // MainConsole.Instance.OutputFormat("Current debug level is {0}", DebugLevel); | 542 | MainConsole.Instance.OutputFormat("Current debug level is {0}", DebugLevel); |
529 | // } | 543 | } |
530 | // else | 544 | else |
531 | // { | 545 | { |
532 | // MainConsole.Instance.Output("Usage: debug xengine 0..1"); | 546 | MainConsole.Instance.Output("Usage: debug xengine log <level>"); |
533 | // } | 547 | } |
534 | // } | 548 | } |
535 | 549 | ||
536 | /// <summary> | 550 | /// <summary> |
537 | /// Parse the raw item id into a script instance from the command params if it's present. | 551 | /// Parse the raw item id into a script instance from the command params if it's present. |
@@ -631,7 +645,6 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
631 | } | 645 | } |
632 | 646 | ||
633 | sb.AppendFormat("Scripts loaded : {0}\n", scriptsLoaded); | 647 | sb.AppendFormat("Scripts loaded : {0}\n", scriptsLoaded); |
634 | sb.AppendFormat("Unique scripts : {0}\n", m_uniqueScripts.Count); | ||
635 | sb.AppendFormat("Scripts waiting for load : {0}\n", m_CompileQueue.Count); | 648 | sb.AppendFormat("Scripts waiting for load : {0}\n", m_CompileQueue.Count); |
636 | sb.AppendFormat("Max threads : {0}\n", m_ThreadPool.MaxThreads); | 649 | sb.AppendFormat("Max threads : {0}\n", m_ThreadPool.MaxThreads); |
637 | sb.AppendFormat("Min threads : {0}\n", m_ThreadPool.MinThreads); | 650 | sb.AppendFormat("Min threads : {0}\n", m_ThreadPool.MinThreads); |
@@ -754,6 +767,8 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
754 | { | 767 | { |
755 | if (instance.Running) | 768 | if (instance.Running) |
756 | { | 769 | { |
770 | instance.StayStopped = true; // the script was stopped explicitly | ||
771 | |||
757 | instance.Stop(0); | 772 | instance.Stop(0); |
758 | 773 | ||
759 | SceneObjectPart sop = m_Scene.GetSceneObjectPart(instance.ObjectID); | 774 | SceneObjectPart sop = m_Scene.GetSceneObjectPart(instance.ObjectID); |
@@ -778,11 +793,20 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
778 | // | 793 | // |
779 | if (m_Assemblies.ContainsKey(instance.AssetID)) | 794 | if (m_Assemblies.ContainsKey(instance.AssetID)) |
780 | { | 795 | { |
796 | <<<<<<< HEAD | ||
797 | // Force a final state save | ||
798 | // | ||
799 | try | ||
800 | { | ||
801 | if (instance.StatePersistedHere) | ||
802 | instance.SaveState(); | ||
803 | ======= | ||
781 | string assembly = m_Assemblies[instance.AssetID]; | 804 | string assembly = m_Assemblies[instance.AssetID]; |
782 | 805 | ||
783 | try | 806 | try |
784 | { | 807 | { |
785 | instance.SaveState(assembly); | 808 | instance.SaveState(assembly); |
809 | >>>>>>> avn/ubitvar | ||
786 | } | 810 | } |
787 | catch (Exception e) | 811 | catch (Exception e) |
788 | { | 812 | { |
@@ -794,10 +818,16 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
794 | } | 818 | } |
795 | } | 819 | } |
796 | 820 | ||
821 | <<<<<<< HEAD | ||
822 | // Clear the event queue and abort the instance thread | ||
823 | // | ||
824 | instance.Stop(0, true); | ||
825 | ======= | ||
797 | // Clear the event queue and abort the instance thread | 826 | // Clear the event queue and abort the instance thread |
798 | // | 827 | // |
799 | instance.ClearQueue(); | 828 | instance.ClearQueue(); |
800 | instance.Stop(0); | 829 | instance.Stop(0); |
830 | >>>>>>> avn/ubitvar | ||
801 | 831 | ||
802 | // Release events, timer, etc | 832 | // Release events, timer, etc |
803 | // | 833 | // |
@@ -898,6 +928,25 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
898 | 928 | ||
899 | List<IScriptInstance> instances = new List<IScriptInstance>(); | 929 | List<IScriptInstance> instances = new List<IScriptInstance>(); |
900 | 930 | ||
931 | <<<<<<< HEAD | ||
932 | lock (m_Scripts) | ||
933 | { | ||
934 | foreach (IScriptInstance instance in m_Scripts.Values) | ||
935 | { | ||
936 | if (instance.StatePersistedHere) | ||
937 | { | ||
938 | // m_log.DebugFormat( | ||
939 | // "[XEngine]: Adding script {0}.{1}, item UUID {2}, prim UUID {3} in {4} for state persistence", | ||
940 | // instance.PrimName, instance.ScriptName, instance.ItemID, instance.ObjectID, World.Name); | ||
941 | |||
942 | instances.Add(instance); | ||
943 | } | ||
944 | } | ||
945 | } | ||
946 | |||
947 | foreach (IScriptInstance i in instances) | ||
948 | { | ||
949 | ======= | ||
901 | lockScriptsForRead(true); | 950 | lockScriptsForRead(true); |
902 | foreach (IScriptInstance instance in m_Scripts.Values) | 951 | foreach (IScriptInstance instance in m_Scripts.Values) |
903 | instances.Add(instance); | 952 | instances.Add(instance); |
@@ -913,9 +962,10 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
913 | assembly = m_Assemblies[i.AssetID]; | 962 | assembly = m_Assemblies[i.AssetID]; |
914 | 963 | ||
915 | 964 | ||
965 | >>>>>>> avn/ubitvar | ||
916 | try | 966 | try |
917 | { | 967 | { |
918 | i.SaveState(assembly); | 968 | i.SaveState(); |
919 | } | 969 | } |
920 | catch (Exception e) | 970 | catch (Exception e) |
921 | { | 971 | { |
@@ -927,8 +977,6 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
927 | } | 977 | } |
928 | } | 978 | } |
929 | 979 | ||
930 | instances.Clear(); | ||
931 | |||
932 | if (saveTime > 0) | 980 | if (saveTime > 0) |
933 | m_ThreadPool.QueueWorkItem(new WorkItemCallback(this.DoBackup), | 981 | m_ThreadPool.QueueWorkItem(new WorkItemCallback(this.DoBackup), |
934 | new Object[] { saveTime }); | 982 | new Object[] { saveTime }); |
@@ -938,6 +986,14 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
938 | 986 | ||
939 | public void SaveAllState() | 987 | public void SaveAllState() |
940 | { | 988 | { |
989 | DoBackup(new object[] { 0 }); | ||
990 | } | ||
991 | |||
992 | public object DoMaintenance(object p) | ||
993 | { | ||
994 | object[] parms = (object[])p; | ||
995 | int sleepTime = (int)parms[0]; | ||
996 | |||
941 | foreach (IScriptInstance inst in m_Scripts.Values) | 997 | foreach (IScriptInstance inst in m_Scripts.Values) |
942 | { | 998 | { |
943 | if (inst.EventTime() > m_EventLimit) | 999 | if (inst.EventTime() > m_EventLimit) |
@@ -947,14 +1003,6 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
947 | inst.Start(); | 1003 | inst.Start(); |
948 | } | 1004 | } |
949 | } | 1005 | } |
950 | } | ||
951 | |||
952 | public object DoMaintenance(object p) | ||
953 | { | ||
954 | object[] parms = (object[])p; | ||
955 | int sleepTime = (int)parms[0]; | ||
956 | |||
957 | SaveAllState(); | ||
958 | 1006 | ||
959 | System.Threading.Thread.Sleep(sleepTime); | 1007 | System.Threading.Thread.Sleep(sleepTime); |
960 | 1008 | ||
@@ -1032,8 +1080,6 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
1032 | if (restOfFirstLine.StartsWith("c#") | 1080 | if (restOfFirstLine.StartsWith("c#") |
1033 | || restOfFirstLine.StartsWith("vb") | 1081 | || restOfFirstLine.StartsWith("vb") |
1034 | || restOfFirstLine.StartsWith("lsl") | 1082 | || restOfFirstLine.StartsWith("lsl") |
1035 | || restOfFirstLine.StartsWith("js") | ||
1036 | || restOfFirstLine.StartsWith("yp") | ||
1037 | || restOfFirstLine.Length == 0) | 1083 | || restOfFirstLine.Length == 0) |
1038 | warnRunningInXEngine = true; | 1084 | warnRunningInXEngine = true; |
1039 | 1085 | ||
@@ -1067,12 +1113,6 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
1067 | if (engine != ScriptEngineName) | 1113 | if (engine != ScriptEngineName) |
1068 | return; | 1114 | return; |
1069 | 1115 | ||
1070 | // If we've seen this exact script text before, use that reference instead | ||
1071 | if (m_uniqueScripts.ContainsKey(script)) | ||
1072 | script = m_uniqueScripts[script]; | ||
1073 | else | ||
1074 | m_uniqueScripts[script] = script; | ||
1075 | |||
1076 | Object[] parms = new Object[]{localID, itemID, script, startParam, postOnRez, (StateSource)stateSource}; | 1116 | Object[] parms = new Object[]{localID, itemID, script, startParam, postOnRez, (StateSource)stateSource}; |
1077 | 1117 | ||
1078 | if (stateSource == (int)StateSource.ScriptedRez) | 1118 | if (stateSource == (int)StateSource.ScriptedRez) |
@@ -1086,11 +1126,12 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
1086 | } | 1126 | } |
1087 | else | 1127 | else |
1088 | { | 1128 | { |
1089 | m_CompileQueue.Enqueue(parms); | ||
1090 | lock (m_CompileDict) | 1129 | lock (m_CompileDict) |
1091 | { | ||
1092 | m_CompileDict[itemID] = 0; | 1130 | m_CompileDict[itemID] = 0; |
1093 | } | 1131 | |
1132 | // This must occur after the m_CompileDict so that an existing compile thread cannot hit the check | ||
1133 | // in DoOnRezScript() before m_CompileDict has been updated. | ||
1134 | m_CompileQueue.Enqueue(parms); | ||
1094 | 1135 | ||
1095 | // m_log.DebugFormat("[XEngine]: Added script {0} to compile queue", itemID); | 1136 | // m_log.DebugFormat("[XEngine]: Added script {0} to compile queue", itemID); |
1096 | 1137 | ||
@@ -1112,49 +1153,81 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
1112 | 1153 | ||
1113 | public Object DoOnRezScriptQueue(Object dummy) | 1154 | public Object DoOnRezScriptQueue(Object dummy) |
1114 | { | 1155 | { |
1115 | if (m_InitialStartup) | 1156 | try |
1116 | { | 1157 | { |
1117 | // This delay exists to stop mono problems where script compilation and startup would stop the sim | 1158 | if (m_InitialStartup) |
1118 | // working properly for the session. | 1159 | { |
1119 | System.Threading.Thread.Sleep(m_StartDelay); | 1160 | // This delay exists to stop mono problems where script compilation and startup would stop the sim |
1161 | // working properly for the session. | ||
1162 | System.Threading.Thread.Sleep(m_StartDelay); | ||
1120 | 1163 | ||
1121 | m_log.InfoFormat("[XEngine]: Performing initial script startup on {0}", m_Scene.Name); | 1164 | m_log.InfoFormat("[XEngine]: Performing initial script startup on {0}", m_Scene.Name); |
1122 | } | 1165 | } |
1123 | 1166 | ||
1124 | object[] o; | 1167 | object[] o; |
1125 | 1168 | ||
1126 | int scriptsStarted = 0; | 1169 | int scriptsStarted = 0; |
1127 | 1170 | ||
1128 | while (m_CompileQueue.Dequeue(out o)) | 1171 | while (m_CompileQueue.Dequeue(out o)) |
1129 | { | ||
1130 | if (DoOnRezScript(o)) | ||
1131 | { | 1172 | { |
1132 | scriptsStarted++; | 1173 | try |
1174 | { | ||
1175 | if (DoOnRezScript(o)) | ||
1176 | { | ||
1177 | scriptsStarted++; | ||
1133 | 1178 | ||
1134 | if (m_InitialStartup) | 1179 | if (m_InitialStartup) |
1135 | if (scriptsStarted % 50 == 0) | 1180 | if (scriptsStarted % 50 == 0) |
1136 | m_log.InfoFormat( | 1181 | m_log.InfoFormat( |
1137 | "[XEngine]: Started {0} scripts in {1}", scriptsStarted, m_Scene.Name); | 1182 | "[XEngine]: Started {0} scripts in {1}", scriptsStarted, m_Scene.Name); |
1183 | } | ||
1184 | } | ||
1185 | catch (Exception e) | ||
1186 | { | ||
1187 | m_log.Error( | ||
1188 | string.Format( | ||
1189 | "[XEngine]: Failure in DoOnRezScriptQueue() for item {0} in {1}. Continuing. Exception ", | ||
1190 | o[1], m_Scene.Name), | ||
1191 | e); | ||
1192 | } | ||
1138 | } | 1193 | } |
1139 | } | ||
1140 | 1194 | ||
1141 | if (m_InitialStartup) | 1195 | if (m_InitialStartup) |
1142 | m_log.InfoFormat( | 1196 | m_log.InfoFormat( |
1143 | "[XEngine]: Completed starting {0} scripts on {1}", scriptsStarted, m_Scene.Name); | 1197 | "[XEngine]: Completed starting {0} scripts on {1}", scriptsStarted, m_Scene.Name); |
1144 | 1198 | ||
1145 | // NOTE: Despite having a lockless queue, this lock is required | 1199 | } |
1146 | // to make sure there is never no compile thread while there | 1200 | catch (Exception e) |
1147 | // are still scripts to compile. This could otherwise happen | 1201 | { |
1148 | // due to a race condition | 1202 | m_log.Error( |
1149 | // | 1203 | string.Format("[XEngine]: Failure in DoOnRezScriptQueue() in {0}. Exception ", m_Scene.Name), e); |
1150 | lock (m_CompileQueue) | 1204 | } |
1151 | m_CurrentCompile = null; | 1205 | finally |
1206 | { | ||
1207 | // FIXME: On failure we must trigger this even if the compile queue is not actually empty so that the | ||
1208 | // RegionReadyModule is not forever waiting. This event really needs a different name. | ||
1209 | m_Scene.EventManager.TriggerEmptyScriptCompileQueue(m_ScriptFailCount, | ||
1210 | m_ScriptErrorMessage); | ||
1152 | 1211 | ||
1153 | m_Scene.EventManager.TriggerEmptyScriptCompileQueue(m_ScriptFailCount, | 1212 | m_ScriptFailCount = 0; |
1154 | m_ScriptErrorMessage); | 1213 | m_InitialStartup = false; |
1155 | 1214 | ||
1156 | m_ScriptFailCount = 0; | 1215 | // NOTE: Despite having a lockless queue, this lock is required |
1157 | m_InitialStartup = false; | 1216 | // to make sure there is never no compile thread while there |
1217 | // are still scripts to compile. This could otherwise happen | ||
1218 | // due to a race condition | ||
1219 | // | ||
1220 | lock (m_CompileQueue) | ||
1221 | { | ||
1222 | m_CurrentCompile = null; | ||
1223 | |||
1224 | // This is to avoid a situation where the m_CompileQueue while loop above could complete but | ||
1225 | // OnRezScript() place a new script on the queue and check m_CurrentCompile = null before we hit | ||
1226 | // this section. | ||
1227 | if (m_CompileQueue.Count > 0) | ||
1228 | m_CurrentCompile = m_ThreadPool.QueueWorkItem(DoOnRezScriptQueue, null); | ||
1229 | } | ||
1230 | } | ||
1158 | 1231 | ||
1159 | return null; | 1232 | return null; |
1160 | } | 1233 | } |
@@ -1201,16 +1274,17 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
1201 | return false; | 1274 | return false; |
1202 | } | 1275 | } |
1203 | 1276 | ||
1204 | m_log.DebugFormat( | 1277 | if (DebugLevel > 0) |
1205 | "[XEngine]: Loading script {0}.{1}, item UUID {2}, prim UUID {3} @ {4}.{5}", | 1278 | m_log.DebugFormat( |
1206 | part.ParentGroup.RootPart.Name, item.Name, itemID, part.UUID, | 1279 | "[XEngine]: Loading script {0}.{1}, item UUID {2}, prim UUID {3} @ {4}.{5}", |
1207 | part.ParentGroup.RootPart.AbsolutePosition, part.ParentGroup.Scene.RegionInfo.RegionName); | 1280 | part.ParentGroup.RootPart.Name, item.Name, itemID, part.UUID, |
1281 | part.ParentGroup.RootPart.AbsolutePosition, part.ParentGroup.Scene.RegionInfo.RegionName); | ||
1208 | 1282 | ||
1209 | UUID assetID = item.AssetID; | 1283 | UUID assetID = item.AssetID; |
1210 | 1284 | ||
1211 | ScenePresence presence = m_Scene.GetScenePresence(item.OwnerID); | 1285 | ScenePresence presence = m_Scene.GetScenePresence(item.OwnerID); |
1212 | 1286 | ||
1213 | string assembly = ""; | 1287 | string assemblyPath = ""; |
1214 | 1288 | ||
1215 | Culture.SetCurrentCulture(); | 1289 | Culture.SetCurrentCulture(); |
1216 | 1290 | ||
@@ -1222,12 +1296,16 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
1222 | { | 1296 | { |
1223 | lock (m_AddingAssemblies) | 1297 | lock (m_AddingAssemblies) |
1224 | { | 1298 | { |
1225 | m_Compiler.PerformScriptCompile(script, assetID.ToString(), item.OwnerID, out assembly, out linemap); | 1299 | m_Compiler.PerformScriptCompile(script, assetID.ToString(), item.OwnerID, out assemblyPath, out linemap); |
1226 | 1300 | ||
1227 | if (!m_AddingAssemblies.ContainsKey(assembly)) { | 1301 | // m_log.DebugFormat( |
1228 | m_AddingAssemblies[assembly] = 1; | 1302 | // "[XENGINE]: Found assembly path {0} onrez {1} in {2}", |
1303 | // assemblyPath, item.ItemID, World.Name); | ||
1304 | |||
1305 | if (!m_AddingAssemblies.ContainsKey(assemblyPath)) { | ||
1306 | m_AddingAssemblies[assemblyPath] = 1; | ||
1229 | } else { | 1307 | } else { |
1230 | m_AddingAssemblies[assembly]++; | 1308 | m_AddingAssemblies[assemblyPath]++; |
1231 | } | 1309 | } |
1232 | } | 1310 | } |
1233 | 1311 | ||
@@ -1387,11 +1465,156 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
1387 | } | 1465 | } |
1388 | else | 1466 | else |
1389 | { | 1467 | { |
1468 | <<<<<<< HEAD | ||
1469 | m_log.ErrorFormat("[XEngine] Exception creating app domain:\n {0}", e.ToString()); | ||
1470 | m_ScriptErrorMessage += "Exception creating app domain:\n"; | ||
1471 | m_ScriptFailCount++; | ||
1472 | lock (m_AddingAssemblies) | ||
1473 | { | ||
1474 | m_AddingAssemblies[assemblyPath]--; | ||
1475 | } | ||
1476 | return false; | ||
1477 | ======= | ||
1390 | sandbox = AppDomain.CurrentDomain; | 1478 | sandbox = AppDomain.CurrentDomain; |
1479 | >>>>>>> avn/ubitvar | ||
1480 | } | ||
1481 | |||
1482 | <<<<<<< HEAD | ||
1483 | IScript scriptObj = null; | ||
1484 | EventWaitHandle coopSleepHandle; | ||
1485 | bool coopTerminationForThisScript; | ||
1486 | |||
1487 | // Set up assembly name to point to the appropriate scriptEngines directory | ||
1488 | AssemblyName assemblyName = new AssemblyName(Path.GetFileNameWithoutExtension(assemblyPath)); | ||
1489 | assemblyName.CodeBase = Path.GetDirectoryName(assemblyPath); | ||
1490 | |||
1491 | if (m_coopTermination) | ||
1492 | { | ||
1493 | try | ||
1494 | { | ||
1495 | coopSleepHandle = new XEngineEventWaitHandle(false, EventResetMode.AutoReset); | ||
1496 | |||
1497 | scriptObj | ||
1498 | = (IScript)m_AppDomains[appDomain].CreateInstanceAndUnwrap( | ||
1499 | assemblyName.FullName, | ||
1500 | "SecondLife.XEngineScript", | ||
1501 | false, | ||
1502 | BindingFlags.Default, | ||
1503 | null, | ||
1504 | new object[] { coopSleepHandle }, | ||
1505 | null, | ||
1506 | null); | ||
1507 | |||
1508 | coopTerminationForThisScript = true; | ||
1509 | } | ||
1510 | catch (TypeLoadException) | ||
1511 | { | ||
1512 | coopSleepHandle = null; | ||
1513 | |||
1514 | try | ||
1515 | { | ||
1516 | scriptObj | ||
1517 | = (IScript)m_AppDomains[appDomain].CreateInstanceAndUnwrap( | ||
1518 | assemblyName.FullName, | ||
1519 | "SecondLife.Script", | ||
1520 | false, | ||
1521 | BindingFlags.Default, | ||
1522 | null, | ||
1523 | null, | ||
1524 | null, | ||
1525 | null); | ||
1526 | } | ||
1527 | catch (Exception e2) | ||
1528 | { | ||
1529 | m_log.Error( | ||
1530 | string.Format( | ||
1531 | "[XENGINE]: Could not load previous SecondLife.Script from assembly {0} in {1}. Not starting. Exception ", | ||
1532 | assemblyName.FullName, World.Name), | ||
1533 | e2); | ||
1534 | |||
1535 | return false; | ||
1536 | } | ||
1537 | |||
1538 | coopTerminationForThisScript = false; | ||
1539 | } | ||
1540 | } | ||
1541 | else | ||
1542 | { | ||
1543 | try | ||
1544 | { | ||
1545 | scriptObj | ||
1546 | = (IScript)m_AppDomains[appDomain].CreateInstanceAndUnwrap( | ||
1547 | assemblyName.FullName, | ||
1548 | "SecondLife.Script", | ||
1549 | false, | ||
1550 | BindingFlags.Default, | ||
1551 | null, | ||
1552 | null, | ||
1553 | null, | ||
1554 | null); | ||
1555 | |||
1556 | coopSleepHandle = null; | ||
1557 | coopTerminationForThisScript = false; | ||
1391 | } | 1558 | } |
1559 | catch (TypeLoadException) | ||
1560 | { | ||
1561 | coopSleepHandle = new XEngineEventWaitHandle(false, EventResetMode.AutoReset); | ||
1562 | |||
1563 | try | ||
1564 | { | ||
1565 | scriptObj | ||
1566 | = (IScript)m_AppDomains[appDomain].CreateInstanceAndUnwrap( | ||
1567 | assemblyName.FullName, | ||
1568 | "SecondLife.XEngineScript", | ||
1569 | false, | ||
1570 | BindingFlags.Default, | ||
1571 | null, | ||
1572 | new object[] { coopSleepHandle }, | ||
1573 | null, | ||
1574 | null); | ||
1575 | } | ||
1576 | catch (Exception e2) | ||
1577 | { | ||
1578 | m_log.Error( | ||
1579 | string.Format( | ||
1580 | "[XENGINE]: Could not load previous SecondLife.XEngineScript from assembly {0} in {1}. Not starting. Exception ", | ||
1581 | assemblyName.FullName, World.Name), | ||
1582 | e2); | ||
1583 | |||
1584 | return false; | ||
1585 | } | ||
1586 | |||
1587 | coopTerminationForThisScript = true; | ||
1588 | } | ||
1589 | } | ||
1392 | 1590 | ||
1591 | if (m_coopTermination != coopTerminationForThisScript && !HaveNotifiedLogOfScriptStopMistmatch) | ||
1592 | { | ||
1593 | // Notify the log that there is at least one script compile that doesn't match the | ||
1594 | // ScriptStopStrategy. Operator has to manually delete old DLLs - we can't do this on Windows | ||
1595 | // once the assembly has been loaded evne if the instantiation of a class was unsuccessful. | ||
1596 | m_log.WarnFormat( | ||
1597 | "[XEngine]: At least one existing compiled script DLL in {0} has {1} as ScriptStopStrategy whereas config setting is {2}." | ||
1598 | + "\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).", | ||
1599 | World.Name, coopTerminationForThisScript ? "co-op" : "abort", m_coopTermination ? "co-op" : "abort"); | ||
1600 | |||
1601 | HaveNotifiedLogOfScriptStopMistmatch = true; | ||
1602 | } | ||
1603 | |||
1604 | instance = new ScriptInstance(this, part, | ||
1605 | item, | ||
1606 | startParam, postOnRez, | ||
1607 | m_MaxScriptQueue); | ||
1608 | |||
1609 | if ( | ||
1610 | !instance.Load( | ||
1611 | scriptObj, coopSleepHandle, assemblyPath, | ||
1612 | Path.Combine(ScriptEnginePath, World.RegionInfo.RegionID.ToString()), stateSource, coopTerminationForThisScript)) | ||
1613 | return false; | ||
1614 | ======= | ||
1393 | // if (!instance.Load(m_AppDomains[appDomain], assembly, stateSource)) | 1615 | // if (!instance.Load(m_AppDomains[appDomain], assembly, stateSource)) |
1394 | // return false; | 1616 | // return false; |
1617 | >>>>>>> avn/ubitvar | ||
1395 | 1618 | ||
1396 | m_AppDomains[appDomain] = sandbox; | 1619 | m_AppDomains[appDomain] = sandbox; |
1397 | 1620 | ||
@@ -1444,11 +1667,11 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
1444 | } | 1667 | } |
1445 | 1668 | ||
1446 | if (!m_Assemblies.ContainsKey(assetID)) | 1669 | if (!m_Assemblies.ContainsKey(assetID)) |
1447 | m_Assemblies[assetID] = assembly; | 1670 | m_Assemblies[assetID] = assemblyPath; |
1448 | 1671 | ||
1449 | lock (m_AddingAssemblies) | 1672 | lock (m_AddingAssemblies) |
1450 | { | 1673 | { |
1451 | m_AddingAssemblies[assembly]--; | 1674 | m_AddingAssemblies[assemblyPath]--; |
1452 | } | 1675 | } |
1453 | 1676 | ||
1454 | if (instance!=null) | 1677 | if (instance!=null) |
@@ -1482,6 +1705,9 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
1482 | return; | 1705 | return; |
1483 | } | 1706 | } |
1484 | 1707 | ||
1708 | <<<<<<< HEAD | ||
1709 | instance.Stop(m_WaitForEventCompletionOnScriptStop, true); | ||
1710 | ======= | ||
1485 | IScriptInstance instance=m_Scripts[itemID]; | 1711 | IScriptInstance instance=m_Scripts[itemID]; |
1486 | lockScriptsForRead(false); | 1712 | lockScriptsForRead(false); |
1487 | lockScriptsForWrite(true); | 1713 | lockScriptsForWrite(true); |
@@ -1492,6 +1718,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
1492 | instance.Stop(m_WaitForEventCompletionOnScriptStop); | 1718 | instance.Stop(m_WaitForEventCompletionOnScriptStop); |
1493 | 1719 | ||
1494 | // bool objectRemoved = false; | 1720 | // bool objectRemoved = false; |
1721 | >>>>>>> avn/ubitvar | ||
1495 | 1722 | ||
1496 | lock (m_PrimObjects) | 1723 | lock (m_PrimObjects) |
1497 | { | 1724 | { |
@@ -1504,14 +1731,13 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
1504 | 1731 | ||
1505 | // If there are no more scripts, remove prim | 1732 | // If there are no more scripts, remove prim |
1506 | if (m_PrimObjects[localID].Count == 0) | 1733 | if (m_PrimObjects[localID].Count == 0) |
1507 | { | ||
1508 | m_PrimObjects.Remove(localID); | 1734 | m_PrimObjects.Remove(localID); |
1509 | // objectRemoved = true; | ||
1510 | } | ||
1511 | } | 1735 | } |
1512 | } | 1736 | } |
1513 | 1737 | ||
1514 | instance.RemoveState(); | 1738 | if (instance.StatePersistedHere) |
1739 | instance.RemoveState(); | ||
1740 | |||
1515 | instance.DestroyScriptInstance(); | 1741 | instance.DestroyScriptInstance(); |
1516 | 1742 | ||
1517 | if (m_DomainScripts.ContainsKey(instance.AppDomain)) | 1743 | if (m_DomainScripts.ContainsKey(instance.AppDomain)) |
@@ -1653,7 +1879,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
1653 | 1879 | ||
1654 | IScriptInstance instance = (ScriptInstance) parms; | 1880 | IScriptInstance instance = (ScriptInstance) parms; |
1655 | 1881 | ||
1656 | //m_log.DebugFormat("[XEngine]: Processing event for {0}", instance); | 1882 | // m_log.DebugFormat("[XEngine]: Processing event for {0}", instance); |
1657 | 1883 | ||
1658 | return instance.EventProcessor(); | 1884 | return instance.EventProcessor(); |
1659 | } | 1885 | } |
@@ -1829,6 +2055,12 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
1829 | IScriptInstance instance = GetInstance(itemID); | 2055 | IScriptInstance instance = GetInstance(itemID); |
1830 | if (instance != null) | 2056 | if (instance != null) |
1831 | instance.ApiResetScript(); | 2057 | instance.ApiResetScript(); |
2058 | |||
2059 | // Send the new number of threads that are in use by the thread | ||
2060 | // pool, I believe that by adding them to the locations where the | ||
2061 | // script is changing states that I will catch all changes to the | ||
2062 | // thread pool | ||
2063 | m_Scene.setThreadCount(m_ThreadPool.InUseThreads); | ||
1832 | } | 2064 | } |
1833 | 2065 | ||
1834 | public void ResetScript(UUID itemID) | 2066 | public void ResetScript(UUID itemID) |
@@ -1836,6 +2068,12 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
1836 | IScriptInstance instance = GetInstance(itemID); | 2068 | IScriptInstance instance = GetInstance(itemID); |
1837 | if (instance != null) | 2069 | if (instance != null) |
1838 | instance.ResetScript(m_WaitForEventCompletionOnScriptStop); | 2070 | instance.ResetScript(m_WaitForEventCompletionOnScriptStop); |
2071 | |||
2072 | // Send the new number of threads that are in use by the thread | ||
2073 | // pool, I believe that by adding them to the locations where the | ||
2074 | // script is changing states that I will catch all changes to the | ||
2075 | // thread pool | ||
2076 | m_Scene.setThreadCount(m_ThreadPool.InUseThreads); | ||
1839 | } | 2077 | } |
1840 | 2078 | ||
1841 | public void StartScript(UUID itemID) | 2079 | public void StartScript(UUID itemID) |
@@ -1845,6 +2083,12 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
1845 | instance.Start(); | 2083 | instance.Start(); |
1846 | else | 2084 | else |
1847 | m_runFlags.AddOrUpdate(itemID, true, 240); | 2085 | m_runFlags.AddOrUpdate(itemID, true, 240); |
2086 | |||
2087 | // Send the new number of threads that are in use by the thread | ||
2088 | // pool, I believe that by adding them to the locations where the | ||
2089 | // script is changing states that I will catch all changes to the | ||
2090 | // thread pool | ||
2091 | m_Scene.setThreadCount(m_ThreadPool.InUseThreads); | ||
1848 | } | 2092 | } |
1849 | 2093 | ||
1850 | public void StopScript(UUID itemID) | 2094 | public void StopScript(UUID itemID) |
@@ -1853,6 +2097,9 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
1853 | 2097 | ||
1854 | if (instance != null) | 2098 | if (instance != null) |
1855 | { | 2099 | { |
2100 | lock (instance.EventQueue) | ||
2101 | instance.StayStopped = true; // the script was stopped explicitly | ||
2102 | |||
1856 | instance.Stop(m_WaitForEventCompletionOnScriptStop); | 2103 | instance.Stop(m_WaitForEventCompletionOnScriptStop); |
1857 | } | 2104 | } |
1858 | else | 2105 | else |
@@ -1860,6 +2107,12 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
1860 | // m_log.DebugFormat("[XENGINE]: Could not find script with ID {0} to stop in {1}", itemID, World.Name); | 2107 | // m_log.DebugFormat("[XENGINE]: Could not find script with ID {0} to stop in {1}", itemID, World.Name); |
1861 | m_runFlags.AddOrUpdate(itemID, false, 240); | 2108 | m_runFlags.AddOrUpdate(itemID, false, 240); |
1862 | } | 2109 | } |
2110 | |||
2111 | // Send the new number of threads that are in use by the thread | ||
2112 | // pool, I believe that by adding them to the locations where the | ||
2113 | // script is changing states that I will catch all changes to the | ||
2114 | // thread pool | ||
2115 | m_Scene.setThreadCount(m_ThreadPool.InUseThreads); | ||
1863 | } | 2116 | } |
1864 | 2117 | ||
1865 | public DetectParams GetDetectParams(UUID itemID, int idx) | 2118 | public DetectParams GetDetectParams(UUID itemID, int idx) |
@@ -2225,7 +2478,8 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
2225 | catch (IOException ex) | 2478 | catch (IOException ex) |
2226 | { | 2479 | { |
2227 | // if there already exists a file at that location, it may be locked. | 2480 | // if there already exists a file at that location, it may be locked. |
2228 | m_log.ErrorFormat("[XEngine]: Linemap file {0} already exists! {1}", mappath, ex.Message); | 2481 | m_log.Error( |
2482 | string.Format("[XEngine]: Linemap file {0} could not be written. Exception ", mappath), ex); | ||
2229 | } | 2483 | } |
2230 | } | 2484 | } |
2231 | } | 2485 | } |
@@ -2251,6 +2505,9 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
2251 | m_log.ErrorFormat("[XEngine]: Error whilst writing state file {0}, {1}", statepath, ex.Message); | 2505 | m_log.ErrorFormat("[XEngine]: Error whilst writing state file {0}, {1}", statepath, ex.Message); |
2252 | } | 2506 | } |
2253 | 2507 | ||
2508 | // m_log.DebugFormat( | ||
2509 | // "[XEngine]: Wrote state for script item with ID {0} at {1} in {2}", itemID, statepath, m_Scene.Name); | ||
2510 | |||
2254 | return true; | 2511 | return true; |
2255 | } | 2512 | } |
2256 | 2513 | ||
@@ -2272,7 +2529,6 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
2272 | 2529 | ||
2273 | public Dictionary<uint, float> GetObjectScriptsExecutionTimes() | 2530 | public Dictionary<uint, float> GetObjectScriptsExecutionTimes() |
2274 | { | 2531 | { |
2275 | long tickNow = Util.EnvironmentTickCount(); | ||
2276 | Dictionary<uint, float> topScripts = new Dictionary<uint, float>(); | 2532 | Dictionary<uint, float> topScripts = new Dictionary<uint, float>(); |
2277 | 2533 | ||
2278 | lock (m_Scripts) | 2534 | lock (m_Scripts) |
@@ -2282,7 +2538,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
2282 | if (!topScripts.ContainsKey(si.LocalID)) | 2538 | if (!topScripts.ContainsKey(si.LocalID)) |
2283 | topScripts[si.RootLocalID] = 0; | 2539 | topScripts[si.RootLocalID] = 0; |
2284 | 2540 | ||
2285 | topScripts[si.RootLocalID] += CalculateAdjustedExectionTime(si, tickNow); | 2541 | topScripts[si.RootLocalID] += GetExectionTime(si); |
2286 | } | 2542 | } |
2287 | } | 2543 | } |
2288 | 2544 | ||
@@ -2296,7 +2552,6 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
2296 | return 0.0f; | 2552 | return 0.0f; |
2297 | } | 2553 | } |
2298 | float time = 0.0f; | 2554 | float time = 0.0f; |
2299 | long tickNow = Util.EnvironmentTickCount(); | ||
2300 | IScriptInstance si; | 2555 | IScriptInstance si; |
2301 | // Calculate the time for all scripts that this engine is executing | 2556 | // Calculate the time for all scripts that this engine is executing |
2302 | // Ignore any others | 2557 | // Ignore any others |
@@ -2305,36 +2560,15 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
2305 | si = GetInstance(id); | 2560 | si = GetInstance(id); |
2306 | if (si != null && si.Running) | 2561 | if (si != null && si.Running) |
2307 | { | 2562 | { |
2308 | time += CalculateAdjustedExectionTime(si, tickNow); | 2563 | time += GetExectionTime(si); |
2309 | } | 2564 | } |
2310 | } | 2565 | } |
2311 | return time; | 2566 | return time; |
2312 | } | 2567 | } |
2313 | 2568 | ||
2314 | private float CalculateAdjustedExectionTime(IScriptInstance si, long tickNow) | 2569 | private float GetExectionTime(IScriptInstance si) |
2315 | { | 2570 | { |
2316 | long ticksElapsed = tickNow - si.MeasurementPeriodTickStart; | 2571 | return (float)si.ExecutionTime.GetSumTime().TotalMilliseconds; |
2317 | |||
2318 | // Avoid divide by zero | ||
2319 | if (ticksElapsed == 0) | ||
2320 | ticksElapsed = 1; | ||
2321 | |||
2322 | // Scale execution time to the ideal 55 fps frame time for these reasons. | ||
2323 | // | ||
2324 | // 1) XEngine does not execute scripts per frame, unlike other script engines. Hence, there is no | ||
2325 | // 'script execution time per frame', which is the original purpose of this value. | ||
2326 | // | ||
2327 | // 2) Giving the raw execution times is misleading since scripts start at different times, making | ||
2328 | // it impossible to compare scripts. | ||
2329 | // | ||
2330 | // 3) Scaling the raw execution time to the time that the script has been running is better but | ||
2331 | // is still misleading since a script that has just been rezzed may appear to have been running | ||
2332 | // for much longer. | ||
2333 | // | ||
2334 | // 4) Hence, we scale execution time to an idealised frame time (55 fps). This is also not perfect | ||
2335 | // since the figure does not represent actual execution time and very hard running scripts will | ||
2336 | // never exceed 18ms (though this is a very high number for script execution so is a warning sign). | ||
2337 | return ((float)si.MeasurementPeriodExecutionTime / ticksElapsed) * 18.1818f; | ||
2338 | } | 2572 | } |
2339 | 2573 | ||
2340 | public void SuspendScript(UUID itemID) | 2574 | public void SuspendScript(UUID itemID) |
@@ -2346,6 +2580,12 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
2346 | instance.Suspend(); | 2580 | instance.Suspend(); |
2347 | // else | 2581 | // else |
2348 | // m_log.DebugFormat("[XEngine]: Could not find script with ID {0} to resume", itemID); | 2582 | // m_log.DebugFormat("[XEngine]: Could not find script with ID {0} to resume", itemID); |
2583 | |||
2584 | // Send the new number of threads that are in use by the thread | ||
2585 | // pool, I believe that by adding them to the locations where the | ||
2586 | // script is changing states that I will catch all changes to the | ||
2587 | // thread pool | ||
2588 | m_Scene.setThreadCount(m_ThreadPool.InUseThreads); | ||
2349 | } | 2589 | } |
2350 | 2590 | ||
2351 | public void ResumeScript(UUID itemID) | 2591 | public void ResumeScript(UUID itemID) |
@@ -2357,6 +2597,12 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
2357 | instance.Resume(); | 2597 | instance.Resume(); |
2358 | // else | 2598 | // else |
2359 | // m_log.DebugFormat("[XEngine]: Could not find script with ID {0} to resume", itemID); | 2599 | // m_log.DebugFormat("[XEngine]: Could not find script with ID {0} to resume", itemID); |
2600 | |||
2601 | // Send the new number of threads that are in use by the thread | ||
2602 | // pool, I believe that by adding them to the locations where the | ||
2603 | // script is changing states that I will catch all changes to the | ||
2604 | // thread pool | ||
2605 | m_Scene.setThreadCount(m_ThreadPool.InUseThreads); | ||
2360 | } | 2606 | } |
2361 | 2607 | ||
2362 | public bool HasScript(UUID itemID, out bool running) | 2608 | public bool HasScript(UUID itemID, out bool running) |
@@ -2370,5 +2616,30 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
2370 | running = instance.Running; | 2616 | running = instance.Running; |
2371 | return true; | 2617 | return true; |
2372 | } | 2618 | } |
2619 | |||
2620 | public void SleepScript(UUID itemID, int delay) | ||
2621 | { | ||
2622 | IScriptInstance instance = GetInstance(itemID); | ||
2623 | if (instance == null) | ||
2624 | return; | ||
2625 | |||
2626 | instance.ExecutionTimer.Stop(); | ||
2627 | try | ||
2628 | { | ||
2629 | if (instance.CoopWaitHandle != null) | ||
2630 | { | ||
2631 | if (instance.CoopWaitHandle.WaitOne(delay)) | ||
2632 | throw new ScriptCoopStopException(); | ||
2633 | } | ||
2634 | else | ||
2635 | { | ||
2636 | Thread.Sleep(delay); | ||
2637 | } | ||
2638 | } | ||
2639 | finally | ||
2640 | { | ||
2641 | instance.ExecutionTimer.Start(); | ||
2642 | } | ||
2643 | } | ||
2373 | } | 2644 | } |
2374 | } | 2645 | } |