aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/ScriptEngine/XEngine/XEngine.cs')
-rw-r--r--OpenSim/Region/ScriptEngine/XEngine/XEngine.cs385
1 files changed, 253 insertions, 132 deletions
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)