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.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());
}
}
}
}

View File

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

View File

@ -12,9 +12,12 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine
{
private int MaxScriptsPerAppDomain = 1;
/// <summary>
/// List of all AppDomains
/// Internal list of all AppDomains
/// </summary>
private List<AppDomainStructure> AppDomains = new List<AppDomainStructure>();
/// <summary>
/// Structure to keep track of data around AppDomain
/// </summary>
private struct AppDomainStructure
{
/// <summary>
@ -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;
}
/// <summary>
@ -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
}
}
}

View File

@ -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());
}
}
//

View File

@ -16,6 +16,7 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler
/// </summary>
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);

View File

@ -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);
}
}
}

View File

@ -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?

View File

@ -42,7 +42,7 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine
/// <summary>
/// Loads scripts
/// Compiles them if necessary
/// Execute functions for EventQueueManager
/// Execute functions for EventQueueManager (Sends them to script on other AppDomain for execution)
/// </summary>
[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();
//}
/// <summary>
/// Does actual loading and initialization of script Assembly
/// </summary>
@ -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)
/// <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
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();