From 37446b0392ba423894952f81aa0f938d2bd2de22 Mon Sep 17 00:00:00 2001 From: Tedd Hansen Date: Sat, 18 Aug 2007 23:24:38 +0000 Subject: Moved in-AppDomain event execution from Script to OpenSim.Region.ScriptEngine.Executor. Script no longer responsible for handling event calls to itself (and we can create reference cache in Executor). --- OpenSim/Region/ScriptEngine/Common/Executor.cs | 48 ++++++++++++- .../Common/LSL_BuiltIn_Commands_Interface.cs | 1 + .../ScriptEngine/DotNetEngine/AppDomainManager.cs | 66 ++++++++---------- .../DotNetEngine/Compiler/LSL/LSL_BaseClass.cs | 38 +++------- .../Compiler/Server_API/LSL_BuiltIn_Commands.cs | 7 +- .../ScriptEngine/DotNetEngine/EventQueueManager.cs | 2 +- .../ScriptEngine/DotNetEngine/ScriptEngine.cs | 2 +- .../ScriptEngine/DotNetEngine/ScriptManager.cs | 80 ++++------------------ 8 files changed, 107 insertions(+), 137 deletions(-) diff --git a/OpenSim/Region/ScriptEngine/Common/Executor.cs b/OpenSim/Region/ScriptEngine/Common/Executor.cs index 2ae6a60..ca6459b 100644 --- a/OpenSim/Region/ScriptEngine/Common/Executor.cs +++ b/OpenSim/Region/ScriptEngine/Common/Executor.cs @@ -1,10 +1,56 @@ using System; using System.Collections.Generic; using System.Text; +using System.Reflection; namespace OpenSim.Region.ScriptEngine.Common { - class Executor + public class Executor: MarshalByRefObject { + /* TODO: + * + * Needs to be common for all AppDomains - share memory too? + * Needs to have an instance in each AppDomain, and some way of referring it. + * Need to know what AppDomain a script is in so we know where to find our instance. + * + */ + + private IScript m_Script; + + public Executor(IScript Script) + { + m_Script = Script; + } + public void ExecuteEvent(string FunctionName, object[] args) + { + // IMPORTANT: Types and MemberInfo-derived objects require a LOT of memory. + // Instead use RuntimeTypeHandle, RuntimeFieldHandle and RunTimeHandle (IntPtr) instead! + + //foreach (MemberInfo mi in this.GetType().GetMembers()) + //{ + //if (mi.ToString().ToLower().Contains("default")) + //{ + // Console.WriteLine("Member found: " + mi.ToString()); + //} + //} + + Type type = m_Script.GetType(); + + Console.WriteLine("ScriptEngine Executor.ExecuteEvent: \"" + m_Script.State() + "_event_" + FunctionName + "\""); + + try + { + type.InvokeMember(m_Script.State() + "_event_" + FunctionName, BindingFlags.InvokeMethod, null, m_Script, args); + } + catch (Exception e) + { + // TODO: Send to correct place + Console.WriteLine("ScriptEngine Exception attempting to executing script function: " + e.ToString()); + } + + + } + + } } diff --git a/OpenSim/Region/ScriptEngine/Common/LSL_BuiltIn_Commands_Interface.cs b/OpenSim/Region/ScriptEngine/Common/LSL_BuiltIn_Commands_Interface.cs index beddbc5..f80898b 100644 --- a/OpenSim/Region/ScriptEngine/Common/LSL_BuiltIn_Commands_Interface.cs +++ b/OpenSim/Region/ScriptEngine/Common/LSL_BuiltIn_Commands_Interface.cs @@ -34,6 +34,7 @@ namespace OpenSim.Region.ScriptEngine.Common { public interface LSL_BuiltIn_Commands_Interface { + string State(); double llSin(double f); diff --git a/OpenSim/Region/ScriptEngine/DotNetEngine/AppDomainManager.cs b/OpenSim/Region/ScriptEngine/DotNetEngine/AppDomainManager.cs index f80ebac..33e95d3 100644 --- a/OpenSim/Region/ScriptEngine/DotNetEngine/AppDomainManager.cs +++ b/OpenSim/Region/ScriptEngine/DotNetEngine/AppDomainManager.cs @@ -12,9 +12,12 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine { private int MaxScriptsPerAppDomain = 1; /// - /// List of all AppDomains + /// Internal list of all AppDomains /// private List AppDomains = new List(); + /// + /// Structure to keep track of data around AppDomain + /// private struct AppDomainStructure { /// @@ -37,10 +40,11 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine private object GetLock = new object(); // Mutex private object FreeLock = new object(); // Mutex - private ScriptEngine m_scriptEngine; - public AppDomainManager(ScriptEngine scriptEngine) + //private ScriptEngine m_scriptEngine; + //public AppDomainManager(ScriptEngine scriptEngine) + public AppDomainManager() { - m_scriptEngine = scriptEngine; + //m_scriptEngine = scriptEngine; } /// @@ -54,6 +58,7 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine // Current full? if (CurrentAD.ScriptsLoaded >= MaxScriptsPerAppDomain) { + // Add it to AppDomains list and empty current AppDomains.Add(CurrentAD); CurrentAD = new AppDomainStructure(); } @@ -68,7 +73,11 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine } - // Increase number of scripts loaded + // Increase number of scripts loaded into this + // TODO: + // - We assume that every time someone wants an AppDomain they will load into it + // if this assumption is wrong we end up with a miscount and will never unload it. + // CurrentAD.ScriptsLoaded++; // Return AppDomain return CurrentAD.CurrentAppDomain; @@ -84,46 +93,19 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine { // Create and prepare a new AppDomain AppDomainNameCount++; - // TODO: Currently security and configuration match current appdomain + // TODO: Currently security match current appdomain // Construct and initialize settings for a second AppDomain. AppDomainSetup ads = new AppDomainSetup(); ads.ApplicationBase = AppDomain.CurrentDomain.BaseDirectory; - //Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "ScriptEngines"); - //ads.ApplicationName = "DotNetScriptEngine"; - //ads.DynamicBase = ads.ApplicationBase; - - //Console.WriteLine("AppDomain BaseDirectory: " + ads.ApplicationBase); ads.DisallowBindingRedirects = false; ads.DisallowCodeDownload = true; - ads.ShadowCopyFiles = "true"; - - ads.ConfigurationFile = - AppDomain.CurrentDomain.SetupInformation.ConfigurationFile; + ads.ShadowCopyFiles = "true"; // Enabled shadowing + ads.ConfigurationFile = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile; AppDomain AD = AppDomain.CreateDomain("ScriptAppDomain_" + AppDomainNameCount, null, ads); - //foreach (Assembly a in AppDomain.CurrentDomain.GetAssemblies()) - //{ - // //Console.WriteLine("Loading: " + a.GetName(true)); - // try - // { - // //AD.Load(a.GetName(true)); - - // } - // catch (Exception e) - // { - // //Console.WriteLine("FAILED load"); - // } - - //} - //Console.WriteLine("Assembly file: " + this.GetType().Assembly.CodeBase); - //Console.WriteLine("Assembly name: " + this.GetType().ToString()); - //AD.CreateInstanceFrom(this.GetType().Assembly.CodeBase, "OpenSim.Region.ScriptEngine.DotNetEngine.ScriptEngine"); - - //AD.Load(this.GetType().Assembly.CodeBase); - - Console.WriteLine("Done preparing new AppDomain."); + // Return the new AppDomain return AD; } @@ -135,14 +117,19 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine { lock (FreeLock) { + // Go through all foreach (AppDomainStructure ads in new System.Collections.ArrayList(AppDomains)) { + // Don't process current AppDomain if (ads.CurrentAppDomain != CurrentAD.CurrentAppDomain) { // Not current AppDomain - if (ads.ScriptsLoaded == ads.ScriptsWaitingUnload) + // Is number of unloaded bigger or equal to number of loaded? + if (ads.ScriptsLoaded <= ads.ScriptsWaitingUnload) { + // Remove from internal list AppDomains.Remove(ads); + // Unload AppDomain.Unload(ads.CurrentAppDomain); } } @@ -159,16 +146,20 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine { lock (FreeLock) { + // Check if it is current AppDomain if (CurrentAD.CurrentAppDomain == ad) { + // Yes - increase CurrentAD.ScriptsWaitingUnload++; return; } + // Lopp through all AppDomains foreach (AppDomainStructure ads in new System.Collections.ArrayList(AppDomains)) { if (ads.CurrentAppDomain == ad) { + // Found it - messy code to increase structure AppDomainStructure ads2 = ads; ads2.ScriptsWaitingUnload++; AppDomains.Remove(ads); @@ -178,5 +169,6 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine } // foreach } // lock } + } } diff --git a/OpenSim/Region/ScriptEngine/DotNetEngine/Compiler/LSL/LSL_BaseClass.cs b/OpenSim/Region/ScriptEngine/DotNetEngine/Compiler/LSL/LSL_BaseClass.cs index 7334e6f..bfb8913 100644 --- a/OpenSim/Region/ScriptEngine/DotNetEngine/Compiler/LSL/LSL_BaseClass.cs +++ b/OpenSim/Region/ScriptEngine/DotNetEngine/Compiler/LSL/LSL_BaseClass.cs @@ -9,8 +9,17 @@ using System.Reflection; namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.LSL { - public class LSL_BaseClass : MarshalByRefObject, LSL_BuiltIn_Commands_Interface + public class LSL_BaseClass : MarshalByRefObject, LSL_BuiltIn_Commands_Interface, IScript { + private Executor m_Exec; + public Executor Exec { + get + { + if (m_Exec == null) + m_Exec = new Executor(this); + return m_Exec; + } + } public LSL_BuiltIn_Commands_Interface m_LSL_Functions; @@ -48,33 +57,6 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.LSL return; } - public void ExecuteEvent(string FunctionName, object[] args) - { - //foreach (MemberInfo mi in this.GetType().GetMembers()) - //{ - //if (mi.ToString().ToLower().Contains("default")) - //{ - // Console.WriteLine("Member found: " + mi.ToString()); - //} - //} - - Type type = this.GetType(); - - Console.WriteLine("ScriptEngine Invoke: \"" + this.State() + "_event_" + FunctionName + "\""); - - try - { - type.InvokeMember(this.State() + "_event_" + FunctionName, BindingFlags.InvokeMethod, null, this, args); - } - catch (Exception e) - { - // TODO: Send to correct place - Console.WriteLine("ScriptEngine Exception attempting to executing script function: " + e.ToString()); - } - - - } - // diff --git a/OpenSim/Region/ScriptEngine/DotNetEngine/Compiler/Server_API/LSL_BuiltIn_Commands.cs b/OpenSim/Region/ScriptEngine/DotNetEngine/Compiler/Server_API/LSL_BuiltIn_Commands.cs index 297a45c..8982bb6 100644 --- a/OpenSim/Region/ScriptEngine/DotNetEngine/Compiler/Server_API/LSL_BuiltIn_Commands.cs +++ b/OpenSim/Region/ScriptEngine/DotNetEngine/Compiler/Server_API/LSL_BuiltIn_Commands.cs @@ -16,6 +16,7 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler /// public class LSL_BuiltIn_Commands: MarshalByRefObject, LSL_BuiltIn_Commands_Interface { + private System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding(); private ScriptManager m_manager; private IScriptHost m_host; @@ -74,7 +75,7 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler public void llWhisper(int channelID, string text) { //Common.SendToDebug("INTERNAL FUNCTION llWhisper(" + channelID + ", \"" + text + "\");"); - Console.WriteLine("llWhisper Channel " + channelID + ", Text: \"" + text + "\""); + //Console.WriteLine("llWhisper Channel " + channelID + ", Text: \"" + text + "\""); //type for whisper is 0 World.SimChat(Helpers.StringToField(text), 0, m_host.AbsolutePosition, m_host.Name, m_host.UUID); @@ -86,7 +87,7 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler { //TODO: DO SOMETHING USEFUL HERE //Common.SendToDebug("INTERNAL FUNCTION llSay(" + (int)channelID + ", \"" + (string)text + "\");"); - Console.WriteLine("llSay Channel " + channelID + ", Text: \"" + text + "\""); + //Console.WriteLine("llSay Channel " + channelID + ", Text: \"" + text + "\""); //type for say is 1 World.SimChat(Helpers.StringToField(text), @@ -95,7 +96,7 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler public void llShout(int channelID, string text) { - Console.WriteLine("llShout Channel " + channelID + ", Text: \"" + text + "\""); + //Console.WriteLine("llShout Channel " + channelID + ", Text: \"" + text + "\""); //type for shout is 2 World.SimChat(Helpers.StringToField(text), 2, m_host.AbsolutePosition, m_host.Name, m_host.UUID); diff --git a/OpenSim/Region/ScriptEngine/DotNetEngine/EventQueueManager.cs b/OpenSim/Region/ScriptEngine/DotNetEngine/EventQueueManager.cs index c20a8b0..311d32b 100644 --- a/OpenSim/Region/ScriptEngine/DotNetEngine/EventQueueManager.cs +++ b/OpenSim/Region/ScriptEngine/DotNetEngine/EventQueueManager.cs @@ -101,7 +101,7 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine QueueItemStruct QIS = EventQueue.Dequeue(); //myScriptEngine.m_logger.Verbose("ScriptEngine", "Processing event for ObjectID: " + QIS.ObjectID + ", ScriptID: " + QIS.ScriptID + ", FunctionName: " + QIS.FunctionName); // TODO: Execute function - myScriptEngine.myScriptManager.ExecuteFunction(QIS.ObjectID, QIS.ScriptID, QIS.FunctionName, QIS.param); + myScriptEngine.myScriptManager.ExecuteEvent(QIS.ObjectID, QIS.ScriptID, QIS.FunctionName, QIS.param); } } } diff --git a/OpenSim/Region/ScriptEngine/DotNetEngine/ScriptEngine.cs b/OpenSim/Region/ScriptEngine/DotNetEngine/ScriptEngine.cs index d08fc32..9b8cff0 100644 --- a/OpenSim/Region/ScriptEngine/DotNetEngine/ScriptEngine.cs +++ b/OpenSim/Region/ScriptEngine/DotNetEngine/ScriptEngine.cs @@ -72,7 +72,7 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine myEventQueueManager = new EventQueueManager(this); myEventManager = new EventManager(this); myScriptManager = new ScriptManager(this); - myAppDomainManager = new AppDomainManager(this); + myAppDomainManager = new AppDomainManager(); // Should we iterate the region for scripts that needs starting? // Or can we assume we are loaded before anything else so we can use proper events? diff --git a/OpenSim/Region/ScriptEngine/DotNetEngine/ScriptManager.cs b/OpenSim/Region/ScriptEngine/DotNetEngine/ScriptManager.cs index 602ac9f..926ec74 100644 --- a/OpenSim/Region/ScriptEngine/DotNetEngine/ScriptManager.cs +++ b/OpenSim/Region/ScriptEngine/DotNetEngine/ScriptManager.cs @@ -42,7 +42,7 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine /// /// Loads scripts /// Compiles them if necessary - /// Execute functions for EventQueueManager + /// Execute functions for EventQueueManager (Sends them to script on other AppDomain for execution) /// [Serializable] public class ScriptManager @@ -182,18 +182,15 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine //OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.LSL.LSL_BaseClass Script = LoadAndInitAssembly(FreeAppDomain, FileName, ObjectID); OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.LSL.LSL_BaseClass Script = LoadAndInitAssembly(FreeAppDomain, FileName, ObjectID); - //string FullScriptID = ScriptID + "." + ObjectID; // Add it to our temporary active script keeper //Scripts.Add(FullScriptID, Script); SetScript(ObjectID, ScriptID, Script); // We need to give (untrusted) assembly a private instance of BuiltIns // this private copy will contain Read-Only FullScriptID so that it can bring that on to the server whenever needed. - //OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.LSL_BuiltIn_Commands_Interface LSLB = new OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.LSL_BuiltIn_Commands_TestImplementation(FullScriptID); + OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.LSL_BuiltIn_Commands LSLB = new OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.LSL_BuiltIn_Commands(this, ObjectID); // Start the script - giving it BuiltIns - //myScriptEngine.m_logger.Verbose("ScriptEngine", "ScriptManager initializing script, handing over private builtin command interface"); - - Script.Start(new OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.LSL_BuiltIn_Commands(this, ObjectID)); + Script.Start(LSLB); } catch (Exception e) @@ -210,12 +207,6 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine return FileName; } - //private AppDomain GetFreeAppDomain() - //{ - // // TODO: Find an available AppDomain - if none, create one and add default security - // return Thread.GetDomain(); - //} - /// /// Does actual loading and initialization of script Assembly /// @@ -239,68 +230,25 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine return mbrt; //return (LSL_BaseClass)mbrt; - - - - - -// //myScriptEngine.m_logger.Verbose("ScriptEngine", "ScriptManager Loading Assembly " + FileName); -// // Load .Net Assembly (.dll) -// // Initialize and return it - -// // TODO: Add error handling -// // Script might not follow our rules since users can upload -anything- - -// Assembly a; -// //try -// //{ - - -// // Load to default appdomain (temporary) -// a = Assembly.LoadFrom(FileName); -// // Load to specified appdomain -// // TODO: Insert security -// //a = FreeAppDomain.Load(FileName); -// //} -// //catch (Exception e) -// //{ -// //} - - -// //foreach (Type _t in a.GetTypes()) -// //{ -// // Console.WriteLine("Type: " + _t.ToString()); -// //} - -// Type t; -// //try -// //{ -// t = a.GetType("SecondLife.Script", true); -// //} -// //catch (Exception e) -// //{ -// //} - -// // Create constructor arguments -// object[] args = new object[] -// { -//// this, -//// host -// }; - -// return (OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.LSL.LSL_BaseClass)Activator.CreateInstance(t, args ); - - } - internal void ExecuteFunction(IScriptHost ObjectID, string ScriptID, string FunctionName, object[] args) + /// + /// Execute a LL-event-function in Script + /// + /// Object the script is located in + /// Script ID + /// Name of function + /// Arguments to pass to function + internal void ExecuteEvent(IScriptHost ObjectID, string ScriptID, string FunctionName, object[] args) { // Execute a function in the script m_scriptEngine.Log.Verbose("ScriptEngine", "Executing Function ObjectID: " + ObjectID + ", ScriptID: " + ScriptID + ", FunctionName: " + FunctionName); OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.LSL.LSL_BaseClass Script = m_scriptEngine.myScriptManager.GetScript(ObjectID, ScriptID); - Script.ExecuteEvent(FunctionName, args); + // Must be done in correct AppDomain, so leaving it up to the script itself + + Script.Exec.ExecuteEvent(FunctionName, args); //Type type = Script.GetType(); -- cgit v1.1