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).
parent
318376707d
commit
37446b0392
|
@ -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());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,6 +34,7 @@ namespace OpenSim.Region.ScriptEngine.Common
|
|||
{
|
||||
public interface LSL_BuiltIn_Commands_Interface
|
||||
{
|
||||
|
||||
string State();
|
||||
|
||||
double llSin(double f);
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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?
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
Loading…
Reference in New Issue