diff --git a/OpenSim/Region/ScriptEngine/Interfaces/ICompiler.cs b/OpenSim/Region/ScriptEngine/Interfaces/ICompiler.cs index e4ca635cfd..a7fa50277d 100644 --- a/OpenSim/Region/ScriptEngine/Interfaces/ICompiler.cs +++ b/OpenSim/Region/ScriptEngine/Interfaces/ICompiler.cs @@ -34,7 +34,36 @@ namespace OpenSim.Region.ScriptEngine.Interfaces { public interface ICompiler { - void PerformScriptCompile(string source, string asset, UUID ownerID, out string assembly, out Dictionary, KeyValuePair> linemap); + /// + /// Performs the script compile. + /// + /// + /// + /// + /// + /// If set to true then always recompile the script, even if we have a DLL already cached. + /// + /// + /// + void PerformScriptCompile( + string source, string asset, UUID ownerID, + out string assembly, out Dictionary, KeyValuePair> linemap); + + /// + /// Performs the script compile. + /// + /// + /// + /// + /// + /// If set to true then always recompile the script, even if we have a DLL already cached. + /// + /// + /// + void PerformScriptCompile( + string source, string asset, UUID ownerID, bool alwaysRecompile, + out string assembly, out Dictionary, KeyValuePair> linemap); + string[] GetWarnings(); } } diff --git a/OpenSim/Region/ScriptEngine/Shared/CodeTools/Compiler.cs b/OpenSim/Region/ScriptEngine/Shared/CodeTools/Compiler.cs index f874de2a5e..98658b6425 100644 --- a/OpenSim/Region/ScriptEngine/Shared/CodeTools/Compiler.cs +++ b/OpenSim/Region/ScriptEngine/Shared/CodeTools/Compiler.cs @@ -284,12 +284,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools return GetCompilerOutput(assetID.ToString()); } - /// - /// Converts script from LSL to CS and calls CompileFromCSText - /// - /// LSL script - /// Filename to .dll assembly - public void PerformScriptCompile(string Script, string asset, UUID ownerUUID, + public void PerformScriptCompile( + string source, string asset, UUID ownerUUID, + out string assembly, out Dictionary, KeyValuePair> linemap) + { + PerformScriptCompile(source, asset, ownerUUID, false, out assembly, out linemap); + } + + public void PerformScriptCompile( + string source, string asset, UUID ownerUUID, bool alwaysRecompile, out string assembly, out Dictionary, KeyValuePair> linemap) { // m_log.DebugFormat("[Compiler]: Compiling script\n{0}", Script); @@ -303,9 +306,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools CheckOrCreateScriptsDirectory(); - // Don't recompile if we already have it + // Don't recompile if we're not forced to and we already have it // Performing 3 file exists tests for every script can still be slow - if (File.Exists(assembly) && File.Exists(assembly + ".text") && File.Exists(assembly + ".map")) + if (!alwaysRecompile && File.Exists(assembly) && File.Exists(assembly + ".text") && File.Exists(assembly + ".map")) { // If we have already read this linemap file, then it will be in our dictionary. // Don't build another copy of the dictionary (saves memory) and certainly @@ -316,29 +319,27 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools return; } - if (Script == String.Empty) - { + if (source == String.Empty) throw new Exception("Cannot find script assembly and no script text present"); - } enumCompileType language = DefaultCompileLanguage; - if (Script.StartsWith("//c#", true, CultureInfo.InvariantCulture)) + if (source.StartsWith("//c#", true, CultureInfo.InvariantCulture)) language = enumCompileType.cs; - if (Script.StartsWith("//vb", true, CultureInfo.InvariantCulture)) + if (source.StartsWith("//vb", true, CultureInfo.InvariantCulture)) { language = enumCompileType.vb; // We need to remove //vb, it won't compile with that - Script = Script.Substring(4, Script.Length - 4); + source = source.Substring(4, source.Length - 4); } - if (Script.StartsWith("//lsl", true, CultureInfo.InvariantCulture)) + if (source.StartsWith("//lsl", true, CultureInfo.InvariantCulture)) language = enumCompileType.lsl; - if (Script.StartsWith("//js", true, CultureInfo.InvariantCulture)) + if (source.StartsWith("//js", true, CultureInfo.InvariantCulture)) language = enumCompileType.js; - if (Script.StartsWith("//yp", true, CultureInfo.InvariantCulture)) + if (source.StartsWith("//yp", true, CultureInfo.InvariantCulture)) language = enumCompileType.yp; // m_log.DebugFormat("[Compiler]: Compile language is {0}", language); @@ -359,13 +360,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools throw new Exception(errtext); } - string compileScript = Script; + string compileScript = source; if (language == enumCompileType.lsl) { // Its LSL, convert it to C# LSL_Converter = (ICodeConverter)new CSCodeGenerator(comms, m_insertCoopTerminationCalls); - compileScript = LSL_Converter.Convert(Script); + compileScript = LSL_Converter.Convert(source); // copy converter warnings into our warnings. foreach (string warning in LSL_Converter.GetWarnings()) diff --git a/OpenSim/Region/ScriptEngine/Shared/CodeTools/Tests/CompilerTest.cs b/OpenSim/Region/ScriptEngine/Shared/CodeTools/Tests/CompilerTest.cs index 938cb2efe8..388de7f675 100644 --- a/OpenSim/Region/ScriptEngine/Shared/CodeTools/Tests/CompilerTest.cs +++ b/OpenSim/Region/ScriptEngine/Shared/CodeTools/Tests/CompilerTest.cs @@ -67,8 +67,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools.Tests } [SetUp] - public void SetUp() + public override void SetUp() { + base.SetUp(); + // Create a CSCodeProvider and CompilerParameters. m_CSCodeProvider = new CSharpCodeProvider(); m_compilerParameters = new CompilerParameters(); diff --git a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs index c5d0752883..979c84ab1d 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs @@ -237,12 +237,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance m_postOnRez = postOnRez; m_AttachedAvatar = Part.ParentGroup.AttachedAvatar; m_RegionID = Part.ParentGroup.Scene.RegionInfo.RegionID; - - if (Engine.Config.GetString("ScriptStopStrategy", "abort") == "co-op") - { - m_coopTermination = true; - m_coopSleepHandle = new XEngineEventWaitHandle(false, EventResetMode.AutoReset); - } } /// @@ -252,54 +246,38 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance /// /// /// false if load failed, true if suceeded - public bool Load(AppDomain dom, string assembly, StateSource stateSource) + public bool Load(AppDomain dom, Assembly scriptAssembly, StateSource stateSource) { - m_Assembly = assembly; + //m_Assembly = scriptAssembly.CodeBase; + m_Assembly = scriptAssembly.Location; m_stateSource = stateSource; - - ApiManager am = new ApiManager(); - - foreach (string api in am.GetApis()) - { - m_Apis[api] = am.CreateApi(api); - m_Apis[api].Initialize(Engine, Part, ScriptTask, m_coopSleepHandle); - } try { object[] constructorParams; - - Assembly scriptAssembly = dom.Load(Path.GetFileNameWithoutExtension(assembly)); Type scriptType = scriptAssembly.GetType("SecondLife.XEngineScript"); if (scriptType != null) { + m_coopTermination = true; + m_coopSleepHandle = new XEngineEventWaitHandle(false, EventResetMode.AutoReset); constructorParams = new object[] { m_coopSleepHandle }; } - else if (!m_coopTermination) - { - scriptType = scriptAssembly.GetType("SecondLife.Script"); - constructorParams = null; - } else { - m_log.ErrorFormat( - "[SCRIPT INSTANCE]: Not starting script {0} (id {1}) in part {2} (id {3}) in object {4} in {5}. You must remove all existing {6}* script DLL files before using enabling co-op termination" - + ", either by setting DeleteScriptsOnStartup = true in [XEngine] for one run" - + " or by deleting these files manually.", - ScriptTask.Name, ScriptTask.ItemID, Part.Name, Part.UUID, Part.ParentGroup.Name, Engine.World.Name, assembly); - - return false; + m_coopTermination = false; + scriptType = scriptAssembly.GetType("SecondLife.Script"); + constructorParams = null; } // m_log.DebugFormat( // "[SCRIPT INSTANCE]: Looking to load {0} from assembly {1} in {2}", -// scriptType.FullName, Path.GetFileNameWithoutExtension(assembly), Engine.World.Name); +// scriptType.FullName, m_Assembly, Engine.World.Name); if (dom != System.AppDomain.CurrentDomain) m_Script = (IScript)dom.CreateInstanceAndUnwrap( - Path.GetFileNameWithoutExtension(assembly), + Path.GetFileNameWithoutExtension(m_Assembly), scriptType.FullName, false, BindingFlags.Default, @@ -327,11 +305,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance { m_log.ErrorFormat( "[SCRIPT INSTANCE]: Not starting script {0} (id {1}) in part {2} (id {3}) in object {4} in {5}. Error loading assembly {6}. Exception {7}{8}", - ScriptTask.Name, ScriptTask.ItemID, Part.Name, Part.UUID, Part.ParentGroup.Name, Engine.World.Name, assembly, e.Message, e.StackTrace); + ScriptTask.Name, ScriptTask.ItemID, Part.Name, Part.UUID, Part.ParentGroup.Name, Engine.World.Name, m_Assembly, e.Message, e.StackTrace); return false; } + ApiManager am = new ApiManager(); + + foreach (string api in am.GetApis()) + { + m_Apis[api] = am.CreateApi(api); + m_Apis[api].Initialize(Engine, Part, ScriptTask, m_coopSleepHandle); + } + try { foreach (KeyValuePair kv in m_Apis) @@ -341,8 +327,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance // // m_log.Debug("[Script] Script instance created"); - Part.SetScriptEvents(ItemID, - (int)m_Script.GetStateEventFlags(State)); + Part.SetScriptEvents(ItemID, (int)m_Script.GetStateEventFlags(State)); } catch (Exception e) { @@ -355,8 +340,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance m_SaveState = true; - string savedState = Path.Combine(Path.GetDirectoryName(assembly), - ItemID.ToString() + ".state"); + string savedState = Path.Combine(Path.GetDirectoryName(m_Assembly), ItemID.ToString() + ".state"); + if (File.Exists(savedState)) { string xml = String.Empty; diff --git a/OpenSim/Region/ScriptEngine/XEngine/Tests/XEngineBasicTests.cs b/OpenSim/Region/ScriptEngine/XEngine/Tests/XEngineBasicTests.cs index 5abfe9a2c8..bafcdd80dd 100644 --- a/OpenSim/Region/ScriptEngine/XEngine/Tests/XEngineBasicTests.cs +++ b/OpenSim/Region/ScriptEngine/XEngine/Tests/XEngineBasicTests.cs @@ -87,7 +87,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine.Tests public void TestCompileAndStartScript() { TestHelpers.InMethod(); -// log4net.Config.XmlConfigurator.Configure(); + TestHelpers.EnableLogging(); UUID userId = TestHelpers.ParseTail(0x1); // UUID objectId = TestHelpers.ParseTail(0x100); diff --git a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs index b261b9fb32..7cb4862e04 100644 --- a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs +++ b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs @@ -86,6 +86,8 @@ namespace OpenSim.Region.ScriptEngine.XEngine /// private int m_StartDelay; + private bool m_coopTermination; + private int m_IdleTimeout; private int m_StackSize; private int m_SleepTime; @@ -246,6 +248,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine if (rawScriptStopStrategy == "co-op") { + m_coopTermination = true; ScriptClassName = "XEngineScript"; ScriptBaseClassName = typeof(XEngineScriptBase).FullName; ScriptBaseClassParameters = typeof(XEngineScriptBase).GetConstructor(new Type[] { typeof(WaitHandle) }).GetParameters(); @@ -1139,7 +1142,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine ScenePresence presence = m_Scene.GetScenePresence(item.OwnerID); - string assembly = ""; + string assemblyPath = ""; Culture.SetCurrentCulture(); @@ -1151,12 +1154,12 @@ namespace OpenSim.Region.ScriptEngine.XEngine { lock (m_AddingAssemblies) { - m_Compiler.PerformScriptCompile(script, assetID.ToString(), item.OwnerID, out assembly, out linemap); + m_Compiler.PerformScriptCompile(script, assetID.ToString(), item.OwnerID, out assemblyPath, out linemap); - if (!m_AddingAssemblies.ContainsKey(assembly)) { - m_AddingAssemblies[assembly] = 1; + if (!m_AddingAssemblies.ContainsKey(assemblyPath)) { + m_AddingAssemblies[assemblyPath] = 1; } else { - m_AddingAssemblies[assembly]++; + m_AddingAssemblies[assemblyPath]++; } } @@ -1301,19 +1304,43 @@ namespace OpenSim.Region.ScriptEngine.XEngine m_ScriptFailCount++; lock (m_AddingAssemblies) { - m_AddingAssemblies[assembly]--; + m_AddingAssemblies[assemblyPath]--; } return false; } } m_DomainScripts[appDomain].Add(itemID); + Assembly scriptAssembly = m_AppDomains[appDomain].Load(Path.GetFileNameWithoutExtension(assemblyPath)); + bool recompile = false; + + if (m_coopTermination) + { + Type scriptType = scriptAssembly.GetType("SecondLife.XEngineScript"); + + if (scriptType == null) + recompile = true; + } + else + { + Type scriptType = scriptAssembly.GetType("SecondLife.Script"); + + if (scriptType == null) + recompile = true; + } + + // If we are loading all scripts into the same AppDomain, then we can't reload the DLL in this + // simulator session if the script halt strategy has been changed. Instead, we'll continue with + // the existing DLL and the new one will be used in the next simulator session. + if (recompile) + m_Compiler.PerformScriptCompile(script, assetID.ToString(), item.OwnerID, true, out assemblyPath, out linemap); + instance = new ScriptInstance(this, part, item, startParam, postOnRez, m_MaxScriptQueue); - if (!instance.Load(m_AppDomains[appDomain], assembly, stateSource)) + if (!instance.Load(m_AppDomains[appDomain], scriptAssembly, stateSource)) return false; // if (DebugLevel >= 1) @@ -1345,11 +1372,11 @@ namespace OpenSim.Region.ScriptEngine.XEngine } if (!m_Assemblies.ContainsKey(assetID)) - m_Assemblies[assetID] = assembly; + m_Assemblies[assetID] = assemblyPath; lock (m_AddingAssemblies) { - m_AddingAssemblies[assembly]--; + m_AddingAssemblies[assemblyPath]--; } if (instance != null)