diff options
Diffstat (limited to '')
-rw-r--r-- | OpenSim/Region/ScriptEngine/XEngine/Tests/XEngineTest.cs | 8 | ||||
-rw-r--r-- | OpenSim/Region/ScriptEngine/XEngine/XEngine.cs | 385 |
2 files changed, 256 insertions, 137 deletions
diff --git a/OpenSim/Region/ScriptEngine/XEngine/Tests/XEngineTest.cs b/OpenSim/Region/ScriptEngine/XEngine/Tests/XEngineTest.cs index 7d7bd82..f247a0b 100644 --- a/OpenSim/Region/ScriptEngine/XEngine/Tests/XEngineTest.cs +++ b/OpenSim/Region/ScriptEngine/XEngine/Tests/XEngineTest.cs | |||
@@ -58,9 +58,6 @@ namespace OpenSim.Region.ScriptEngine.XEngine.Tests | |||
58 | // Console.WriteLine(AppDomain.CurrentDomain.BaseDirectory); | 58 | // Console.WriteLine(AppDomain.CurrentDomain.BaseDirectory); |
59 | m_xEngine = new XEngine(); | 59 | m_xEngine = new XEngine(); |
60 | 60 | ||
61 | // Necessary to stop serialization complaining | ||
62 | WorldCommModule wcModule = new WorldCommModule(); | ||
63 | |||
64 | IniConfigSource configSource = new IniConfigSource(); | 61 | IniConfigSource configSource = new IniConfigSource(); |
65 | 62 | ||
66 | IConfig startupConfig = configSource.AddConfig("Startup"); | 63 | IConfig startupConfig = configSource.AddConfig("Startup"); |
@@ -68,13 +65,14 @@ namespace OpenSim.Region.ScriptEngine.XEngine.Tests | |||
68 | 65 | ||
69 | IConfig xEngineConfig = configSource.AddConfig("XEngine"); | 66 | IConfig xEngineConfig = configSource.AddConfig("XEngine"); |
70 | xEngineConfig.Set("Enabled", "true"); | 67 | xEngineConfig.Set("Enabled", "true"); |
68 | xEngineConfig.Set("StartDelay", "0"); | ||
71 | 69 | ||
72 | // These tests will not run with AppDomainLoading = true, at least on mono. For unknown reasons, the call | 70 | // These tests will not run with AppDomainLoading = true, at least on mono. For unknown reasons, the call |
73 | // to AssemblyResolver.OnAssemblyResolve fails. | 71 | // to AssemblyResolver.OnAssemblyResolve fails. |
74 | xEngineConfig.Set("AppDomainLoading", "false"); | 72 | xEngineConfig.Set("AppDomainLoading", "false"); |
75 | 73 | ||
76 | m_scene = SceneHelpers.SetupScene("My Test", UUID.Random(), 1000, 1000, null, configSource); | 74 | m_scene = new SceneHelpers().SetupScene("My Test", UUID.Random(), 1000, 1000, configSource); |
77 | SceneHelpers.SetupSceneModules(m_scene, configSource, m_xEngine, wcModule); | 75 | SceneHelpers.SetupSceneModules(m_scene, configSource, m_xEngine); |
78 | m_scene.StartScripts(); | 76 | m_scene.StartScripts(); |
79 | } | 77 | } |
80 | 78 | ||
diff --git a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs index 2a01fc4..d763063 100644 --- a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs +++ b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs | |||
@@ -63,6 +63,14 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
63 | { | 63 | { |
64 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 64 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
65 | 65 | ||
66 | /// <summary> | ||
67 | /// Control the printing of certain debug messages. | ||
68 | /// </summary> | ||
69 | /// <remarks> | ||
70 | /// If DebugLevel >= 1, then we log every time that a script is started. | ||
71 | /// </remarks> | ||
72 | // public int DebugLevel { get; set; } | ||
73 | |||
66 | private SmartThreadPool m_ThreadPool; | 74 | private SmartThreadPool m_ThreadPool; |
67 | private int m_MaxScriptQueue; | 75 | private int m_MaxScriptQueue; |
68 | private Scene m_Scene; | 76 | private Scene m_Scene; |
@@ -70,7 +78,13 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
70 | private IConfigSource m_ConfigSource = null; | 78 | private IConfigSource m_ConfigSource = null; |
71 | private ICompiler m_Compiler; | 79 | private ICompiler m_Compiler; |
72 | private int m_MinThreads; | 80 | private int m_MinThreads; |
73 | private int m_MaxThreads ; | 81 | private int m_MaxThreads; |
82 | |||
83 | /// <summary> | ||
84 | /// Amount of time to delay before starting. | ||
85 | /// </summary> | ||
86 | private int m_StartDelay; | ||
87 | |||
74 | private int m_IdleTimeout; | 88 | private int m_IdleTimeout; |
75 | private int m_StackSize; | 89 | private int m_StackSize; |
76 | private int m_SleepTime; | 90 | private int m_SleepTime; |
@@ -284,14 +298,14 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
284 | AppDomain.CurrentDomain.AssemblyResolve += | 298 | AppDomain.CurrentDomain.AssemblyResolve += |
285 | OnAssemblyResolve; | 299 | OnAssemblyResolve; |
286 | 300 | ||
287 | m_log.InfoFormat("[XEngine] Initializing scripts in region {0}", | ||
288 | scene.RegionInfo.RegionName); | ||
289 | m_Scene = scene; | 301 | m_Scene = scene; |
302 | m_log.InfoFormat("[XEngine]: Initializing scripts in region {0}", m_Scene.RegionInfo.RegionName); | ||
290 | 303 | ||
291 | m_MinThreads = m_ScriptConfig.GetInt("MinThreads", 2); | 304 | m_MinThreads = m_ScriptConfig.GetInt("MinThreads", 2); |
292 | m_MaxThreads = m_ScriptConfig.GetInt("MaxThreads", 100); | 305 | m_MaxThreads = m_ScriptConfig.GetInt("MaxThreads", 100); |
293 | m_IdleTimeout = m_ScriptConfig.GetInt("IdleTimeout", 60); | 306 | m_IdleTimeout = m_ScriptConfig.GetInt("IdleTimeout", 60); |
294 | string priority = m_ScriptConfig.GetString("Priority", "BelowNormal"); | 307 | string priority = m_ScriptConfig.GetString("Priority", "BelowNormal"); |
308 | m_StartDelay = m_ScriptConfig.GetInt("StartDelay", 15000); | ||
295 | m_MaxScriptQueue = m_ScriptConfig.GetInt("MaxScriptEventQueue",300); | 309 | m_MaxScriptQueue = m_ScriptConfig.GetInt("MaxScriptEventQueue",300); |
296 | m_StackSize = m_ScriptConfig.GetInt("ThreadStackSize", 262144); | 310 | m_StackSize = m_ScriptConfig.GetInt("ThreadStackSize", 262144); |
297 | m_SleepTime = m_ScriptConfig.GetInt("MaintenanceInterval", 10) * 1000; | 311 | m_SleepTime = m_ScriptConfig.GetInt("MaintenanceInterval", 10) * 1000; |
@@ -389,9 +403,42 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
389 | "Starts all stopped scripts." | 403 | "Starts all stopped scripts." |
390 | + "If a <script-item-uuid> is given then only that script will be started. Otherwise, all suitable scripts are started.", | 404 | + "If a <script-item-uuid> is given then only that script will be started. Otherwise, all suitable scripts are started.", |
391 | (module, cmdparams) => HandleScriptsAction(cmdparams, HandleStartScript)); | 405 | (module, cmdparams) => HandleScriptsAction(cmdparams, HandleStartScript)); |
406 | |||
407 | // MainConsole.Instance.Commands.AddCommand( | ||
408 | // "Debug", false, "debug xengine", "debug xengine [<level>]", | ||
409 | // "Turn on detailed xengine debugging.", | ||
410 | // "If level <= 0, then no extra logging is done.\n" | ||
411 | // + "If level >= 1, then we log every time that a script is started.", | ||
412 | // HandleDebugLevelCommand); | ||
392 | } | 413 | } |
393 | 414 | ||
394 | /// <summary> | 415 | /// <summary> |
416 | /// Change debug level | ||
417 | /// </summary> | ||
418 | /// <param name="module"></param> | ||
419 | /// <param name="args"></param> | ||
420 | // private void HandleDebugLevelCommand(string module, string[] args) | ||
421 | // { | ||
422 | // if (args.Length == 3) | ||
423 | // { | ||
424 | // int newDebug; | ||
425 | // if (int.TryParse(args[2], out newDebug)) | ||
426 | // { | ||
427 | // DebugLevel = newDebug; | ||
428 | // MainConsole.Instance.OutputFormat("Debug level set to {0}", newDebug); | ||
429 | // } | ||
430 | // } | ||
431 | // else if (args.Length == 2) | ||
432 | // { | ||
433 | // MainConsole.Instance.OutputFormat("Current debug level is {0}", DebugLevel); | ||
434 | // } | ||
435 | // else | ||
436 | // { | ||
437 | // MainConsole.Instance.Output("Usage: debug xengine 0..1"); | ||
438 | // } | ||
439 | // } | ||
440 | |||
441 | /// <summary> | ||
395 | /// Parse the raw item id into a script instance from the command params if it's present. | 442 | /// Parse the raw item id into a script instance from the command params if it's present. |
396 | /// </summary> | 443 | /// </summary> |
397 | /// <param name="cmdparams"></param> | 444 | /// <param name="cmdparams"></param> |
@@ -799,35 +846,66 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
799 | int colon = firstline.IndexOf(':'); | 846 | int colon = firstline.IndexOf(':'); |
800 | if (firstline.Length > 2 && firstline.Substring(0, 2) == "//" && colon != -1) | 847 | if (firstline.Length > 2 && firstline.Substring(0, 2) == "//" && colon != -1) |
801 | { | 848 | { |
802 | string engineName = firstline.Substring(2, colon-2); | 849 | string engineName = firstline.Substring(2, colon - 2); |
803 | 850 | ||
804 | if (names.Contains(engineName)) | 851 | if (names.Contains(engineName)) |
805 | { | 852 | { |
806 | engine = engineName; | 853 | engine = engineName; |
807 | script = "//" + script.Substring(script.IndexOf(':')+1); | 854 | script = "//" + script.Substring(colon + 1); |
808 | } | 855 | } |
809 | else | 856 | else |
810 | { | 857 | { |
811 | if (engine == ScriptEngineName) | 858 | if (engine == ScriptEngineName) |
812 | { | 859 | { |
813 | SceneObjectPart part = | 860 | // If we are falling back on XEngine as the default engine, then only complain to the user |
814 | m_Scene.GetSceneObjectPart( | 861 | // if a script language has been explicitly set and it's one that we recognize or there are |
815 | localID); | 862 | // no non-whitespace characters after the colon. |
816 | 863 | // | |
817 | TaskInventoryItem item = | 864 | // If the script is |
818 | part.Inventory.GetInventoryItem(itemID); | 865 | // explicitly not allowed or the script is not in LSL then the user will be informed by a later compiler message. |
819 | 866 | // | |
820 | ScenePresence presence = | 867 | // If the colon ends the line then we'll risk the false positive as this is more likely |
821 | m_Scene.GetScenePresence( | 868 | // to signal a real scriptengine line where the user wants to use the default compile language. |
822 | item.OwnerID); | 869 | // |
823 | 870 | // This avoids the overwhelming number of false positives where we're in this code because | |
824 | if (presence != null) | 871 | // there's a colon in a comment in the first line of a script for entirely |
872 | // unrelated reasons (e.g. vim settings). | ||
873 | // | ||
874 | // TODO: A better fix would be to deprecate simple : detection and look for some less likely | ||
875 | // string to begin the comment (like #! in unix shell scripts). | ||
876 | bool warnRunningInXEngine = false; | ||
877 | string restOfFirstLine = firstline.Substring(colon + 1); | ||
878 | |||
879 | // FIXME: These are hardcoded because they are currently hardcoded in Compiler.cs | ||
880 | if (restOfFirstLine.StartsWith("c#") | ||
881 | || restOfFirstLine.StartsWith("vb") | ||
882 | || restOfFirstLine.StartsWith("lsl") | ||
883 | || restOfFirstLine.StartsWith("js") | ||
884 | || restOfFirstLine.StartsWith("yp") | ||
885 | || restOfFirstLine.Length == 0) | ||
886 | warnRunningInXEngine = true; | ||
887 | |||
888 | if (warnRunningInXEngine) | ||
825 | { | 889 | { |
826 | presence.ControllingClient.SendAgentAlertMessage( | 890 | SceneObjectPart part = |
827 | "Selected engine unavailable. "+ | 891 | m_Scene.GetSceneObjectPart( |
828 | "Running script on "+ | 892 | localID); |
829 | ScriptEngineName, | 893 | |
830 | false); | 894 | TaskInventoryItem item = |
895 | part.Inventory.GetInventoryItem(itemID); | ||
896 | |||
897 | ScenePresence presence = | ||
898 | m_Scene.GetScenePresence( | ||
899 | item.OwnerID); | ||
900 | |||
901 | if (presence != null) | ||
902 | { | ||
903 | presence.ControllingClient.SendAgentAlertMessage( | ||
904 | "Selected engine unavailable. "+ | ||
905 | "Running script on "+ | ||
906 | ScriptEngineName, | ||
907 | false); | ||
908 | } | ||
831 | } | 909 | } |
832 | } | 910 | } |
833 | } | 911 | } |
@@ -884,20 +962,31 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
884 | { | 962 | { |
885 | if (m_InitialStartup) | 963 | if (m_InitialStartup) |
886 | { | 964 | { |
887 | m_InitialStartup = false; | 965 | // This delay exists to stop mono problems where script compilation and startup would stop the sim |
888 | System.Threading.Thread.Sleep(15000); | 966 | // working properly for the session. |
967 | System.Threading.Thread.Sleep(m_StartDelay); | ||
968 | } | ||
889 | 969 | ||
890 | if (m_CompileQueue.Count == 0) | 970 | object[] o; |
971 | |||
972 | int scriptsStarted = 0; | ||
973 | |||
974 | while (m_CompileQueue.Dequeue(out o)) | ||
975 | { | ||
976 | if (DoOnRezScript(o)) | ||
891 | { | 977 | { |
892 | // No scripts on region, so won't get triggered later | 978 | scriptsStarted++; |
893 | // by the queue becoming empty so we trigger it here | 979 | |
894 | m_Scene.EventManager.TriggerEmptyScriptCompileQueue(0, String.Empty); | 980 | if (m_InitialStartup) |
981 | if (scriptsStarted % 50 == 0) | ||
982 | m_log.InfoFormat( | ||
983 | "[XEngine]: Started {0} scripts in {1}", scriptsStarted, m_Scene.RegionInfo.RegionName); | ||
895 | } | 984 | } |
896 | } | 985 | } |
897 | 986 | ||
898 | object[] o; | 987 | if (m_InitialStartup) |
899 | while (m_CompileQueue.Dequeue(out o)) | 988 | m_log.InfoFormat( |
900 | DoOnRezScript(o); | 989 | "[XEngine]: Completed starting {0} scripts on {1}", scriptsStarted, m_Scene.RegionInfo.RegionName); |
901 | 990 | ||
902 | // NOTE: Despite having a lockless queue, this lock is required | 991 | // NOTE: Despite having a lockless queue, this lock is required |
903 | // to make sure there is never no compile thread while there | 992 | // to make sure there is never no compile thread while there |
@@ -905,12 +994,13 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
905 | // due to a race condition | 994 | // due to a race condition |
906 | // | 995 | // |
907 | lock (m_CompileQueue) | 996 | lock (m_CompileQueue) |
908 | { | ||
909 | m_CurrentCompile = null; | 997 | m_CurrentCompile = null; |
910 | } | 998 | |
911 | m_Scene.EventManager.TriggerEmptyScriptCompileQueue(m_ScriptFailCount, | 999 | m_Scene.EventManager.TriggerEmptyScriptCompileQueue(m_ScriptFailCount, |
912 | m_ScriptErrorMessage); | 1000 | m_ScriptErrorMessage); |
1001 | |||
913 | m_ScriptFailCount = 0; | 1002 | m_ScriptFailCount = 0; |
1003 | m_InitialStartup = false; | ||
914 | 1004 | ||
915 | return null; | 1005 | return null; |
916 | } | 1006 | } |
@@ -1093,11 +1183,18 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
1093 | 1183 | ||
1094 | AppDomain sandbox; | 1184 | AppDomain sandbox; |
1095 | if (m_AppDomainLoading) | 1185 | if (m_AppDomainLoading) |
1186 | { | ||
1096 | sandbox = AppDomain.CreateDomain( | 1187 | sandbox = AppDomain.CreateDomain( |
1097 | m_Scene.RegionInfo.RegionID.ToString(), | 1188 | m_Scene.RegionInfo.RegionID.ToString(), |
1098 | evidence, appSetup); | 1189 | evidence, appSetup); |
1190 | m_AppDomains[appDomain].AssemblyResolve += | ||
1191 | new ResolveEventHandler( | ||
1192 | AssemblyResolver.OnAssemblyResolve); | ||
1193 | } | ||
1099 | else | 1194 | else |
1195 | { | ||
1100 | sandbox = AppDomain.CurrentDomain; | 1196 | sandbox = AppDomain.CurrentDomain; |
1197 | } | ||
1101 | 1198 | ||
1102 | //PolicyLevel sandboxPolicy = PolicyLevel.CreateAppDomainLevel(); | 1199 | //PolicyLevel sandboxPolicy = PolicyLevel.CreateAppDomainLevel(); |
1103 | //AllMembershipCondition sandboxMembershipCondition = new AllMembershipCondition(); | 1200 | //AllMembershipCondition sandboxMembershipCondition = new AllMembershipCondition(); |
@@ -1109,9 +1206,6 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
1109 | 1206 | ||
1110 | m_AppDomains[appDomain] = sandbox; | 1207 | m_AppDomains[appDomain] = sandbox; |
1111 | 1208 | ||
1112 | m_AppDomains[appDomain].AssemblyResolve += | ||
1113 | new ResolveEventHandler( | ||
1114 | AssemblyResolver.OnAssemblyResolve); | ||
1115 | m_DomainScripts[appDomain] = new List<UUID>(); | 1209 | m_DomainScripts[appDomain] = new List<UUID>(); |
1116 | } | 1210 | } |
1117 | catch (Exception e) | 1211 | catch (Exception e) |
@@ -1396,25 +1490,24 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
1396 | return false; | 1490 | return false; |
1397 | 1491 | ||
1398 | uuids = m_PrimObjects[localID]; | 1492 | uuids = m_PrimObjects[localID]; |
1399 | |||
1400 | 1493 | ||
1401 | foreach (UUID itemID in uuids) | 1494 | foreach (UUID itemID in uuids) |
1402 | { | ||
1403 | IScriptInstance instance = null; | ||
1404 | try | ||
1405 | { | 1495 | { |
1406 | if (m_Scripts.ContainsKey(itemID)) | 1496 | IScriptInstance instance = null; |
1407 | instance = m_Scripts[itemID]; | 1497 | try |
1408 | } | 1498 | { |
1409 | catch { /* ignore race conditions */ } | 1499 | if (m_Scripts.ContainsKey(itemID)) |
1410 | 1500 | instance = m_Scripts[itemID]; | |
1411 | if (instance != null) | 1501 | } |
1412 | { | 1502 | catch { /* ignore race conditions */ } |
1413 | instance.PostEvent(p); | 1503 | |
1414 | result = true; | 1504 | if (instance != null) |
1505 | { | ||
1506 | instance.PostEvent(p); | ||
1507 | result = true; | ||
1508 | } | ||
1415 | } | 1509 | } |
1416 | } | 1510 | } |
1417 | } | ||
1418 | 1511 | ||
1419 | return result; | 1512 | return result; |
1420 | } | 1513 | } |
@@ -1539,6 +1632,13 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
1539 | } | 1632 | } |
1540 | } | 1633 | } |
1541 | 1634 | ||
1635 | public void SetRunEnable(UUID instanceID, bool enable) | ||
1636 | { | ||
1637 | IScriptInstance instance = GetInstance(instanceID); | ||
1638 | if (instance != null) | ||
1639 | instance.Run = enable; | ||
1640 | } | ||
1641 | |||
1542 | public bool GetScriptState(UUID itemID) | 1642 | public bool GetScriptState(UUID itemID) |
1543 | { | 1643 | { |
1544 | IScriptInstance instance = GetInstance(itemID); | 1644 | IScriptInstance instance = GetInstance(itemID); |
@@ -1573,7 +1673,11 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
1573 | { | 1673 | { |
1574 | IScriptInstance instance = GetInstance(itemID); | 1674 | IScriptInstance instance = GetInstance(itemID); |
1575 | if (instance != null) | 1675 | if (instance != null) |
1576 | instance.Stop(0); | 1676 | { |
1677 | // Give the script some time to finish processing its last event. Simply aborting the script thread can | ||
1678 | // cause issues on mono 2.6, 2.10 and possibly later where locks are not released properly on abort. | ||
1679 | instance.Stop(1000); | ||
1680 | } | ||
1577 | } | 1681 | } |
1578 | 1682 | ||
1579 | public DetectParams GetDetectParams(UUID itemID, int idx) | 1683 | public DetectParams GetDetectParams(UUID itemID, int idx) |
@@ -1671,12 +1775,12 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
1671 | 1775 | ||
1672 | public string GetXMLState(UUID itemID) | 1776 | public string GetXMLState(UUID itemID) |
1673 | { | 1777 | { |
1674 | // m_log.DebugFormat("[XEngine]: Getting XML state for {0}", itemID); | 1778 | // m_log.DebugFormat("[XEngine]: Getting XML state for script instance {0}", itemID); |
1675 | 1779 | ||
1676 | IScriptInstance instance = GetInstance(itemID); | 1780 | IScriptInstance instance = GetInstance(itemID); |
1677 | if (instance == null) | 1781 | if (instance == null) |
1678 | { | 1782 | { |
1679 | // m_log.DebugFormat("[XEngine]: Found no script for {0}, returning empty string", itemID); | 1783 | // m_log.DebugFormat("[XEngine]: Found no script instance for {0}, returning empty string", itemID); |
1680 | return ""; | 1784 | return ""; |
1681 | } | 1785 | } |
1682 | 1786 | ||
@@ -1749,14 +1853,15 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
1749 | FileMode.Open, FileAccess.Read)) | 1853 | FileMode.Open, FileAccess.Read)) |
1750 | { | 1854 | { |
1751 | tfs.Read(tdata, 0, tdata.Length); | 1855 | tfs.Read(tdata, 0, tdata.Length); |
1752 | tfs.Close(); | ||
1753 | } | 1856 | } |
1754 | 1857 | ||
1755 | assem = new System.Text.ASCIIEncoding().GetString(tdata); | 1858 | assem = Encoding.ASCII.GetString(tdata); |
1756 | } | 1859 | } |
1757 | catch (Exception e) | 1860 | catch (Exception e) |
1758 | { | 1861 | { |
1759 | m_log.DebugFormat("[XEngine]: Unable to open script textfile {0}, reason: {1}", assemName+".text", e.Message); | 1862 | m_log.ErrorFormat( |
1863 | "[XEngine]: Unable to open script textfile {0}{1}, reason: {2}", | ||
1864 | assemName, ".text", e.Message); | ||
1760 | } | 1865 | } |
1761 | } | 1866 | } |
1762 | } | 1867 | } |
@@ -1773,16 +1878,15 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
1773 | using (FileStream fs = File.Open(assemName, FileMode.Open, FileAccess.Read)) | 1878 | using (FileStream fs = File.Open(assemName, FileMode.Open, FileAccess.Read)) |
1774 | { | 1879 | { |
1775 | fs.Read(data, 0, data.Length); | 1880 | fs.Read(data, 0, data.Length); |
1776 | fs.Close(); | ||
1777 | } | 1881 | } |
1778 | 1882 | ||
1779 | assem = System.Convert.ToBase64String(data); | 1883 | assem = System.Convert.ToBase64String(data); |
1780 | } | 1884 | } |
1781 | catch (Exception e) | 1885 | catch (Exception e) |
1782 | { | 1886 | { |
1783 | m_log.DebugFormat("[XEngine]: Unable to open script assembly {0}, reason: {1}", assemName, e.Message); | 1887 | m_log.ErrorFormat( |
1888 | "[XEngine]: Unable to open script assembly {0}, reason: {1}", assemName, e.Message); | ||
1784 | } | 1889 | } |
1785 | |||
1786 | } | 1890 | } |
1787 | } | 1891 | } |
1788 | 1892 | ||
@@ -1795,9 +1899,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
1795 | using (StreamReader msr = new StreamReader(mfs)) | 1899 | using (StreamReader msr = new StreamReader(mfs)) |
1796 | { | 1900 | { |
1797 | map = msr.ReadToEnd(); | 1901 | map = msr.ReadToEnd(); |
1798 | msr.Close(); | ||
1799 | } | 1902 | } |
1800 | mfs.Close(); | ||
1801 | } | 1903 | } |
1802 | } | 1904 | } |
1803 | 1905 | ||
@@ -1833,6 +1935,8 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
1833 | 1935 | ||
1834 | public bool SetXMLState(UUID itemID, string xml) | 1936 | public bool SetXMLState(UUID itemID, string xml) |
1835 | { | 1937 | { |
1938 | // m_log.DebugFormat("[XEngine]: Writing state for script item with ID {0}", itemID); | ||
1939 | |||
1836 | if (xml == String.Empty) | 1940 | if (xml == String.Empty) |
1837 | return false; | 1941 | return false; |
1838 | 1942 | ||
@@ -1893,31 +1997,61 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
1893 | { | 1997 | { |
1894 | using (FileStream fs = File.Create(path)) | 1998 | using (FileStream fs = File.Create(path)) |
1895 | { | 1999 | { |
2000 | // m_log.DebugFormat("[XEngine]: Writing assembly file {0}", path); | ||
2001 | |||
1896 | fs.Write(filedata, 0, filedata.Length); | 2002 | fs.Write(filedata, 0, filedata.Length); |
1897 | fs.Close(); | ||
1898 | } | 2003 | } |
1899 | } | 2004 | } |
1900 | catch (IOException ex) | 2005 | catch (IOException ex) |
1901 | { | 2006 | { |
1902 | // if there already exists a file at that location, it may be locked. | 2007 | // if there already exists a file at that location, it may be locked. |
1903 | m_log.ErrorFormat("[XEngine]: File {0} already exists! {1}", path, ex.Message); | 2008 | m_log.ErrorFormat("[XEngine]: Error whilst writing assembly file {0}, {1}", path, ex.Message); |
1904 | } | 2009 | } |
2010 | |||
2011 | string textpath = path + ".text"; | ||
1905 | try | 2012 | try |
1906 | { | 2013 | { |
1907 | using (FileStream fs = File.Create(path + ".text")) | 2014 | using (FileStream fs = File.Create(textpath)) |
1908 | { | 2015 | { |
1909 | using (StreamWriter sw = new StreamWriter(fs)) | 2016 | using (StreamWriter sw = new StreamWriter(fs)) |
1910 | { | 2017 | { |
2018 | // m_log.DebugFormat("[XEngine]: Writing .text file {0}", textpath); | ||
2019 | |||
1911 | sw.Write(base64); | 2020 | sw.Write(base64); |
1912 | sw.Close(); | ||
1913 | } | 2021 | } |
1914 | fs.Close(); | ||
1915 | } | 2022 | } |
1916 | } | 2023 | } |
1917 | catch (IOException ex) | 2024 | catch (IOException ex) |
1918 | { | 2025 | { |
1919 | // if there already exists a file at that location, it may be locked. | 2026 | // if there already exists a file at that location, it may be locked. |
1920 | m_log.ErrorFormat("[XEngine]: File {0} already exists! {1}", path, ex.Message); | 2027 | m_log.ErrorFormat("[XEngine]: Error whilst writing .text file {0}, {1}", textpath, ex.Message); |
2028 | } | ||
2029 | } | ||
2030 | |||
2031 | XmlNodeList mapL = rootE.GetElementsByTagName("LineMap"); | ||
2032 | if (mapL.Count > 0) | ||
2033 | { | ||
2034 | XmlElement mapE = (XmlElement)mapL[0]; | ||
2035 | |||
2036 | string mappath = Path.Combine(m_ScriptEnginesPath, World.RegionInfo.RegionID.ToString()); | ||
2037 | mappath = Path.Combine(mappath, mapE.GetAttribute("Filename")); | ||
2038 | |||
2039 | try | ||
2040 | { | ||
2041 | using (FileStream mfs = File.Create(mappath)) | ||
2042 | { | ||
2043 | using (StreamWriter msw = new StreamWriter(mfs)) | ||
2044 | { | ||
2045 | // m_log.DebugFormat("[XEngine]: Writing linemap file {0}", mappath); | ||
2046 | |||
2047 | msw.Write(mapE.InnerText); | ||
2048 | } | ||
2049 | } | ||
2050 | } | ||
2051 | catch (IOException ex) | ||
2052 | { | ||
2053 | // if there already exists a file at that location, it may be locked. | ||
2054 | m_log.ErrorFormat("[XEngine]: Linemap file {0} already exists! {1}", mappath, ex.Message); | ||
1921 | } | 2055 | } |
1922 | } | 2056 | } |
1923 | } | 2057 | } |
@@ -1931,43 +2065,16 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
1931 | { | 2065 | { |
1932 | using (StreamWriter ssw = new StreamWriter(sfs)) | 2066 | using (StreamWriter ssw = new StreamWriter(sfs)) |
1933 | { | 2067 | { |
2068 | // m_log.DebugFormat("[XEngine]: Writing state file {0}", statepath); | ||
2069 | |||
1934 | ssw.Write(stateE.OuterXml); | 2070 | ssw.Write(stateE.OuterXml); |
1935 | ssw.Close(); | ||
1936 | } | 2071 | } |
1937 | sfs.Close(); | ||
1938 | } | 2072 | } |
1939 | } | 2073 | } |
1940 | catch (IOException ex) | 2074 | catch (IOException ex) |
1941 | { | 2075 | { |
1942 | // if there already exists a file at that location, it may be locked. | 2076 | // if there already exists a file at that location, it may be locked. |
1943 | m_log.ErrorFormat("[XEngine]: File {0} already exists! {1}", statepath, ex.Message); | 2077 | m_log.ErrorFormat("[XEngine]: Error whilst writing state file {0}, {1}", statepath, ex.Message); |
1944 | } | ||
1945 | |||
1946 | XmlNodeList mapL = rootE.GetElementsByTagName("LineMap"); | ||
1947 | if (mapL.Count > 0) | ||
1948 | { | ||
1949 | XmlElement mapE = (XmlElement)mapL[0]; | ||
1950 | |||
1951 | string mappath = Path.Combine(m_ScriptEnginesPath, World.RegionInfo.RegionID.ToString()); | ||
1952 | mappath = Path.Combine(mappath, mapE.GetAttribute("Filename")); | ||
1953 | |||
1954 | try | ||
1955 | { | ||
1956 | using (FileStream mfs = File.Create(mappath)) | ||
1957 | { | ||
1958 | using (StreamWriter msw = new StreamWriter(mfs)) | ||
1959 | { | ||
1960 | msw.Write(mapE.InnerText); | ||
1961 | msw.Close(); | ||
1962 | } | ||
1963 | mfs.Close(); | ||
1964 | } | ||
1965 | } | ||
1966 | catch (IOException ex) | ||
1967 | { | ||
1968 | // if there already exists a file at that location, it may be locked. | ||
1969 | m_log.ErrorFormat("[XEngine]: File {0} already exists! {1}", statepath, ex.Message); | ||
1970 | } | ||
1971 | } | 2078 | } |
1972 | 2079 | ||
1973 | return true; | 2080 | return true; |
@@ -2001,45 +2108,59 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
2001 | if (!topScripts.ContainsKey(si.LocalID)) | 2108 | if (!topScripts.ContainsKey(si.LocalID)) |
2002 | topScripts[si.RootLocalID] = 0; | 2109 | topScripts[si.RootLocalID] = 0; |
2003 | 2110 | ||
2004 | // long ticksElapsed = tickNow - si.MeasurementPeriodTickStart; | 2111 | topScripts[si.RootLocalID] += CalculateAdjustedExectionTime(si, tickNow); |
2005 | // float framesElapsed = ticksElapsed / (18.1818 * TimeSpan.TicksPerMillisecond); | 2112 | } |
2006 | 2113 | } | |
2007 | // Execution time of the script adjusted by it's measurement period to make scripts started at | ||
2008 | // different times comparable. | ||
2009 | // float adjustedExecutionTime | ||
2010 | // = (float)si.MeasurementPeriodExecutionTime | ||
2011 | // / ((float)(tickNow - si.MeasurementPeriodTickStart) / ScriptInstance.MaxMeasurementPeriod) | ||
2012 | // / TimeSpan.TicksPerMillisecond; | ||
2013 | |||
2014 | long ticksElapsed = tickNow - si.MeasurementPeriodTickStart; | ||
2015 | |||
2016 | // Avoid divide by zerp | ||
2017 | if (ticksElapsed == 0) | ||
2018 | ticksElapsed = 1; | ||
2019 | 2114 | ||
2020 | // Scale execution time to the ideal 55 fps frame time for these reasons. | 2115 | return topScripts; |
2021 | // | 2116 | } |
2022 | // 1) XEngine does not execute scripts per frame, unlike other script engines. Hence, there is no | ||
2023 | // 'script execution time per frame', which is the original purpose of this value. | ||
2024 | // | ||
2025 | // 2) Giving the raw execution times is misleading since scripts start at different times, making | ||
2026 | // it impossible to compare scripts. | ||
2027 | // | ||
2028 | // 3) Scaling the raw execution time to the time that the script has been running is better but | ||
2029 | // is still misleading since a script that has just been rezzed may appear to have been running | ||
2030 | // for much longer. | ||
2031 | // | ||
2032 | // 4) Hence, we scale execution time to an idealised frame time (55 fps). This is also not perfect | ||
2033 | // since the figure does not represent actual execution time and very hard running scripts will | ||
2034 | // never exceed 18ms (though this is a very high number for script execution so is a warning sign). | ||
2035 | float adjustedExecutionTime | ||
2036 | = ((float)si.MeasurementPeriodExecutionTime / ticksElapsed) * 18.1818f; | ||
2037 | 2117 | ||
2038 | topScripts[si.RootLocalID] += adjustedExecutionTime; | 2118 | public float GetScriptExecutionTime(List<UUID> itemIDs) |
2119 | { | ||
2120 | if (itemIDs == null|| itemIDs.Count == 0) | ||
2121 | { | ||
2122 | return 0.0f; | ||
2123 | } | ||
2124 | float time = 0.0f; | ||
2125 | long tickNow = Util.EnvironmentTickCount(); | ||
2126 | IScriptInstance si; | ||
2127 | // Calculate the time for all scripts that this engine is executing | ||
2128 | // Ignore any others | ||
2129 | foreach (UUID id in itemIDs) | ||
2130 | { | ||
2131 | si = GetInstance(id); | ||
2132 | if (si != null && si.Running) | ||
2133 | { | ||
2134 | time += CalculateAdjustedExectionTime(si, tickNow); | ||
2039 | } | 2135 | } |
2040 | } | 2136 | } |
2137 | return time; | ||
2138 | } | ||
2041 | 2139 | ||
2042 | return topScripts; | 2140 | private float CalculateAdjustedExectionTime(IScriptInstance si, long tickNow) |
2141 | { | ||
2142 | long ticksElapsed = tickNow - si.MeasurementPeriodTickStart; | ||
2143 | |||
2144 | // Avoid divide by zero | ||
2145 | if (ticksElapsed == 0) | ||
2146 | ticksElapsed = 1; | ||
2147 | |||
2148 | // Scale execution time to the ideal 55 fps frame time for these reasons. | ||
2149 | // | ||
2150 | // 1) XEngine does not execute scripts per frame, unlike other script engines. Hence, there is no | ||
2151 | // 'script execution time per frame', which is the original purpose of this value. | ||
2152 | // | ||
2153 | // 2) Giving the raw execution times is misleading since scripts start at different times, making | ||
2154 | // it impossible to compare scripts. | ||
2155 | // | ||
2156 | // 3) Scaling the raw execution time to the time that the script has been running is better but | ||
2157 | // is still misleading since a script that has just been rezzed may appear to have been running | ||
2158 | // for much longer. | ||
2159 | // | ||
2160 | // 4) Hence, we scale execution time to an idealised frame time (55 fps). This is also not perfect | ||
2161 | // since the figure does not represent actual execution time and very hard running scripts will | ||
2162 | // never exceed 18ms (though this is a very high number for script execution so is a warning sign). | ||
2163 | return ((float)si.MeasurementPeriodExecutionTime / ticksElapsed) * 18.1818f; | ||
2043 | } | 2164 | } |
2044 | 2165 | ||
2045 | public void SuspendScript(UUID itemID) | 2166 | public void SuspendScript(UUID itemID) |