From 1bed3aff0b21102f04481b2345a0d804c2e5716c Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Mon, 26 Jan 2015 23:16:06 +0000 Subject: On a multi-region simulator when AppDomain = true, make sure the DLL from the appropriate script engines subdir is loaded rather than always that of the first engine to load the DLL. This resolves a DLL load failure on my Linux box when an attachment script was present on another region before the avatar arrived. --- .../ScriptEngine/Shared/CodeTools/Compiler.cs | 8 +- .../ScriptEngine/Shared/Instance/ScriptInstance.cs | 109 ++++++------------- .../Shared/Instance/Tests/CoopTerminationTests.cs | 3 +- OpenSim/Region/ScriptEngine/XEngine/XEngine.cs | 118 +++++++++++++++++++-- 4 files changed, 147 insertions(+), 91 deletions(-) (limited to 'OpenSim') diff --git a/OpenSim/Region/ScriptEngine/Shared/CodeTools/Compiler.cs b/OpenSim/Region/ScriptEngine/Shared/CodeTools/Compiler.cs index 52a34a6..af324bf 100644 --- a/OpenSim/Region/ScriptEngine/Shared/CodeTools/Compiler.cs +++ b/OpenSim/Region/ScriptEngine/Shared/CodeTools/Compiler.cs @@ -291,7 +291,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools string source, string asset, UUID ownerUUID, bool alwaysRecompile, out string assembly, out Dictionary, KeyValuePair> linemap) { -// m_log.DebugFormat("[Compiler]: Compiling script\n{0}", Script); +// m_log.DebugFormat("[Compiler]: Checking script for asset {0} in {1}\n{2}", asset, m_scriptEngine.World.Name, source); IScriptModuleComms comms = m_scriptEngine.World.RequestModuleInterface(); @@ -300,12 +300,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools assembly = GetCompilerOutput(asset); +// m_log.DebugFormat("[Compiler]: Retrieved assembly {0} for asset {1} in {2}", assembly, asset, m_scriptEngine.World.Name); + CheckOrCreateScriptsDirectory(); // 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 (!alwaysRecompile && File.Exists(assembly) && File.Exists(assembly + ".text") && File.Exists(assembly + ".map")) { +// m_log.DebugFormat("[Compiler]: Found existing assembly {0} for asset {1} in {2}", assembly, asset, m_scriptEngine.World.Name); + // 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 // don't keep reading the same file from disk multiple times. @@ -315,6 +319,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools return; } +// m_log.DebugFormat("[Compiler]: Compiling assembly {0} for asset {1} in {2}", assembly, asset, m_scriptEngine.World.Name); + if (source == String.Empty) throw new Exception("Cannot find script assembly and no script text present"); diff --git a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs index b4b4fa0..5ff56a1 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs @@ -259,65 +259,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance /// /// /// false if load failed, true if suceeded - public bool Load(AppDomain dom, Assembly scriptAssembly, string dataPath, StateSource stateSource) + public bool Load( + IScript script, EventWaitHandle coopSleepHandle, string assemblyPath, + string dataPath, StateSource stateSource, bool coopTermination) { - m_assemblyPath = scriptAssembly.Location; + m_Script = script; + m_coopSleepHandle = coopSleepHandle; + m_assemblyPath = assemblyPath; m_dataPath = dataPath; m_stateSource = stateSource; - - try - { - object[] constructorParams; - 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 - { - m_coopTermination = false; - scriptType = scriptAssembly.GetType("SecondLife.Script"); - constructorParams = null; - } - - if (dom != System.AppDomain.CurrentDomain) - m_Script - = (IScript)dom.CreateInstanceAndUnwrap( - Path.GetFileNameWithoutExtension(m_assemblyPath), - scriptType.FullName, - false, - BindingFlags.Default, - null, - constructorParams, - null, - null, - null); - else - m_Script - = (IScript)scriptAssembly.CreateInstance( - scriptType.FullName, - false, - BindingFlags.Default, - null, - constructorParams, - null, - null); - - //ILease lease = (ILease)RemotingServices.GetLifetimeService(m_Script as ScriptBaseClass); - //RemotingServices.GetLifetimeService(m_Script as ScriptBaseClass); -// lease.Register(this); - } - catch (Exception e) - { - 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, scriptAssembly.Location, e.Message, e.StackTrace); - - return false; - } + m_coopTermination = coopTermination; ApiManager am = new ApiManager(); @@ -334,7 +285,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance m_Script.InitApi(kv.Key, kv.Value); } -// // m_log.Debug("[Script] Script instance created"); + // // m_log.Debug("[Script] Script instance created"); Part.SetScriptEvents(ItemID, (int)m_Script.GetStateEventFlags(State)); } @@ -352,9 +303,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance if (File.Exists(savedState)) { -// m_log.DebugFormat( -// "[SCRIPT INSTANCE]: Found state for script {0} for {1} ({2}) at {3} in {4}", -// ItemID, savedState, Part.Name, Part.ParentGroup.Name, Part.ParentGroup.Scene.Name); + // m_log.DebugFormat( + // "[SCRIPT INSTANCE]: Found state for script {0} for {1} ({2}) at {3} in {4}", + // ItemID, savedState, Part.Name, Part.ParentGroup.Name, Part.ParentGroup.Scene.Name); string xml = String.Empty; @@ -375,13 +326,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance ScriptSerializer.Deserialize(xml, this); AsyncCommandManager.CreateFromData(Engine, - LocalID, ItemID, ObjectID, - PluginData); + LocalID, ItemID, ObjectID, + PluginData); -// m_log.DebugFormat("[Script] Successfully retrieved state for script {0}.{1}", PrimName, m_ScriptName); + // m_log.DebugFormat("[Script] Successfully retrieved state for script {0}.{1}", PrimName, m_ScriptName); Part.SetScriptEvents(ItemID, - (int)m_Script.GetStateEventFlags(State)); + (int)m_Script.GetStateEventFlags(State)); if (!Running) m_startOnInit = false; @@ -401,26 +352,26 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance if (!StatePersistedHere) RemoveState(); } -// else -// { -// m_log.WarnFormat( -// "[SCRIPT INSTANCE]: Not starting script {0} (id {1}) in part {2} (id {3}) in object {4} in {5}. Unable to load script state file {6}. Memory limit exceeded.", -// ScriptTask.Name, ScriptTask.ItemID, Part.Name, Part.UUID, Part.ParentGroup.Name, Engine.World.Name, savedState); -// } + // else + // { + // m_log.WarnFormat( + // "[SCRIPT INSTANCE]: Not starting script {0} (id {1}) in part {2} (id {3}) in object {4} in {5}. Unable to load script state file {6}. Memory limit exceeded.", + // ScriptTask.Name, ScriptTask.ItemID, Part.Name, Part.UUID, Part.ParentGroup.Name, Engine.World.Name, savedState); + // } } catch (Exception e) { - m_log.ErrorFormat( - "[SCRIPT INSTANCE]: Not starting script {0} (id {1}) in part {2} (id {3}) in object {4} in {5}. Unable to load script state file {6}. XML is {7}. Exception {8}{9}", - ScriptTask.Name, ScriptTask.ItemID, Part.Name, Part.UUID, Part.ParentGroup.Name, Engine.World.Name, savedState, xml, e.Message, e.StackTrace); + m_log.ErrorFormat( + "[SCRIPT INSTANCE]: Not starting script {0} (id {1}) in part {2} (id {3}) in object {4} in {5}. Unable to load script state file {6}. XML is {7}. Exception {8}{9}", + ScriptTask.Name, ScriptTask.ItemID, Part.Name, Part.UUID, Part.ParentGroup.Name, Engine.World.Name, savedState, xml, e.Message, e.StackTrace); } } -// else -// { -// m_log.DebugFormat( -// "[SCRIPT INSTANCE]: Did not find state for script {0} for {1} ({2}) at {3} in {4}", -// ItemID, savedState, Part.Name, Part.ParentGroup.Name, Part.ParentGroup.Scene.Name); -// } + // else + // { + // m_log.DebugFormat( + // "[SCRIPT INSTANCE]: Did not find state for script {0} for {1} ({2}) at {3} in {4}", + // ItemID, savedState, Part.Name, Part.ParentGroup.Name, Part.ParentGroup.Scene.Name); + // } return true; } diff --git a/OpenSim/Region/ScriptEngine/Shared/Instance/Tests/CoopTerminationTests.cs b/OpenSim/Region/ScriptEngine/Shared/Instance/Tests/CoopTerminationTests.cs index 1fff6ba..5b9794b 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Instance/Tests/CoopTerminationTests.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Instance/Tests/CoopTerminationTests.cs @@ -76,6 +76,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance.Tests //AppDomain.CurrentDomain.SetData("APPBASE", Environment.CurrentDirectory + "/bin"); // Console.WriteLine(AppDomain.CurrentDomain.BaseDirectory); m_xEngine = new OpenSim.Region.ScriptEngine.XEngine.XEngine(); + m_xEngine.DebugLevel = 1; IniConfigSource configSource = new IniConfigSource(); @@ -336,7 +337,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance.Tests public void TestStopOnInfiniteJumpLoop() { TestHelpers.InMethod(); -// TestHelpers.EnableLogging(); + TestHelpers.EnableLogging(); string script = @"default diff --git a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs index c8029d7..dd5bc0d 100644 --- a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs +++ b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs @@ -1327,22 +1327,116 @@ namespace OpenSim.Region.ScriptEngine.XEngine } m_DomainScripts[appDomain].Add(itemID); - Assembly scriptAssembly = m_AppDomains[appDomain].Load(Path.GetFileNameWithoutExtension(assemblyPath)); + IScript scriptObj = null; bool recompile = false; + bool abortAfterRecompile = false; + EventWaitHandle coopSleepHandle = null; + bool coopTerminationForThisScript; + string typeName; + + // Set up assembly name to point to the appropriate scriptEngines directory + AssemblyName assemblyName = new AssemblyName(Path.GetFileNameWithoutExtension(assemblyPath)); + assemblyName.CodeBase = Path.GetDirectoryName(assemblyPath); if (m_coopTermination) { - Type scriptType = scriptAssembly.GetType("SecondLife.XEngineScript"); + try + { + coopSleepHandle = new XEngineEventWaitHandle(false, EventResetMode.AutoReset); + + scriptObj + = (IScript)m_AppDomains[appDomain].CreateInstanceAndUnwrap( + assemblyName.FullName, + "SecondLife.XEngineScript", + false, + BindingFlags.Default, + null, + new object[] { coopSleepHandle }, + null, + null); + + coopTerminationForThisScript = true; + } + catch (TypeLoadException e) + { + coopSleepHandle = null; - if (scriptType == null) + try + { + scriptObj + = (IScript)m_AppDomains[appDomain].CreateInstanceAndUnwrap( + assemblyName.FullName, + "SecondLife.Script", + false, + BindingFlags.Default, + null, + null, + null, + null); + } + catch (Exception e2) + { + m_log.Error( + string.Format( + "[XENGINE]: Could not load previous SecondLife.Script from assembly {0} in {1}. Recompiling then aborting. Exception ", + assemblyName.FullName, World.Name), + e2); + + abortAfterRecompile = true; + } + + coopTerminationForThisScript = false; recompile = true; + } } else { - Type scriptType = scriptAssembly.GetType("SecondLife.Script"); + try + { + scriptObj + = (IScript)m_AppDomains[appDomain].CreateInstanceAndUnwrap( + assemblyName.FullName, + "SecondLife.Script", + false, + BindingFlags.Default, + null, + null, + null, + null); + + coopTerminationForThisScript = false; + } + catch (TypeLoadException e) + { + coopSleepHandle = new XEngineEventWaitHandle(false, EventResetMode.AutoReset); + + try + { + scriptObj + = (IScript)m_AppDomains[appDomain].CreateInstanceAndUnwrap( + assemblyName.FullName, + "SecondLife.XEngineScript", + false, + BindingFlags.Default, + null, + new object[] { new XEngineEventWaitHandle(false, EventResetMode.AutoReset) }, + null, + null); + } + catch (Exception e2) + { + m_log.Error( + string.Format( + "[XENGINE]: Could not load previous SecondLife.XEngineScript from assembly {0} in {1}. Recompiling then aborting. Exception ", + assemblyName.FullName, World.Name), + e2); - if (scriptType == null) + abortAfterRecompile = true; + } + + coopTerminationForThisScript = true; recompile = true; + } } // If we are loading all scripts into the same AppDomain, then we can't reload the DLL in this @@ -1351,12 +1445,15 @@ namespace OpenSim.Region.ScriptEngine.XEngine if (recompile) { m_log.DebugFormat( - "[XEngine]: Recompiling script {0}.{1}, item UUID {2}, prim UUID {3} @ {4}.{5} to switch it to {6} termination. Will be active on next restart.", + "[XEngine]: Recompiling script {0}.{1}, item UUID {2}, prim UUID {3} @ {4}.{5} to switch it to {6} termination. New termination will be active on next restart.", part.ParentGroup.RootPart.Name, item.Name, itemID, part.UUID, part.ParentGroup.RootPart.AbsolutePosition, part.ParentGroup.Scene.Name, m_coopTermination ? "co-op" : "abort"); m_Compiler.PerformScriptCompile(script, assetID.ToString(), item.OwnerID, true, out assemblyPath, out linemap); + + if (abortAfterRecompile) + return false; } instance = new ScriptInstance(this, part, @@ -1364,10 +1461,11 @@ namespace OpenSim.Region.ScriptEngine.XEngine startParam, postOnRez, m_MaxScriptQueue); - if (!instance.Load( - m_AppDomains[appDomain], scriptAssembly, - Path.Combine(ScriptEnginePath, World.RegionInfo.RegionID.ToString()), stateSource)) - return false; + if ( + !instance.Load( + scriptObj, coopSleepHandle, assemblyPath, + Path.Combine(ScriptEnginePath, World.RegionInfo.RegionID.ToString()), stateSource, coopTerminationForThisScript)) + return false; // if (DebugLevel >= 1) // m_log.DebugFormat( -- cgit v1.1