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).

afrisby
Tedd Hansen 2007-08-18 23:24:38 +00:00
parent 318376707d
commit 37446b0392
8 changed files with 107 additions and 137 deletions

View File

@ -1,10 +1,56 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text; using System.Text;
using System.Reflection;
namespace OpenSim.Region.ScriptEngine.Common 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());
}
}
} }
} }

View File

@ -34,6 +34,7 @@ namespace OpenSim.Region.ScriptEngine.Common
{ {
public interface LSL_BuiltIn_Commands_Interface public interface LSL_BuiltIn_Commands_Interface
{ {
string State(); string State();
double llSin(double f); double llSin(double f);

View File

@ -12,9 +12,12 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine
{ {
private int MaxScriptsPerAppDomain = 1; private int MaxScriptsPerAppDomain = 1;
/// <summary> /// <summary>
/// List of all AppDomains /// Internal list of all AppDomains
/// </summary> /// </summary>
private List<AppDomainStructure> AppDomains = new List<AppDomainStructure>(); private List<AppDomainStructure> AppDomains = new List<AppDomainStructure>();
/// <summary>
/// Structure to keep track of data around AppDomain
/// </summary>
private struct AppDomainStructure private struct AppDomainStructure
{ {
/// <summary> /// <summary>
@ -37,10 +40,11 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine
private object GetLock = new object(); // Mutex private object GetLock = new object(); // Mutex
private object FreeLock = new object(); // Mutex private object FreeLock = new object(); // Mutex
private ScriptEngine m_scriptEngine; //private ScriptEngine m_scriptEngine;
public AppDomainManager(ScriptEngine scriptEngine) //public AppDomainManager(ScriptEngine scriptEngine)
public AppDomainManager()
{ {
m_scriptEngine = scriptEngine; //m_scriptEngine = scriptEngine;
} }
/// <summary> /// <summary>
@ -54,6 +58,7 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine
// Current full? // Current full?
if (CurrentAD.ScriptsLoaded >= MaxScriptsPerAppDomain) if (CurrentAD.ScriptsLoaded >= MaxScriptsPerAppDomain)
{ {
// Add it to AppDomains list and empty current
AppDomains.Add(CurrentAD); AppDomains.Add(CurrentAD);
CurrentAD = new AppDomainStructure(); 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++; CurrentAD.ScriptsLoaded++;
// Return AppDomain // Return AppDomain
return CurrentAD.CurrentAppDomain; return CurrentAD.CurrentAppDomain;
@ -84,46 +93,19 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine
{ {
// Create and prepare a new AppDomain // Create and prepare a new AppDomain
AppDomainNameCount++; AppDomainNameCount++;
// TODO: Currently security and configuration match current appdomain // TODO: Currently security match current appdomain
// Construct and initialize settings for a second AppDomain. // Construct and initialize settings for a second AppDomain.
AppDomainSetup ads = new AppDomainSetup(); AppDomainSetup ads = new AppDomainSetup();
ads.ApplicationBase = AppDomain.CurrentDomain.BaseDirectory; 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.DisallowBindingRedirects = false;
ads.DisallowCodeDownload = true; ads.DisallowCodeDownload = true;
ads.ShadowCopyFiles = "true"; ads.ShadowCopyFiles = "true"; // Enabled shadowing
ads.ConfigurationFile = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile;
ads.ConfigurationFile =
AppDomain.CurrentDomain.SetupInformation.ConfigurationFile;
AppDomain AD = AppDomain.CreateDomain("ScriptAppDomain_" + AppDomainNameCount, null, ads); 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); // Return the new AppDomain
//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 AD; return AD;
} }
@ -135,14 +117,19 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine
{ {
lock (FreeLock) lock (FreeLock)
{ {
// Go through all
foreach (AppDomainStructure ads in new System.Collections.ArrayList(AppDomains)) foreach (AppDomainStructure ads in new System.Collections.ArrayList(AppDomains))
{ {
// Don't process current AppDomain
if (ads.CurrentAppDomain != CurrentAD.CurrentAppDomain) if (ads.CurrentAppDomain != CurrentAD.CurrentAppDomain)
{ {
// Not current AppDomain // 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); AppDomains.Remove(ads);
// Unload
AppDomain.Unload(ads.CurrentAppDomain); AppDomain.Unload(ads.CurrentAppDomain);
} }
} }
@ -159,16 +146,20 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine
{ {
lock (FreeLock) lock (FreeLock)
{ {
// Check if it is current AppDomain
if (CurrentAD.CurrentAppDomain == ad) if (CurrentAD.CurrentAppDomain == ad)
{ {
// Yes - increase
CurrentAD.ScriptsWaitingUnload++; CurrentAD.ScriptsWaitingUnload++;
return; return;
} }
// Lopp through all AppDomains
foreach (AppDomainStructure ads in new System.Collections.ArrayList(AppDomains)) foreach (AppDomainStructure ads in new System.Collections.ArrayList(AppDomains))
{ {
if (ads.CurrentAppDomain == ad) if (ads.CurrentAppDomain == ad)
{ {
// Found it - messy code to increase structure
AppDomainStructure ads2 = ads; AppDomainStructure ads2 = ads;
ads2.ScriptsWaitingUnload++; ads2.ScriptsWaitingUnload++;
AppDomains.Remove(ads); AppDomains.Remove(ads);
@ -178,5 +169,6 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine
} // foreach } // foreach
} // lock } // lock
} }
} }
} }

View File

@ -9,8 +9,17 @@ using System.Reflection;
namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.LSL 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; public LSL_BuiltIn_Commands_Interface m_LSL_Functions;
@ -48,33 +57,6 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.LSL
return; 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());
}
}
// //

View File

@ -16,6 +16,7 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler
/// </summary> /// </summary>
public class LSL_BuiltIn_Commands: MarshalByRefObject, LSL_BuiltIn_Commands_Interface public class LSL_BuiltIn_Commands: MarshalByRefObject, LSL_BuiltIn_Commands_Interface
{ {
private System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding(); private System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();
private ScriptManager m_manager; private ScriptManager m_manager;
private IScriptHost m_host; private IScriptHost m_host;
@ -74,7 +75,7 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler
public void llWhisper(int channelID, string text) public void llWhisper(int channelID, string text)
{ {
//Common.SendToDebug("INTERNAL FUNCTION llWhisper(" + channelID + ", \"" + 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 //type for whisper is 0
World.SimChat(Helpers.StringToField(text), World.SimChat(Helpers.StringToField(text),
0, m_host.AbsolutePosition, m_host.Name, m_host.UUID); 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 //TODO: DO SOMETHING USEFUL HERE
//Common.SendToDebug("INTERNAL FUNCTION llSay(" + (int)channelID + ", \"" + (string)text + "\");"); //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 //type for say is 1
World.SimChat(Helpers.StringToField(text), World.SimChat(Helpers.StringToField(text),
@ -95,7 +96,7 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler
public void llShout(int channelID, string text) 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 //type for shout is 2
World.SimChat(Helpers.StringToField(text), World.SimChat(Helpers.StringToField(text),
2, m_host.AbsolutePosition, m_host.Name, m_host.UUID); 2, m_host.AbsolutePosition, m_host.Name, m_host.UUID);

View File

@ -101,7 +101,7 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine
QueueItemStruct QIS = EventQueue.Dequeue(); QueueItemStruct QIS = EventQueue.Dequeue();
//myScriptEngine.m_logger.Verbose("ScriptEngine", "Processing event for ObjectID: " + QIS.ObjectID + ", ScriptID: " + QIS.ScriptID + ", FunctionName: " + QIS.FunctionName); //myScriptEngine.m_logger.Verbose("ScriptEngine", "Processing event for ObjectID: " + QIS.ObjectID + ", ScriptID: " + QIS.ScriptID + ", FunctionName: " + QIS.FunctionName);
// TODO: Execute function // 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);
} }
} }
} }

View File

@ -72,7 +72,7 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine
myEventQueueManager = new EventQueueManager(this); myEventQueueManager = new EventQueueManager(this);
myEventManager = new EventManager(this); myEventManager = new EventManager(this);
myScriptManager = new ScriptManager(this); myScriptManager = new ScriptManager(this);
myAppDomainManager = new AppDomainManager(this); myAppDomainManager = new AppDomainManager();
// Should we iterate the region for scripts that needs starting? // 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? // Or can we assume we are loaded before anything else so we can use proper events?

View File

@ -42,7 +42,7 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine
/// <summary> /// <summary>
/// Loads scripts /// Loads scripts
/// Compiles them if necessary /// Compiles them if necessary
/// Execute functions for EventQueueManager /// Execute functions for EventQueueManager (Sends them to script on other AppDomain for execution)
/// </summary> /// </summary>
[Serializable] [Serializable]
public class ScriptManager 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);
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 // Add it to our temporary active script keeper
//Scripts.Add(FullScriptID, Script); //Scripts.Add(FullScriptID, Script);
SetScript(ObjectID, ScriptID, Script); SetScript(ObjectID, ScriptID, Script);
// We need to give (untrusted) assembly a private instance of BuiltIns // 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. // 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 // Start the script - giving it BuiltIns
//myScriptEngine.m_logger.Verbose("ScriptEngine", "ScriptManager initializing script, handing over private builtin command interface"); Script.Start(LSLB);
Script.Start(new OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.LSL_BuiltIn_Commands(this, ObjectID));
} }
catch (Exception e) catch (Exception e)
@ -210,12 +207,6 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine
return FileName; return FileName;
} }
//private AppDomain GetFreeAppDomain()
//{
// // TODO: Find an available AppDomain - if none, create one and add default security
// return Thread.GetDomain();
//}
/// <summary> /// <summary>
/// Does actual loading and initialization of script Assembly /// Does actual loading and initialization of script Assembly
/// </summary> /// </summary>
@ -239,68 +230,25 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine
return mbrt; return mbrt;
//return (LSL_BaseClass)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) /// <summary>
/// Execute a LL-event-function in Script
/// </summary>
/// <param name="ObjectID">Object the script is located in</param>
/// <param name="ScriptID">Script ID</param>
/// <param name="FunctionName">Name of function</param>
/// <param name="args">Arguments to pass to function</param>
internal void ExecuteEvent(IScriptHost ObjectID, string ScriptID, string FunctionName, object[] args)
{ {
// Execute a function in the script // Execute a function in the script
m_scriptEngine.Log.Verbose("ScriptEngine", "Executing Function ObjectID: " + ObjectID + ", ScriptID: " + ScriptID + ", FunctionName: " + FunctionName); 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); 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(); //Type type = Script.GetType();