diff options
Diffstat (limited to 'OpenSim/Region/ScriptEngine/XEngine/XEngine.cs')
-rw-r--r-- | OpenSim/Region/ScriptEngine/XEngine/XEngine.cs | 368 |
1 files changed, 241 insertions, 127 deletions
diff --git a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs index 2a01fc4..cc783aa 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; |
@@ -284,9 +292,8 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
284 | AppDomain.CurrentDomain.AssemblyResolve += | 292 | AppDomain.CurrentDomain.AssemblyResolve += |
285 | OnAssemblyResolve; | 293 | OnAssemblyResolve; |
286 | 294 | ||
287 | m_log.InfoFormat("[XEngine] Initializing scripts in region {0}", | ||
288 | scene.RegionInfo.RegionName); | ||
289 | m_Scene = scene; | 295 | m_Scene = scene; |
296 | m_log.InfoFormat("[XEngine]: Initializing scripts in region {0}", m_Scene.RegionInfo.RegionName); | ||
290 | 297 | ||
291 | m_MinThreads = m_ScriptConfig.GetInt("MinThreads", 2); | 298 | m_MinThreads = m_ScriptConfig.GetInt("MinThreads", 2); |
292 | m_MaxThreads = m_ScriptConfig.GetInt("MaxThreads", 100); | 299 | m_MaxThreads = m_ScriptConfig.GetInt("MaxThreads", 100); |
@@ -389,9 +396,42 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
389 | "Starts all stopped scripts." | 396 | "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.", | 397 | + "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)); | 398 | (module, cmdparams) => HandleScriptsAction(cmdparams, HandleStartScript)); |
399 | |||
400 | // MainConsole.Instance.Commands.AddCommand( | ||
401 | // "Debug", false, "debug xengine", "debug xengine [<level>]", | ||
402 | // "Turn on detailed xengine debugging.", | ||
403 | // "If level <= 0, then no extra logging is done.\n" | ||
404 | // + "If level >= 1, then we log every time that a script is started.", | ||
405 | // HandleDebugLevelCommand); | ||
392 | } | 406 | } |
393 | 407 | ||
394 | /// <summary> | 408 | /// <summary> |
409 | /// Change debug level | ||
410 | /// </summary> | ||
411 | /// <param name="module"></param> | ||
412 | /// <param name="args"></param> | ||
413 | // private void HandleDebugLevelCommand(string module, string[] args) | ||
414 | // { | ||
415 | // if (args.Length == 3) | ||
416 | // { | ||
417 | // int newDebug; | ||
418 | // if (int.TryParse(args[2], out newDebug)) | ||
419 | // { | ||
420 | // DebugLevel = newDebug; | ||
421 | // MainConsole.Instance.OutputFormat("Debug level set to {0}", newDebug); | ||
422 | // } | ||
423 | // } | ||
424 | // else if (args.Length == 2) | ||
425 | // { | ||
426 | // MainConsole.Instance.OutputFormat("Current debug level is {0}", DebugLevel); | ||
427 | // } | ||
428 | // else | ||
429 | // { | ||
430 | // MainConsole.Instance.Output("Usage: debug xengine 0..1"); | ||
431 | // } | ||
432 | // } | ||
433 | |||
434 | /// <summary> | ||
395 | /// Parse the raw item id into a script instance from the command params if it's present. | 435 | /// Parse the raw item id into a script instance from the command params if it's present. |
396 | /// </summary> | 436 | /// </summary> |
397 | /// <param name="cmdparams"></param> | 437 | /// <param name="cmdparams"></param> |
@@ -799,35 +839,66 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
799 | int colon = firstline.IndexOf(':'); | 839 | int colon = firstline.IndexOf(':'); |
800 | if (firstline.Length > 2 && firstline.Substring(0, 2) == "//" && colon != -1) | 840 | if (firstline.Length > 2 && firstline.Substring(0, 2) == "//" && colon != -1) |
801 | { | 841 | { |
802 | string engineName = firstline.Substring(2, colon-2); | 842 | string engineName = firstline.Substring(2, colon - 2); |
803 | 843 | ||
804 | if (names.Contains(engineName)) | 844 | if (names.Contains(engineName)) |
805 | { | 845 | { |
806 | engine = engineName; | 846 | engine = engineName; |
807 | script = "//" + script.Substring(script.IndexOf(':')+1); | 847 | script = "//" + script.Substring(colon + 1); |
808 | } | 848 | } |
809 | else | 849 | else |
810 | { | 850 | { |
811 | if (engine == ScriptEngineName) | 851 | if (engine == ScriptEngineName) |
812 | { | 852 | { |
813 | SceneObjectPart part = | 853 | // If we are falling back on XEngine as the default engine, then only complain to the user |
814 | m_Scene.GetSceneObjectPart( | 854 | // if a script language has been explicitly set and it's one that we recognize or there are |
815 | localID); | 855 | // no non-whitespace characters after the colon. |
816 | 856 | // | |
817 | TaskInventoryItem item = | 857 | // If the script is |
818 | part.Inventory.GetInventoryItem(itemID); | 858 | // explicitly not allowed or the script is not in LSL then the user will be informed by a later compiler message. |
819 | 859 | // | |
820 | ScenePresence presence = | 860 | // If the colon ends the line then we'll risk the false positive as this is more likely |
821 | m_Scene.GetScenePresence( | 861 | // to signal a real scriptengine line where the user wants to use the default compile language. |
822 | item.OwnerID); | 862 | // |
823 | 863 | // This avoids the overwhelming number of false positives where we're in this code because | |
824 | if (presence != null) | 864 | // there's a colon in a comment in the first line of a script for entirely |
865 | // unrelated reasons (e.g. vim settings). | ||
866 | // | ||
867 | // TODO: A better fix would be to deprecate simple : detection and look for some less likely | ||
868 | // string to begin the comment (like #! in unix shell scripts). | ||
869 | bool warnRunningInXEngine = false; | ||
870 | string restOfFirstLine = firstline.Substring(colon + 1); | ||
871 | |||
872 | // FIXME: These are hardcoded because they are currently hardcoded in Compiler.cs | ||
873 | if (restOfFirstLine.StartsWith("c#") | ||
874 | || restOfFirstLine.StartsWith("vb") | ||
875 | || restOfFirstLine.StartsWith("lsl") | ||
876 | || restOfFirstLine.StartsWith("js") | ||
877 | || restOfFirstLine.StartsWith("yp") | ||
878 | || restOfFirstLine.Length == 0) | ||
879 | warnRunningInXEngine = true; | ||
880 | |||
881 | if (warnRunningInXEngine) | ||
825 | { | 882 | { |
826 | presence.ControllingClient.SendAgentAlertMessage( | 883 | SceneObjectPart part = |
827 | "Selected engine unavailable. "+ | 884 | m_Scene.GetSceneObjectPart( |
828 | "Running script on "+ | 885 | localID); |
829 | ScriptEngineName, | 886 | |
830 | false); | 887 | TaskInventoryItem item = |
888 | part.Inventory.GetInventoryItem(itemID); | ||
889 | |||
890 | ScenePresence presence = | ||
891 | m_Scene.GetScenePresence( | ||
892 | item.OwnerID); | ||
893 | |||
894 | if (presence != null) | ||
895 | { | ||
896 | presence.ControllingClient.SendAgentAlertMessage( | ||
897 | "Selected engine unavailable. "+ | ||
898 | "Running script on "+ | ||
899 | ScriptEngineName, | ||
900 | false); | ||
901 | } | ||
831 | } | 902 | } |
832 | } | 903 | } |
833 | } | 904 | } |
@@ -884,20 +955,31 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
884 | { | 955 | { |
885 | if (m_InitialStartup) | 956 | if (m_InitialStartup) |
886 | { | 957 | { |
887 | m_InitialStartup = false; | 958 | // This delay exists to stop mono problems where script compilation and startup would stop the sim |
959 | // working properly for the session. | ||
888 | System.Threading.Thread.Sleep(15000); | 960 | System.Threading.Thread.Sleep(15000); |
961 | } | ||
889 | 962 | ||
890 | if (m_CompileQueue.Count == 0) | 963 | object[] o; |
964 | |||
965 | int scriptsStarted = 0; | ||
966 | |||
967 | while (m_CompileQueue.Dequeue(out o)) | ||
968 | { | ||
969 | if (DoOnRezScript(o)) | ||
891 | { | 970 | { |
892 | // No scripts on region, so won't get triggered later | 971 | scriptsStarted++; |
893 | // by the queue becoming empty so we trigger it here | 972 | |
894 | m_Scene.EventManager.TriggerEmptyScriptCompileQueue(0, String.Empty); | 973 | if (m_InitialStartup) |
974 | if (scriptsStarted % 50 == 0) | ||
975 | m_log.InfoFormat( | ||
976 | "[XEngine]: Started {0} scripts in {1}", scriptsStarted, m_Scene.RegionInfo.RegionName); | ||
895 | } | 977 | } |
896 | } | 978 | } |
897 | 979 | ||
898 | object[] o; | 980 | if (m_InitialStartup) |
899 | while (m_CompileQueue.Dequeue(out o)) | 981 | m_log.InfoFormat( |
900 | DoOnRezScript(o); | 982 | "[XEngine]: Completed starting {0} scripts on {1}", scriptsStarted, m_Scene.RegionInfo.RegionName); |
901 | 983 | ||
902 | // NOTE: Despite having a lockless queue, this lock is required | 984 | // NOTE: Despite having a lockless queue, this lock is required |
903 | // to make sure there is never no compile thread while there | 985 | // to make sure there is never no compile thread while there |
@@ -905,12 +987,13 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
905 | // due to a race condition | 987 | // due to a race condition |
906 | // | 988 | // |
907 | lock (m_CompileQueue) | 989 | lock (m_CompileQueue) |
908 | { | ||
909 | m_CurrentCompile = null; | 990 | m_CurrentCompile = null; |
910 | } | 991 | |
911 | m_Scene.EventManager.TriggerEmptyScriptCompileQueue(m_ScriptFailCount, | 992 | m_Scene.EventManager.TriggerEmptyScriptCompileQueue(m_ScriptFailCount, |
912 | m_ScriptErrorMessage); | 993 | m_ScriptErrorMessage); |
994 | |||
913 | m_ScriptFailCount = 0; | 995 | m_ScriptFailCount = 0; |
996 | m_InitialStartup = false; | ||
914 | 997 | ||
915 | return null; | 998 | return null; |
916 | } | 999 | } |
@@ -1093,11 +1176,18 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
1093 | 1176 | ||
1094 | AppDomain sandbox; | 1177 | AppDomain sandbox; |
1095 | if (m_AppDomainLoading) | 1178 | if (m_AppDomainLoading) |
1179 | { | ||
1096 | sandbox = AppDomain.CreateDomain( | 1180 | sandbox = AppDomain.CreateDomain( |
1097 | m_Scene.RegionInfo.RegionID.ToString(), | 1181 | m_Scene.RegionInfo.RegionID.ToString(), |
1098 | evidence, appSetup); | 1182 | evidence, appSetup); |
1183 | m_AppDomains[appDomain].AssemblyResolve += | ||
1184 | new ResolveEventHandler( | ||
1185 | AssemblyResolver.OnAssemblyResolve); | ||
1186 | } | ||
1099 | else | 1187 | else |
1188 | { | ||
1100 | sandbox = AppDomain.CurrentDomain; | 1189 | sandbox = AppDomain.CurrentDomain; |
1190 | } | ||
1101 | 1191 | ||
1102 | //PolicyLevel sandboxPolicy = PolicyLevel.CreateAppDomainLevel(); | 1192 | //PolicyLevel sandboxPolicy = PolicyLevel.CreateAppDomainLevel(); |
1103 | //AllMembershipCondition sandboxMembershipCondition = new AllMembershipCondition(); | 1193 | //AllMembershipCondition sandboxMembershipCondition = new AllMembershipCondition(); |
@@ -1109,9 +1199,6 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
1109 | 1199 | ||
1110 | m_AppDomains[appDomain] = sandbox; | 1200 | m_AppDomains[appDomain] = sandbox; |
1111 | 1201 | ||
1112 | m_AppDomains[appDomain].AssemblyResolve += | ||
1113 | new ResolveEventHandler( | ||
1114 | AssemblyResolver.OnAssemblyResolve); | ||
1115 | m_DomainScripts[appDomain] = new List<UUID>(); | 1202 | m_DomainScripts[appDomain] = new List<UUID>(); |
1116 | } | 1203 | } |
1117 | catch (Exception e) | 1204 | catch (Exception e) |
@@ -1396,25 +1483,24 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
1396 | return false; | 1483 | return false; |
1397 | 1484 | ||
1398 | uuids = m_PrimObjects[localID]; | 1485 | uuids = m_PrimObjects[localID]; |
1399 | |||
1400 | 1486 | ||
1401 | foreach (UUID itemID in uuids) | 1487 | foreach (UUID itemID in uuids) |
1402 | { | ||
1403 | IScriptInstance instance = null; | ||
1404 | try | ||
1405 | { | 1488 | { |
1406 | if (m_Scripts.ContainsKey(itemID)) | 1489 | IScriptInstance instance = null; |
1407 | instance = m_Scripts[itemID]; | 1490 | try |
1408 | } | 1491 | { |
1409 | catch { /* ignore race conditions */ } | 1492 | if (m_Scripts.ContainsKey(itemID)) |
1410 | 1493 | instance = m_Scripts[itemID]; | |
1411 | if (instance != null) | 1494 | } |
1412 | { | 1495 | catch { /* ignore race conditions */ } |
1413 | instance.PostEvent(p); | 1496 | |
1414 | result = true; | 1497 | if (instance != null) |
1498 | { | ||
1499 | instance.PostEvent(p); | ||
1500 | result = true; | ||
1501 | } | ||
1415 | } | 1502 | } |
1416 | } | 1503 | } |
1417 | } | ||
1418 | 1504 | ||
1419 | return result; | 1505 | return result; |
1420 | } | 1506 | } |
@@ -1539,6 +1625,13 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
1539 | } | 1625 | } |
1540 | } | 1626 | } |
1541 | 1627 | ||
1628 | public void SetRunEnable(UUID instanceID, bool enable) | ||
1629 | { | ||
1630 | IScriptInstance instance = GetInstance(instanceID); | ||
1631 | if (instance != null) | ||
1632 | instance.Run = enable; | ||
1633 | } | ||
1634 | |||
1542 | public bool GetScriptState(UUID itemID) | 1635 | public bool GetScriptState(UUID itemID) |
1543 | { | 1636 | { |
1544 | IScriptInstance instance = GetInstance(itemID); | 1637 | IScriptInstance instance = GetInstance(itemID); |
@@ -1573,7 +1666,11 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
1573 | { | 1666 | { |
1574 | IScriptInstance instance = GetInstance(itemID); | 1667 | IScriptInstance instance = GetInstance(itemID); |
1575 | if (instance != null) | 1668 | if (instance != null) |
1576 | instance.Stop(0); | 1669 | { |
1670 | // Give the script some time to finish processing its last event. Simply aborting the script thread can | ||
1671 | // cause issues on mono 2.6, 2.10 and possibly later where locks are not released properly on abort. | ||
1672 | instance.Stop(1000); | ||
1673 | } | ||
1577 | } | 1674 | } |
1578 | 1675 | ||
1579 | public DetectParams GetDetectParams(UUID itemID, int idx) | 1676 | public DetectParams GetDetectParams(UUID itemID, int idx) |
@@ -1749,14 +1846,15 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
1749 | FileMode.Open, FileAccess.Read)) | 1846 | FileMode.Open, FileAccess.Read)) |
1750 | { | 1847 | { |
1751 | tfs.Read(tdata, 0, tdata.Length); | 1848 | tfs.Read(tdata, 0, tdata.Length); |
1752 | tfs.Close(); | ||
1753 | } | 1849 | } |
1754 | 1850 | ||
1755 | assem = new System.Text.ASCIIEncoding().GetString(tdata); | 1851 | assem = new System.Text.ASCIIEncoding().GetString(tdata); |
1756 | } | 1852 | } |
1757 | catch (Exception e) | 1853 | catch (Exception e) |
1758 | { | 1854 | { |
1759 | m_log.DebugFormat("[XEngine]: Unable to open script textfile {0}, reason: {1}", assemName+".text", e.Message); | 1855 | m_log.ErrorFormat( |
1856 | "[XEngine]: Unable to open script textfile {0}{1}, reason: {2}", | ||
1857 | assemName, ".text", e.Message); | ||
1760 | } | 1858 | } |
1761 | } | 1859 | } |
1762 | } | 1860 | } |
@@ -1773,16 +1871,15 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
1773 | using (FileStream fs = File.Open(assemName, FileMode.Open, FileAccess.Read)) | 1871 | using (FileStream fs = File.Open(assemName, FileMode.Open, FileAccess.Read)) |
1774 | { | 1872 | { |
1775 | fs.Read(data, 0, data.Length); | 1873 | fs.Read(data, 0, data.Length); |
1776 | fs.Close(); | ||
1777 | } | 1874 | } |
1778 | 1875 | ||
1779 | assem = System.Convert.ToBase64String(data); | 1876 | assem = System.Convert.ToBase64String(data); |
1780 | } | 1877 | } |
1781 | catch (Exception e) | 1878 | catch (Exception e) |
1782 | { | 1879 | { |
1783 | m_log.DebugFormat("[XEngine]: Unable to open script assembly {0}, reason: {1}", assemName, e.Message); | 1880 | m_log.ErrorFormat( |
1881 | "[XEngine]: Unable to open script assembly {0}, reason: {1}", assemName, e.Message); | ||
1784 | } | 1882 | } |
1785 | |||
1786 | } | 1883 | } |
1787 | } | 1884 | } |
1788 | 1885 | ||
@@ -1795,9 +1892,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
1795 | using (StreamReader msr = new StreamReader(mfs)) | 1892 | using (StreamReader msr = new StreamReader(mfs)) |
1796 | { | 1893 | { |
1797 | map = msr.ReadToEnd(); | 1894 | map = msr.ReadToEnd(); |
1798 | msr.Close(); | ||
1799 | } | 1895 | } |
1800 | mfs.Close(); | ||
1801 | } | 1896 | } |
1802 | } | 1897 | } |
1803 | 1898 | ||
@@ -1833,6 +1928,8 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
1833 | 1928 | ||
1834 | public bool SetXMLState(UUID itemID, string xml) | 1929 | public bool SetXMLState(UUID itemID, string xml) |
1835 | { | 1930 | { |
1931 | // m_log.DebugFormat("[XEngine]: Writing state for script item with ID {0}", itemID); | ||
1932 | |||
1836 | if (xml == String.Empty) | 1933 | if (xml == String.Empty) |
1837 | return false; | 1934 | return false; |
1838 | 1935 | ||
@@ -1893,31 +1990,61 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
1893 | { | 1990 | { |
1894 | using (FileStream fs = File.Create(path)) | 1991 | using (FileStream fs = File.Create(path)) |
1895 | { | 1992 | { |
1993 | // m_log.DebugFormat("[XEngine]: Writing assembly file {0}", path); | ||
1994 | |||
1896 | fs.Write(filedata, 0, filedata.Length); | 1995 | fs.Write(filedata, 0, filedata.Length); |
1897 | fs.Close(); | ||
1898 | } | 1996 | } |
1899 | } | 1997 | } |
1900 | catch (IOException ex) | 1998 | catch (IOException ex) |
1901 | { | 1999 | { |
1902 | // if there already exists a file at that location, it may be locked. | 2000 | // 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); | 2001 | m_log.ErrorFormat("[XEngine]: Error whilst writing assembly file {0}, {1}", path, ex.Message); |
1904 | } | 2002 | } |
2003 | |||
2004 | string textpath = path + ".text"; | ||
1905 | try | 2005 | try |
1906 | { | 2006 | { |
1907 | using (FileStream fs = File.Create(path + ".text")) | 2007 | using (FileStream fs = File.Create(textpath)) |
1908 | { | 2008 | { |
1909 | using (StreamWriter sw = new StreamWriter(fs)) | 2009 | using (StreamWriter sw = new StreamWriter(fs)) |
1910 | { | 2010 | { |
2011 | // m_log.DebugFormat("[XEngine]: Writing .text file {0}", textpath); | ||
2012 | |||
1911 | sw.Write(base64); | 2013 | sw.Write(base64); |
1912 | sw.Close(); | ||
1913 | } | 2014 | } |
1914 | fs.Close(); | ||
1915 | } | 2015 | } |
1916 | } | 2016 | } |
1917 | catch (IOException ex) | 2017 | catch (IOException ex) |
1918 | { | 2018 | { |
1919 | // if there already exists a file at that location, it may be locked. | 2019 | // 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); | 2020 | m_log.ErrorFormat("[XEngine]: Error whilst writing .text file {0}, {1}", textpath, ex.Message); |
2021 | } | ||
2022 | } | ||
2023 | |||
2024 | XmlNodeList mapL = rootE.GetElementsByTagName("LineMap"); | ||
2025 | if (mapL.Count > 0) | ||
2026 | { | ||
2027 | XmlElement mapE = (XmlElement)mapL[0]; | ||
2028 | |||
2029 | string mappath = Path.Combine(m_ScriptEnginesPath, World.RegionInfo.RegionID.ToString()); | ||
2030 | mappath = Path.Combine(mappath, mapE.GetAttribute("Filename")); | ||
2031 | |||
2032 | try | ||
2033 | { | ||
2034 | using (FileStream mfs = File.Create(mappath)) | ||
2035 | { | ||
2036 | using (StreamWriter msw = new StreamWriter(mfs)) | ||
2037 | { | ||
2038 | // m_log.DebugFormat("[XEngine]: Writing linemap file {0}", mappath); | ||
2039 | |||
2040 | msw.Write(mapE.InnerText); | ||
2041 | } | ||
2042 | } | ||
2043 | } | ||
2044 | catch (IOException ex) | ||
2045 | { | ||
2046 | // if there already exists a file at that location, it may be locked. | ||
2047 | m_log.ErrorFormat("[XEngine]: Linemap file {0} already exists! {1}", mappath, ex.Message); | ||
1921 | } | 2048 | } |
1922 | } | 2049 | } |
1923 | } | 2050 | } |
@@ -1931,43 +2058,16 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
1931 | { | 2058 | { |
1932 | using (StreamWriter ssw = new StreamWriter(sfs)) | 2059 | using (StreamWriter ssw = new StreamWriter(sfs)) |
1933 | { | 2060 | { |
2061 | // m_log.DebugFormat("[XEngine]: Writing state file {0}", statepath); | ||
2062 | |||
1934 | ssw.Write(stateE.OuterXml); | 2063 | ssw.Write(stateE.OuterXml); |
1935 | ssw.Close(); | ||
1936 | } | 2064 | } |
1937 | sfs.Close(); | ||
1938 | } | 2065 | } |
1939 | } | 2066 | } |
1940 | catch (IOException ex) | 2067 | catch (IOException ex) |
1941 | { | 2068 | { |
1942 | // if there already exists a file at that location, it may be locked. | 2069 | // 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); | 2070 | 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 | } | 2071 | } |
1972 | 2072 | ||
1973 | return true; | 2073 | return true; |
@@ -2001,45 +2101,59 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
2001 | if (!topScripts.ContainsKey(si.LocalID)) | 2101 | if (!topScripts.ContainsKey(si.LocalID)) |
2002 | topScripts[si.RootLocalID] = 0; | 2102 | topScripts[si.RootLocalID] = 0; |
2003 | 2103 | ||
2004 | // long ticksElapsed = tickNow - si.MeasurementPeriodTickStart; | 2104 | topScripts[si.RootLocalID] += CalculateAdjustedExectionTime(si, tickNow); |
2005 | // float framesElapsed = ticksElapsed / (18.1818 * TimeSpan.TicksPerMillisecond); | 2105 | } |
2006 | 2106 | } | |
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 | 2107 | ||
2020 | // Scale execution time to the ideal 55 fps frame time for these reasons. | 2108 | return topScripts; |
2021 | // | 2109 | } |
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 | 2110 | ||
2038 | topScripts[si.RootLocalID] += adjustedExecutionTime; | 2111 | public float GetScriptExecutionTime(List<UUID> itemIDs) |
2112 | { | ||
2113 | if (itemIDs == null|| itemIDs.Count == 0) | ||
2114 | { | ||
2115 | return 0.0f; | ||
2116 | } | ||
2117 | float time = 0.0f; | ||
2118 | long tickNow = Util.EnvironmentTickCount(); | ||
2119 | IScriptInstance si; | ||
2120 | // Calculate the time for all scripts that this engine is executing | ||
2121 | // Ignore any others | ||
2122 | foreach (UUID id in itemIDs) | ||
2123 | { | ||
2124 | si = GetInstance(id); | ||
2125 | if (si != null && si.Running) | ||
2126 | { | ||
2127 | time += CalculateAdjustedExectionTime(si, tickNow); | ||
2039 | } | 2128 | } |
2040 | } | 2129 | } |
2130 | return time; | ||
2131 | } | ||
2041 | 2132 | ||
2042 | return topScripts; | 2133 | private float CalculateAdjustedExectionTime(IScriptInstance si, long tickNow) |
2134 | { | ||
2135 | long ticksElapsed = tickNow - si.MeasurementPeriodTickStart; | ||
2136 | |||
2137 | // Avoid divide by zero | ||
2138 | if (ticksElapsed == 0) | ||
2139 | ticksElapsed = 1; | ||
2140 | |||
2141 | // Scale execution time to the ideal 55 fps frame time for these reasons. | ||
2142 | // | ||
2143 | // 1) XEngine does not execute scripts per frame, unlike other script engines. Hence, there is no | ||
2144 | // 'script execution time per frame', which is the original purpose of this value. | ||
2145 | // | ||
2146 | // 2) Giving the raw execution times is misleading since scripts start at different times, making | ||
2147 | // it impossible to compare scripts. | ||
2148 | // | ||
2149 | // 3) Scaling the raw execution time to the time that the script has been running is better but | ||
2150 | // is still misleading since a script that has just been rezzed may appear to have been running | ||
2151 | // for much longer. | ||
2152 | // | ||
2153 | // 4) Hence, we scale execution time to an idealised frame time (55 fps). This is also not perfect | ||
2154 | // since the figure does not represent actual execution time and very hard running scripts will | ||
2155 | // never exceed 18ms (though this is a very high number for script execution so is a warning sign). | ||
2156 | return ((float)si.MeasurementPeriodExecutionTime / ticksElapsed) * 18.1818f; | ||
2043 | } | 2157 | } |
2044 | 2158 | ||
2045 | public void SuspendScript(UUID itemID) | 2159 | public void SuspendScript(UUID itemID) |