SCRIPTING STILL BROKEN
Added comments and regions, restructured code Changed a lot of AppDomain junk from console from using Console.Write to Log.Verbose and set it to #if DEBUG All modules should now refresh their configuration runtime Made all logging in ScriptEngine.Common get script name from actual engine Renamed LSLLongCmdHandler to AsyncLSLCommandManager Added auto-recover with 5 sec throttle for new MaintenanceThreadThreadPoolClientBranch
parent
a6726b0c9d
commit
d02a90823f
|
@ -112,7 +112,7 @@ namespace OpenSim.Region.ScriptEngine.Common
|
||||||
{
|
{
|
||||||
m_LSL_Functions = LSL_Functions;
|
m_LSL_Functions = LSL_Functions;
|
||||||
|
|
||||||
//MainLog.Instance.Notice("ScriptEngine", "LSL_BaseClass.Start() called.");
|
//MainLog.Instance.Notice(ScriptEngineName, "LSL_BaseClass.Start() called.");
|
||||||
|
|
||||||
// Get this AppDomain's settings and display some of them.
|
// Get this AppDomain's settings and display some of them.
|
||||||
AppDomainSetup ads = AppDomain.CurrentDomain.SetupInformation;
|
AppDomainSetup ads = AppDomain.CurrentDomain.SetupInformation;
|
||||||
|
|
|
@ -61,7 +61,7 @@ namespace OpenSim.Region.ScriptEngine.Common
|
||||||
m_localID = localID;
|
m_localID = localID;
|
||||||
m_itemID = itemID;
|
m_itemID = itemID;
|
||||||
|
|
||||||
//MainLog.Instance.Notice("ScriptEngine", "LSL_BaseClass.Start() called. Hosted by [" + m_host.Name + ":" + m_host.UUID + "@" + m_host.AbsolutePosition + "]");
|
//MainLog.Instance.Notice(ScriptEngineName, "LSL_BaseClass.Start() called. Hosted by [" + m_host.Name + ":" + m_host.UUID + "@" + m_host.AbsolutePosition + "]");
|
||||||
}
|
}
|
||||||
|
|
||||||
private DateTime m_timer = DateTime.Now;
|
private DateTime m_timer = DateTime.Now;
|
||||||
|
@ -1038,7 +1038,7 @@ namespace OpenSim.Region.ScriptEngine.Common
|
||||||
public void llSetTimerEvent(double sec)
|
public void llSetTimerEvent(double sec)
|
||||||
{
|
{
|
||||||
// Setting timer repeat
|
// Setting timer repeat
|
||||||
m_ScriptEngine.m_LSLLongCmdHandler.SetTimerEvent(m_localID, m_itemID, sec);
|
m_ScriptEngine.m_ASYNCLSLCommandManager.SetTimerEvent(m_localID, m_itemID, sec);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void llSleep(double sec)
|
public void llSleep(double sec)
|
||||||
|
|
|
@ -35,7 +35,7 @@ using OpenSim.Region.ScriptEngine.Common;
|
||||||
|
|
||||||
namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
|
namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
|
||||||
{
|
{
|
||||||
public class AppDomainManager
|
public class AppDomainManager : iScriptEngineFunctionModule
|
||||||
{
|
{
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -85,12 +85,17 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
|
||||||
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(int MaxScriptsPerDomain)
|
public AppDomainManager(ScriptEngine scriptEngine)
|
||||||
{
|
{
|
||||||
maxScriptsPerAppDomain = MaxScriptsPerDomain;
|
m_scriptEngine = scriptEngine;
|
||||||
//m_scriptEngine = scriptEngine;
|
ReadConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ReadConfig()
|
||||||
|
{
|
||||||
|
maxScriptsPerAppDomain = m_scriptEngine.ScriptConfigSource.GetInt("ScriptsPerAppDomain", 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -99,7 +104,7 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
|
||||||
/// <returns>Free AppDomain</returns>
|
/// <returns>Free AppDomain</returns>
|
||||||
private AppDomainStructure GetFreeAppDomain()
|
private AppDomainStructure GetFreeAppDomain()
|
||||||
{
|
{
|
||||||
Console.WriteLine("Finding free AppDomain");
|
// Console.WriteLine("Finding free AppDomain");
|
||||||
lock (getLock)
|
lock (getLock)
|
||||||
{
|
{
|
||||||
// Current full?
|
// Current full?
|
||||||
|
@ -117,7 +122,7 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
|
||||||
currentAD.CurrentAppDomain = PrepareNewAppDomain();
|
currentAD.CurrentAppDomain = PrepareNewAppDomain();
|
||||||
}
|
}
|
||||||
|
|
||||||
Console.WriteLine("Scripts loaded in this Appdomain: " + currentAD.ScriptsLoaded);
|
// Console.WriteLine("Scripts loaded in this Appdomain: " + currentAD.ScriptsLoaded);
|
||||||
return currentAD;
|
return currentAD;
|
||||||
} // lock
|
} // lock
|
||||||
}
|
}
|
||||||
|
@ -144,7 +149,7 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
|
||||||
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);
|
||||||
Console.WriteLine("Loading: " +
|
m_scriptEngine.Log.Verbose(m_scriptEngine.ScriptEngineName, "AppDomain Loading: " +
|
||||||
AssemblyName.GetAssemblyName("OpenSim.Region.ScriptEngine.Common.dll").ToString());
|
AssemblyName.GetAssemblyName("OpenSim.Region.ScriptEngine.Common.dll").ToString());
|
||||||
AD.Load(AssemblyName.GetAssemblyName("OpenSim.Region.ScriptEngine.Common.dll"));
|
AD.Load(AssemblyName.GetAssemblyName("OpenSim.Region.ScriptEngine.Common.dll"));
|
||||||
|
|
||||||
|
@ -169,17 +174,16 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
|
||||||
// Is number of unloaded bigger or equal to number of loaded?
|
// Is number of unloaded bigger or equal to number of loaded?
|
||||||
if (ads.ScriptsLoaded <= ads.ScriptsWaitingUnload)
|
if (ads.ScriptsLoaded <= ads.ScriptsWaitingUnload)
|
||||||
{
|
{
|
||||||
Console.WriteLine("Found empty AppDomain, unloading");
|
|
||||||
// Remove from internal list
|
// Remove from internal list
|
||||||
appDomains.Remove(ads);
|
appDomains.Remove(ads);
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
|
Console.WriteLine("Found empty AppDomain, unloading");
|
||||||
long m = GC.GetTotalMemory(true);
|
long m = GC.GetTotalMemory(true);
|
||||||
#endif
|
#endif
|
||||||
// Unload
|
// Unload
|
||||||
AppDomain.Unload(ads.CurrentAppDomain);
|
AppDomain.Unload(ads.CurrentAppDomain);
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
Console.WriteLine("AppDomain unload freed " + (m - GC.GetTotalMemory(true)) +
|
m_scriptEngine.Log.Verbose(m_scriptEngine.ScriptEngineName, "AppDomain unload freed " + (m - GC.GetTotalMemory(true)) + " bytes of memory");
|
||||||
" bytes of memory");
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -193,7 +197,9 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
|
||||||
// Find next available AppDomain to put it in
|
// Find next available AppDomain to put it in
|
||||||
AppDomainStructure FreeAppDomain = GetFreeAppDomain();
|
AppDomainStructure FreeAppDomain = GetFreeAppDomain();
|
||||||
|
|
||||||
Console.WriteLine("Loading into AppDomain: " + FileName);
|
#if DEBUG
|
||||||
|
m_scriptEngine.Log.Verbose(m_scriptEngine.ScriptEngineName, "Loading into AppDomain: " + FileName);
|
||||||
|
#endif
|
||||||
IScript mbrt =
|
IScript mbrt =
|
||||||
(IScript)
|
(IScript)
|
||||||
FreeAppDomain.CurrentAppDomain.CreateInstanceFromAndUnwrap(FileName, "SecondLife.Script");
|
FreeAppDomain.CurrentAppDomain.CreateInstanceFromAndUnwrap(FileName, "SecondLife.Script");
|
||||||
|
@ -213,7 +219,9 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
|
||||||
{
|
{
|
||||||
lock (freeLock)
|
lock (freeLock)
|
||||||
{
|
{
|
||||||
Console.WriteLine("Stopping script in AppDomain");
|
#if DEBUG
|
||||||
|
m_scriptEngine.Log.Verbose(m_scriptEngine.ScriptEngineName, "Stopping script in AppDomain");
|
||||||
|
#endif
|
||||||
// Check if it is current AppDomain
|
// Check if it is current AppDomain
|
||||||
if (currentAD.CurrentAppDomain == ad)
|
if (currentAD.CurrentAppDomain == ad)
|
||||||
{
|
{
|
||||||
|
@ -236,5 +244,15 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
|
||||||
|
|
||||||
UnloadAppDomains(); // Outsite lock, has its own GetLock
|
UnloadAppDomains(); // Outsite lock, has its own GetLock
|
||||||
}
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// If set to true then threads and stuff should try to make a graceful exit
|
||||||
|
/// </summary>
|
||||||
|
public bool PleaseShutdown
|
||||||
|
{
|
||||||
|
get { return _PleaseShutdown; }
|
||||||
|
set { _PleaseShutdown = value; }
|
||||||
|
}
|
||||||
|
private bool _PleaseShutdown = false;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -38,16 +38,17 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handles LSL commands that takes long time and returns an event, for example timers, HTTP requests, etc.
|
/// Handles LSL commands that takes long time and returns an event, for example timers, HTTP requests, etc.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class LSLLongCmdHandler
|
public class AsyncLSLCommandManager : iScriptEngineFunctionModule
|
||||||
{
|
{
|
||||||
private Thread cmdHandlerThread;
|
private Thread cmdHandlerThread;
|
||||||
private int cmdHandlerThreadCycleSleepms = 100;
|
private int cmdHandlerThreadCycleSleepms;
|
||||||
|
|
||||||
private ScriptEngine m_ScriptEngine;
|
private ScriptEngine m_ScriptEngine;
|
||||||
|
|
||||||
public LSLLongCmdHandler(ScriptEngine _ScriptEngine)
|
public AsyncLSLCommandManager(ScriptEngine _ScriptEngine)
|
||||||
{
|
{
|
||||||
m_ScriptEngine = _ScriptEngine;
|
m_ScriptEngine = _ScriptEngine;
|
||||||
|
ReadConfig();
|
||||||
|
|
||||||
// Start the thread that will be doing the work
|
// Start the thread that will be doing the work
|
||||||
cmdHandlerThread = new Thread(CmdHandlerThreadLoop);
|
cmdHandlerThread = new Thread(CmdHandlerThreadLoop);
|
||||||
|
@ -57,7 +58,13 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
|
||||||
cmdHandlerThread.Start();
|
cmdHandlerThread.Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
~LSLLongCmdHandler()
|
public void ReadConfig()
|
||||||
|
{
|
||||||
|
cmdHandlerThreadCycleSleepms = m_ScriptEngine.ScriptConfigSource.GetInt("AsyncLLCommandLoopms", 50);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
~AsyncLSLCommandManager()
|
||||||
{
|
{
|
||||||
// Shut down thread
|
// Shut down thread
|
||||||
try
|
try
|
||||||
|
@ -291,5 +298,16 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// If set to true then threads and stuff should try to make a graceful exit
|
||||||
|
/// </summary>
|
||||||
|
public bool PleaseShutdown
|
||||||
|
{
|
||||||
|
get { return _PleaseShutdown; }
|
||||||
|
set { _PleaseShutdown = value; }
|
||||||
|
}
|
||||||
|
private bool _PleaseShutdown = false;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -44,14 +44,14 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
|
||||||
public static void SendToDebug(string Message)
|
public static void SendToDebug(string Message)
|
||||||
{
|
{
|
||||||
//if (Debug == true)
|
//if (Debug == true)
|
||||||
mySE.Log.Verbose("ScriptEngine", "Debug: " + Message);
|
mySE.Log.Verbose(mySE.ScriptEngineName, "Debug: " + Message);
|
||||||
//SendToDebugEvent("\r\n" + DateTime.Now.ToString("[HH:mm:ss] ") + Message);
|
//SendToDebugEvent("\r\n" + DateTime.Now.ToString("[HH:mm:ss] ") + Message);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void SendToLog(string Message)
|
public static void SendToLog(string Message)
|
||||||
{
|
{
|
||||||
//if (Debug == true)
|
//if (Debug == true)
|
||||||
mySE.Log.Verbose("ScriptEngine", "LOG: " + Message);
|
mySE.Log.Verbose(mySE.ScriptEngineName, "LOG: " + Message);
|
||||||
//SendToLogEvent("\r\n" + DateTime.Now.ToString("[HH:mm:ss] ") + Message);
|
//SendToLogEvent("\r\n" + DateTime.Now.ToString("[HH:mm:ss] ") + Message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,7 +37,7 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
|
||||||
/// Prepares events so they can be directly executed upon a script by EventQueueManager, then queues it.
|
/// Prepares events so they can be directly executed upon a script by EventQueueManager, then queues it.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class EventManager : OpenSim.Region.ScriptEngine.Common.ScriptServerInterfaces.RemoteEvents
|
public class EventManager : OpenSim.Region.ScriptEngine.Common.ScriptServerInterfaces.RemoteEvents, iScriptEngineFunctionModule
|
||||||
{
|
{
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -59,12 +59,13 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
|
||||||
public EventManager(ScriptEngine _ScriptEngine, bool performHookUp)
|
public EventManager(ScriptEngine _ScriptEngine, bool performHookUp)
|
||||||
{
|
{
|
||||||
myScriptEngine = _ScriptEngine;
|
myScriptEngine = _ScriptEngine;
|
||||||
|
ReadConfig();
|
||||||
|
|
||||||
// Hook up to events from OpenSim
|
// Hook up to events from OpenSim
|
||||||
// We may not want to do it because someone is controlling us and will deliver events to us
|
// We may not want to do it because someone is controlling us and will deliver events to us
|
||||||
if (performHookUp)
|
if (performHookUp)
|
||||||
{
|
{
|
||||||
myScriptEngine.Log.Verbose("ScriptEngine", "Hooking up to server events");
|
myScriptEngine.Log.Verbose(myScriptEngine.ScriptEngineName, "Hooking up to server events");
|
||||||
myScriptEngine.World.EventManager.OnObjectGrab += touch_start;
|
myScriptEngine.World.EventManager.OnObjectGrab += touch_start;
|
||||||
myScriptEngine.World.EventManager.OnRezScript += OnRezScript;
|
myScriptEngine.World.EventManager.OnRezScript += OnRezScript;
|
||||||
myScriptEngine.World.EventManager.OnRemoveScript += OnRemoveScript;
|
myScriptEngine.World.EventManager.OnRemoveScript += OnRemoveScript;
|
||||||
|
@ -73,6 +74,11 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void ReadConfig()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public void changed(uint localID, uint change)
|
public void changed(uint localID, uint change)
|
||||||
{
|
{
|
||||||
// Add to queue for all scripts in localID, Object pass change.
|
// Add to queue for all scripts in localID, Object pass change.
|
||||||
|
@ -263,5 +269,16 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
|
||||||
{
|
{
|
||||||
// myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "http_response", EventQueueManager.llDetectNull);
|
// myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "http_response", EventQueueManager.llDetectNull);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// If set to true then threads and stuff should try to make a graceful exit
|
||||||
|
/// </summary>
|
||||||
|
public bool PleaseShutdown
|
||||||
|
{
|
||||||
|
get { return _PleaseShutdown; }
|
||||||
|
set { _PleaseShutdown = value; }
|
||||||
|
}
|
||||||
|
private bool _PleaseShutdown = false;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -42,7 +42,7 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
|
||||||
/// Events are queued and executed in separate thread
|
/// Events are queued and executed in separate thread
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class EventQueueManager
|
public class EventQueueManager : iScriptEngineFunctionModule
|
||||||
{
|
{
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -197,13 +197,22 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ReadConfig()
|
public void ReadConfig()
|
||||||
{
|
{
|
||||||
|
// Refresh config
|
||||||
numberOfThreads = m_ScriptEngine.ScriptConfigSource.GetInt("NumberOfScriptThreads", 2);
|
numberOfThreads = m_ScriptEngine.ScriptConfigSource.GetInt("NumberOfScriptThreads", 2);
|
||||||
maxFunctionExecutionTimems = m_ScriptEngine.ScriptConfigSource.GetInt("MaxEventExecutionTimeMs", 5000);
|
maxFunctionExecutionTimems = m_ScriptEngine.ScriptConfigSource.GetInt("MaxEventExecutionTimeMs", 5000);
|
||||||
EnforceMaxExecutionTime = m_ScriptEngine.ScriptConfigSource.GetBoolean("EnforceMaxEventExecutionTime", false);
|
EnforceMaxExecutionTime = m_ScriptEngine.ScriptConfigSource.GetBoolean("EnforceMaxEventExecutionTime", false);
|
||||||
KillScriptOnMaxFunctionExecutionTime = m_ScriptEngine.ScriptConfigSource.GetBoolean("DeactivateScriptOnTimeout", false);
|
KillScriptOnMaxFunctionExecutionTime = m_ScriptEngine.ScriptConfigSource.GetBoolean("DeactivateScriptOnTimeout", false);
|
||||||
|
|
||||||
|
// Now refresh config in all threads
|
||||||
|
lock (eventQueueThreadsLock)
|
||||||
|
{
|
||||||
|
foreach (EventQueueThreadClass EventQueueThread in eventQueueThreads)
|
||||||
|
{
|
||||||
|
EventQueueThread.ReadConfig();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
@ -222,7 +231,7 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
|
||||||
{
|
{
|
||||||
foreach (EventQueueThreadClass EventQueueThread in eventQueueThreads)
|
foreach (EventQueueThreadClass EventQueueThread in eventQueueThreads)
|
||||||
{
|
{
|
||||||
EventQueueThread.Shutdown();
|
AbortThreadClass(EventQueueThread);
|
||||||
}
|
}
|
||||||
eventQueueThreads.Clear();
|
eventQueueThreads.Clear();
|
||||||
staticGlobalEventQueueThreads.Clear();
|
staticGlobalEventQueueThreads.Clear();
|
||||||
|
@ -243,7 +252,7 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
|
||||||
EventQueueThreadClass eqtc = new EventQueueThreadClass(this);
|
EventQueueThreadClass eqtc = new EventQueueThreadClass(this);
|
||||||
eventQueueThreads.Add(eqtc);
|
eventQueueThreads.Add(eqtc);
|
||||||
staticGlobalEventQueueThreads.Add(eqtc);
|
staticGlobalEventQueueThreads.Add(eqtc);
|
||||||
m_ScriptEngine.Log.Debug("DotNetEngine", "Started new script execution thread. Current thread count: " + eventQueueThreads.Count);
|
m_ScriptEngine.Log.Debug(m_ScriptEngine.ScriptEngineName, "Started new script execution thread. Current thread count: " + eventQueueThreads.Count);
|
||||||
|
|
||||||
}
|
}
|
||||||
private void AbortThreadClass(EventQueueThreadClass threadClass)
|
private void AbortThreadClass(EventQueueThreadClass threadClass)
|
||||||
|
@ -252,16 +261,17 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
|
||||||
eventQueueThreads.Remove(threadClass);
|
eventQueueThreads.Remove(threadClass);
|
||||||
if (staticGlobalEventQueueThreads.Contains(threadClass))
|
if (staticGlobalEventQueueThreads.Contains(threadClass))
|
||||||
staticGlobalEventQueueThreads.Remove(threadClass);
|
staticGlobalEventQueueThreads.Remove(threadClass);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
threadClass.Shutdown();
|
threadClass.Stop();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
m_ScriptEngine.Log.Error("EventQueueManager", "If you see this, could you please report it to Tedd:");
|
m_ScriptEngine.Log.Error(m_ScriptEngine.ScriptEngineName + ":EventQueueManager", "If you see this, could you please report it to Tedd:");
|
||||||
m_ScriptEngine.Log.Error("EventQueueManager", "Script thread execution timeout kill ended in exception: " + ex.ToString());
|
m_ScriptEngine.Log.Error(m_ScriptEngine.ScriptEngineName + ":EventQueueManager", "Script thread execution timeout kill ended in exception: " + ex.ToString());
|
||||||
}
|
}
|
||||||
m_ScriptEngine.Log.Debug("DotNetEngine", "Killed script execution thread. Remaining thread count: " + eventQueueThreads.Count);
|
m_ScriptEngine.Log.Debug(m_ScriptEngine.ScriptEngineName, "Killed script execution thread. Remaining thread count: " + eventQueueThreads.Count);
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
@ -313,7 +323,7 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
|
||||||
public void AddToObjectQueue(uint localID, string FunctionName, Queue_llDetectParams_Struct qParams, params object[] param)
|
public void AddToObjectQueue(uint localID, string FunctionName, Queue_llDetectParams_Struct qParams, params object[] param)
|
||||||
{
|
{
|
||||||
// Determine all scripts in Object and add to their queue
|
// Determine all scripts in Object and add to their queue
|
||||||
//myScriptEngine.m_logger.Verbose("ScriptEngine", "EventQueueManager Adding localID: " + localID + ", FunctionName: " + FunctionName);
|
//myScriptEngine.m_logger.Verbose(ScriptEngineName, "EventQueueManager Adding localID: " + localID + ", FunctionName: " + FunctionName);
|
||||||
|
|
||||||
|
|
||||||
// Do we have any scripts in this object at all? If not, return
|
// Do we have any scripts in this object at all? If not, return
|
||||||
|
@ -367,6 +377,10 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void AdjustNumberOfScriptThreads()
|
public void AdjustNumberOfScriptThreads()
|
||||||
{
|
{
|
||||||
|
// Is there anything here for us to do?
|
||||||
|
if (eventQueueThreads.Count == numberOfThreads)
|
||||||
|
return;
|
||||||
|
|
||||||
lock (eventQueueThreadsLock)
|
lock (eventQueueThreadsLock)
|
||||||
{
|
{
|
||||||
int diff = numberOfThreads - eventQueueThreads.Count;
|
int diff = numberOfThreads - eventQueueThreads.Count;
|
||||||
|
@ -424,5 +438,15 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
/// <summary>
|
||||||
|
/// If set to true then threads and stuff should try to make a graceful exit
|
||||||
|
/// </summary>
|
||||||
|
public bool PleaseShutdown
|
||||||
|
{
|
||||||
|
get { return _PleaseShutdown; }
|
||||||
|
set { _PleaseShutdown = value; }
|
||||||
|
}
|
||||||
|
private bool _PleaseShutdown = false;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -12,12 +12,13 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Because every thread needs some data set for it (time started to execute current function), it will do its work within a class
|
/// Because every thread needs some data set for it (time started to execute current function), it will do its work within a class
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class EventQueueThreadClass
|
public class EventQueueThreadClass: iScriptEngineFunctionModule
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// How many ms to sleep if queue is empty
|
/// How many ms to sleep if queue is empty
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private int nothingToDoSleepms;// = 50;
|
private int nothingToDoSleepms;// = 50;
|
||||||
|
private ThreadPriority MyThreadPriority;
|
||||||
|
|
||||||
public long LastExecutionStarted;
|
public long LastExecutionStarted;
|
||||||
public bool InExecution = false;
|
public bool InExecution = false;
|
||||||
|
@ -26,25 +27,27 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
|
||||||
private EventQueueManager eventQueueManager;
|
private EventQueueManager eventQueueManager;
|
||||||
public Thread EventQueueThread;
|
public Thread EventQueueThread;
|
||||||
private static int ThreadCount = 0;
|
private static int ThreadCount = 0;
|
||||||
private ThreadPriority MyThreadPriority;
|
|
||||||
|
private string ScriptEngineName = "ScriptEngine.Common";
|
||||||
|
|
||||||
public EventQueueThreadClass(EventQueueManager eqm)
|
public EventQueueThreadClass(EventQueueManager eqm)
|
||||||
{
|
{
|
||||||
eventQueueManager = eqm;
|
eventQueueManager = eqm;
|
||||||
nothingToDoSleepms = eqm.m_ScriptEngine.ScriptConfigSource.GetInt("SleepTimeIfNoScriptExecutionMs", 50);
|
ReadConfig();
|
||||||
Start();
|
Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
~EventQueueThreadClass()
|
~EventQueueThreadClass()
|
||||||
{
|
{
|
||||||
Shutdown();
|
Stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Start thread
|
public void ReadConfig()
|
||||||
/// </summary>
|
|
||||||
private void Start()
|
|
||||||
{
|
{
|
||||||
|
ScriptEngineName = eventQueueManager.m_ScriptEngine.ScriptEngineName;
|
||||||
|
nothingToDoSleepms = eventQueueManager.m_ScriptEngine.ScriptConfigSource.GetInt("SleepTimeIfNoScriptExecutionMs", 50);
|
||||||
|
|
||||||
// Later with ScriptServer we might want to ask OS for stuff too, so doing this a bit manually
|
// Later with ScriptServer we might want to ask OS for stuff too, so doing this a bit manually
|
||||||
string pri = eventQueueManager.m_ScriptEngine.ScriptConfigSource.GetString("ScriptThreadPriority", "BelowNormal");
|
string pri = eventQueueManager.m_ScriptEngine.ScriptConfigSource.GetString("ScriptThreadPriority", "BelowNormal");
|
||||||
switch (pri.ToLower())
|
switch (pri.ToLower())
|
||||||
|
@ -70,6 +73,19 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Now set that priority
|
||||||
|
if (EventQueueThread != null)
|
||||||
|
if (EventQueueThread.IsAlive)
|
||||||
|
EventQueueThread.Priority = MyThreadPriority;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Start thread
|
||||||
|
/// </summary>
|
||||||
|
private void Start()
|
||||||
|
{
|
||||||
|
|
||||||
EventQueueThread = new Thread(EventQueueThreadLoop);
|
EventQueueThread = new Thread(EventQueueThreadLoop);
|
||||||
EventQueueThread.IsBackground = true;
|
EventQueueThread.IsBackground = true;
|
||||||
|
@ -84,18 +100,20 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
|
||||||
ThreadCount++;
|
ThreadCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Shutdown()
|
public void Stop()
|
||||||
{
|
{
|
||||||
|
PleaseShutdown = true; // Set shutdown flag
|
||||||
|
Thread.Sleep(100); // Wait a bit
|
||||||
if (EventQueueThread != null && EventQueueThread.IsAlive == true)
|
if (EventQueueThread != null && EventQueueThread.IsAlive == true)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
EventQueueThread.Abort();
|
EventQueueThread.Abort(); // Send abort
|
||||||
EventQueueThread.Join();
|
EventQueueThread.Join(); // Wait for it
|
||||||
}
|
}
|
||||||
catch (Exception)
|
catch (Exception)
|
||||||
{
|
{
|
||||||
//myScriptEngine.Log.Verbose("ScriptEngine", "EventQueueManager Exception killing worker thread: " + e.ToString());
|
//myScriptEngine.Log.Verbose(ScriptEngineName, "EventQueueManager Exception killing worker thread: " + e.ToString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -106,7 +124,7 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void EventQueueThreadLoop()
|
private void EventQueueThreadLoop()
|
||||||
{
|
{
|
||||||
//myScriptEngine.m_logger.Verbose("ScriptEngine", "EventQueueManager Worker thread spawned");
|
//myScriptEngine.m_logger.Verbose(ScriptEngineName, "EventQueueManager Worker thread spawned");
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
while (true)
|
while (true)
|
||||||
|
@ -117,7 +135,7 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
// Every now and then check if we should shut down
|
// Every now and then check if we should shut down
|
||||||
if (eventQueueManager.ThreadsToExit > 0)
|
if (PleaseShutdown || eventQueueManager.ThreadsToExit > 0)
|
||||||
{
|
{
|
||||||
// Someone should shut down, lets get exclusive lock
|
// Someone should shut down, lets get exclusive lock
|
||||||
lock (eventQueueManager.ThreadsToExitLock)
|
lock (eventQueueManager.ThreadsToExitLock)
|
||||||
|
@ -125,9 +143,15 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
|
||||||
// Lets re-check in case someone grabbed it
|
// Lets re-check in case someone grabbed it
|
||||||
if (eventQueueManager.ThreadsToExit > 0)
|
if (eventQueueManager.ThreadsToExit > 0)
|
||||||
{
|
{
|
||||||
// We are go for shutdown
|
// Its crowded here so we'll shut down
|
||||||
eventQueueManager.ThreadsToExit--;
|
eventQueueManager.ThreadsToExit--;
|
||||||
Shutdown();
|
Stop();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// We have been asked to shut down
|
||||||
|
Stop();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -139,6 +163,9 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
|
||||||
EventQueueManager.QueueItemStruct QIS = BlankQIS;
|
EventQueueManager.QueueItemStruct QIS = BlankQIS;
|
||||||
bool GotItem = false;
|
bool GotItem = false;
|
||||||
|
|
||||||
|
if (PleaseShutdown)
|
||||||
|
return;
|
||||||
|
|
||||||
if (eventQueueManager.eventQueue.Count == 0)
|
if (eventQueueManager.eventQueue.Count == 0)
|
||||||
{
|
{
|
||||||
// Nothing to do? Sleep a bit waiting for something to do
|
// Nothing to do? Sleep a bit waiting for something to do
|
||||||
|
@ -147,7 +174,7 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Something in queue, process
|
// Something in queue, process
|
||||||
//myScriptEngine.m_logger.Verbose("ScriptEngine", "Processing event for localID: " + QIS.localID + ", itemID: " + QIS.itemID + ", FunctionName: " + QIS.FunctionName);
|
//myScriptEngine.m_logger.Verbose(ScriptEngineName, "Processing event for localID: " + QIS.localID + ", itemID: " + QIS.itemID + ", FunctionName: " + QIS.FunctionName);
|
||||||
|
|
||||||
// OBJECT BASED LOCK - TWO THREADS WORKING ON SAME OBJECT IS NOT GOOD
|
// OBJECT BASED LOCK - TWO THREADS WORKING ON SAME OBJECT IS NOT GOOD
|
||||||
lock (eventQueueManager.queueLock)
|
lock (eventQueueManager.queueLock)
|
||||||
|
@ -179,7 +206,7 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
eventQueueManager.m_ScriptEngine.Log.Debug("ScriptEngine",
|
eventQueueManager.m_ScriptEngine.Log.Debug(ScriptEngineName,
|
||||||
"Executing event:\r\n"
|
"Executing event:\r\n"
|
||||||
+ "QIS.localID: " + QIS.localID
|
+ "QIS.localID: " + QIS.localID
|
||||||
+ ", QIS.itemID: " + QIS.itemID
|
+ ", QIS.itemID: " + QIS.itemID
|
||||||
|
@ -235,7 +262,7 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
|
||||||
//else
|
//else
|
||||||
//{
|
//{
|
||||||
// T oconsole
|
// T oconsole
|
||||||
eventQueueManager.m_ScriptEngine.Log.Error("ScriptEngine",
|
eventQueueManager.m_ScriptEngine.Log.Error(ScriptEngineName,
|
||||||
"Unable to send text in-world:\r\n" +
|
"Unable to send text in-world:\r\n" +
|
||||||
text);
|
text);
|
||||||
}
|
}
|
||||||
|
@ -260,19 +287,28 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
|
||||||
}
|
}
|
||||||
catch (ThreadAbortException tae)
|
catch (ThreadAbortException tae)
|
||||||
{
|
{
|
||||||
eventQueueManager.m_ScriptEngine.Log.Notice("ScriptEngine", "ThreadAbortException while executing function.");
|
eventQueueManager.m_ScriptEngine.Log.Notice(ScriptEngineName, "ThreadAbortException while executing function.");
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
eventQueueManager.m_ScriptEngine.Log.Error("ScriptEngine", "Exception in EventQueueThreadLoop: " + e.ToString());
|
eventQueueManager.m_ScriptEngine.Log.Error(ScriptEngineName, "Exception in EventQueueThreadLoop: " + e.ToString());
|
||||||
}
|
}
|
||||||
} // while
|
} // while
|
||||||
} // try
|
} // try
|
||||||
catch (ThreadAbortException)
|
catch (ThreadAbortException)
|
||||||
{
|
{
|
||||||
//myScriptEngine.Log.Verbose("ScriptEngine", "EventQueueManager Worker thread killed: " + tae.Message);
|
//myScriptEngine.Log.Verbose(ScriptEngineName, "EventQueueManager Worker thread killed: " + tae.Message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// If set to true then threads and stuff should try to make a graceful exit
|
||||||
|
/// </summary>
|
||||||
|
public bool PleaseShutdown
|
||||||
|
{
|
||||||
|
get { return _PleaseShutdown; }
|
||||||
|
set { _PleaseShutdown = value; }
|
||||||
|
}
|
||||||
|
private bool _PleaseShutdown = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// This class does maintenance on script engine.
|
/// This class does maintenance on script engine.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class MaintenanceThread
|
public class MaintenanceThread : iScriptEngineFunctionModule
|
||||||
{
|
{
|
||||||
public ScriptEngine m_ScriptEngine;
|
public ScriptEngine m_ScriptEngine;
|
||||||
private int MaintenanceLoopms;
|
private int MaintenanceLoopms;
|
||||||
|
@ -28,7 +28,7 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
|
||||||
StopMaintenanceThread();
|
StopMaintenanceThread();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ReadConfig()
|
public void ReadConfig()
|
||||||
{
|
{
|
||||||
MaintenanceLoopms = m_ScriptEngine.ScriptConfigSource.GetInt("MaintenanceLoopms", 50);
|
MaintenanceLoopms = m_ScriptEngine.ScriptConfigSource.GetInt("MaintenanceLoopms", 50);
|
||||||
}
|
}
|
||||||
|
@ -79,49 +79,75 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
|
||||||
/// A thread should run in this loop and check all running scripts
|
/// A thread should run in this loop and check all running scripts
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void MaintenanceLoop()
|
public void MaintenanceLoop()
|
||||||
|
{
|
||||||
|
if (m_ScriptEngine.m_EventQueueManager.maxFunctionExecutionTimens < MaintenanceLoopms)
|
||||||
|
m_ScriptEngine.Log.Warn(m_ScriptEngine.ScriptEngineName,
|
||||||
|
"Configuration error: MaxEventExecutionTimeMs is less than MaintenanceLoopms. The Maintenance Loop will only check scripts once per run.");
|
||||||
|
|
||||||
|
while (true)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
long Last_maxFunctionExecutionTimens = 0;// DateTime.Now.Ticks;
|
long Last_maxFunctionExecutionTimens = 0; // DateTime.Now.Ticks;
|
||||||
long Last_ReReadConfigFilens = DateTime.Now.Ticks;
|
long Last_ReReadConfigFilens = DateTime.Now.Ticks;
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
System.Threading.Thread.Sleep(MaintenanceLoopms); // Sleep
|
System.Threading.Thread.Sleep(MaintenanceLoopms); // Sleep before next pass
|
||||||
|
if (PleaseShutdown)
|
||||||
// Re-reading config every x seconds?
|
return;
|
||||||
if (m_ScriptEngine.ReReadConfigFileSeconds > 0)
|
//
|
||||||
|
// Re-reading config every x seconds
|
||||||
|
//
|
||||||
|
if (m_ScriptEngine.RefreshConfigFileSeconds > 0)
|
||||||
{
|
{
|
||||||
// Check if its time to re-read config
|
// Check if its time to re-read config
|
||||||
if (DateTime.Now.Ticks - Last_ReReadConfigFilens > m_ScriptEngine.ReReadConfigFilens)
|
if (DateTime.Now.Ticks - Last_ReReadConfigFilens > m_ScriptEngine.RefreshConfigFilens)
|
||||||
{
|
{
|
||||||
// Its time to re-read config file
|
// Its time to re-read config file
|
||||||
m_ScriptEngine.ConfigSource.Reload(); // Re-read config
|
m_ScriptEngine.ConfigSource.Reload(); // Refresh config
|
||||||
|
m_ScriptEngine.ReadConfig();
|
||||||
Last_ReReadConfigFilens = DateTime.Now.Ticks; // Reset time
|
Last_ReReadConfigFilens = DateTime.Now.Ticks; // Reset time
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
// Adjust number of running script threads if not correct
|
// Adjust number of running script threads if not correct
|
||||||
if (m_ScriptEngine.m_EventQueueManager.eventQueueThreads.Count != m_ScriptEngine.m_EventQueueManager.numberOfThreads)
|
//
|
||||||
{
|
|
||||||
m_ScriptEngine.m_EventQueueManager.AdjustNumberOfScriptThreads();
|
m_ScriptEngine.m_EventQueueManager.AdjustNumberOfScriptThreads();
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
// Check if any script has exceeded its max execution time
|
// Check if any script has exceeded its max execution time
|
||||||
|
//
|
||||||
if (m_ScriptEngine.m_EventQueueManager.EnforceMaxExecutionTime)
|
if (m_ScriptEngine.m_EventQueueManager.EnforceMaxExecutionTime)
|
||||||
{
|
{
|
||||||
if (DateTime.Now.Ticks - Last_maxFunctionExecutionTimens > m_ScriptEngine.m_EventQueueManager.maxFunctionExecutionTimens)
|
// We are enforcing execution time
|
||||||
|
if (DateTime.Now.Ticks - Last_maxFunctionExecutionTimens >
|
||||||
|
m_ScriptEngine.m_EventQueueManager.maxFunctionExecutionTimens)
|
||||||
{
|
{
|
||||||
|
// Its time to check again
|
||||||
m_ScriptEngine.m_EventQueueManager.CheckScriptMaxExecTime(); // Do check
|
m_ScriptEngine.m_EventQueueManager.CheckScriptMaxExecTime(); // Do check
|
||||||
Last_maxFunctionExecutionTimens = DateTime.Now.Ticks; // Reset time
|
Last_maxFunctionExecutionTimens = DateTime.Now.Ticks; // Reset time
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (ThreadAbortException tae)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
m_ScriptEngine.Log.Error(m_ScriptEngine.ScriptEngineName, "Exception in MaintenanceLoopThread. Thread will recover after 5 sec throttle. Exception: " + ex.ToString());
|
||||||
|
Thread.Sleep(5000);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
/// <summary>
|
||||||
|
/// If set to true then threads and stuff should try to make a graceful exit
|
||||||
|
/// </summary>
|
||||||
|
public bool PleaseShutdown
|
||||||
|
{
|
||||||
|
get { return _PleaseShutdown; }
|
||||||
|
set { _PleaseShutdown = value; }
|
||||||
|
}
|
||||||
|
private bool _PleaseShutdown = false;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,27 +42,28 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
|
||||||
/// </summary>
|
/// </summary>
|
||||||
///
|
///
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public abstract class ScriptEngine : IRegionModule, OpenSim.Region.ScriptEngine.Common.ScriptServerInterfaces.ScriptEngine
|
public abstract class ScriptEngine : IRegionModule, OpenSim.Region.ScriptEngine.Common.ScriptServerInterfaces.ScriptEngine, iScriptEngineFunctionModule
|
||||||
{
|
{
|
||||||
public Scene World;
|
public Scene World;
|
||||||
public EventManager m_EventManager; // Handles and queues incoming events from OpenSim
|
public EventManager m_EventManager; // Handles and queues incoming events from OpenSim
|
||||||
public EventQueueManager m_EventQueueManager; // Executes events
|
public EventQueueManager m_EventQueueManager; // Executes events, handles script threads
|
||||||
public ScriptManager m_ScriptManager; // Load, unload and execute scripts
|
public ScriptManager m_ScriptManager; // Load, unload and execute scripts
|
||||||
public AppDomainManager m_AppDomainManager;
|
public AppDomainManager m_AppDomainManager; // Handles loading/unloading of scripts into AppDomains
|
||||||
public LSLLongCmdHandler m_LSLLongCmdHandler;
|
public AsyncLSLCommandManager m_ASYNCLSLCommandManager; // Asyncronous LSL commands (commands that returns with an event)
|
||||||
|
public MaintenanceThread m_MaintenanceThread; // Thread that does different kinds of maintenance, for example refreshing config and killing scripts that has been running too long
|
||||||
|
|
||||||
public IConfigSource ConfigSource;
|
public IConfigSource ConfigSource;
|
||||||
public IConfig ScriptConfigSource;
|
public IConfig ScriptConfigSource;
|
||||||
public abstract string ScriptConfigSourceName { get; }
|
public abstract string ScriptEngineName { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// How many seconds between re-reading config-file. 0 = never. ScriptEngine will try to adjust to new config changes.
|
/// How many seconds between re-reading config-file. 0 = never. ScriptEngine will try to adjust to new config changes.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int ReReadConfigFileSeconds {
|
public int RefreshConfigFileSeconds {
|
||||||
get { return (int)(ReReadConfigFilens / 10000); }
|
get { return (int)(RefreshConfigFilens / 10000); }
|
||||||
set { ReReadConfigFilens = value * 10000; }
|
set { RefreshConfigFilens = value * 10000; }
|
||||||
}
|
}
|
||||||
public long ReReadConfigFilens = 0;
|
public long RefreshConfigFilens = 0;
|
||||||
|
|
||||||
public ScriptManager GetScriptManager()
|
public ScriptManager GetScriptManager()
|
||||||
{
|
{
|
||||||
|
@ -88,21 +89,22 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
|
||||||
{
|
{
|
||||||
World = Sceneworld;
|
World = Sceneworld;
|
||||||
m_log = logger;
|
m_log = logger;
|
||||||
ScriptConfigSource = ConfigSource.Configs[ScriptConfigSourceName];
|
ScriptConfigSource = ConfigSource.Configs[ScriptEngineName];
|
||||||
|
|
||||||
Log.Verbose("ScriptEngine", "DotNet & LSL ScriptEngine initializing");
|
Log.Verbose(ScriptEngineName, "DotNet & LSL ScriptEngine initializing");
|
||||||
|
|
||||||
//m_logger.Status("ScriptEngine", "InitializeEngine");
|
//m_logger.Status(ScriptEngineName, "InitializeEngine");
|
||||||
|
|
||||||
// Create all objects we'll be using
|
// Create all objects we'll be using
|
||||||
m_EventQueueManager = new EventQueueManager(this);
|
m_EventQueueManager = new EventQueueManager(this);
|
||||||
m_EventManager = new EventManager(this, HookUpToServer);
|
m_EventManager = new EventManager(this, HookUpToServer);
|
||||||
m_ScriptManager = newScriptManager;
|
m_ScriptManager = newScriptManager;
|
||||||
//m_ScriptManager = new ScriptManager(this);
|
m_AppDomainManager = new AppDomainManager(this);
|
||||||
m_AppDomainManager = new AppDomainManager(ScriptConfigSource.GetInt("ScriptsPerAppDomain", 1));
|
m_ASYNCLSLCommandManager = new AsyncLSLCommandManager(this);
|
||||||
m_LSLLongCmdHandler = new LSLLongCmdHandler(this);
|
m_MaintenanceThread = new MaintenanceThread(this);
|
||||||
|
|
||||||
|
ReadConfig();
|
||||||
|
|
||||||
ReReadConfigFileSeconds = ScriptConfigSource.GetInt("ReReadConfig", 0);
|
|
||||||
|
|
||||||
|
|
||||||
// Should we iterate the region for scripts that needs starting?
|
// Should we iterate the region for scripts that needs starting?
|
||||||
|
@ -118,6 +120,26 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
|
||||||
{
|
{
|
||||||
return this.m_EventManager;
|
return this.m_EventManager;
|
||||||
}
|
}
|
||||||
|
public void ReadConfig()
|
||||||
|
{
|
||||||
|
#if DEBUG
|
||||||
|
Log.Debug(ScriptEngineName, "Refreshing configuration for all modules");
|
||||||
|
#endif
|
||||||
|
RefreshConfigFileSeconds = ScriptConfigSource.GetInt("RefreshConfig", 0);
|
||||||
|
|
||||||
|
// Reload from disk
|
||||||
|
ConfigSource.Reload();
|
||||||
|
// Create a new object (probably not necessary?)
|
||||||
|
// ScriptConfigSource = ConfigSource.Configs[ScriptEngineName];
|
||||||
|
|
||||||
|
if (m_EventQueueManager != null) m_EventQueueManager.ReadConfig();
|
||||||
|
if (m_EventManager != null) m_EventManager.ReadConfig();
|
||||||
|
if (m_ScriptManager != null) m_ScriptManager.ReadConfig();
|
||||||
|
if (m_AppDomainManager != null) m_AppDomainManager.ReadConfig();
|
||||||
|
if (m_ASYNCLSLCommandManager != null) m_ASYNCLSLCommandManager.ReadConfig();
|
||||||
|
if (m_MaintenanceThread != null) m_MaintenanceThread.ReadConfig();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#region IRegionModule
|
#region IRegionModule
|
||||||
|
@ -134,7 +156,7 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
|
||||||
|
|
||||||
public string Name
|
public string Name
|
||||||
{
|
{
|
||||||
get { return "DotNetEngine"; }
|
get { return "Common." + ScriptEngineName; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsSharedModule
|
public bool IsSharedModule
|
||||||
|
@ -146,5 +168,15 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// If set to true then threads and stuff should try to make a graceful exit
|
||||||
|
/// </summary>
|
||||||
|
public bool PleaseShutdown
|
||||||
|
{
|
||||||
|
get { return _PleaseShutdown; }
|
||||||
|
set { _PleaseShutdown = value; }
|
||||||
|
}
|
||||||
|
private bool _PleaseShutdown = false;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -57,12 +57,12 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
|
||||||
// This so that scripts starting or stopping will not slow down other theads or whole system.
|
// This so that scripts starting or stopping will not slow down other theads or whole system.
|
||||||
//
|
//
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public abstract class ScriptManager
|
public abstract class ScriptManager : iScriptEngineFunctionModule
|
||||||
{
|
{
|
||||||
#region Declares
|
#region Declares
|
||||||
|
|
||||||
private Thread scriptLoadUnloadThread;
|
private Thread scriptLoadUnloadThread;
|
||||||
private int scriptLoadUnloadThread_IdleSleepms = 100;
|
private int scriptLoadUnloadThread_IdleSleepms;
|
||||||
private Queue<LUStruct> LUQueue = new Queue<LUStruct>();
|
private Queue<LUStruct> LUQueue = new Queue<LUStruct>();
|
||||||
|
|
||||||
|
|
||||||
|
@ -95,6 +95,11 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
public void ReadConfig()
|
||||||
|
{
|
||||||
|
scriptLoadUnloadThread_IdleSleepms = m_scriptEngine.ScriptConfigSource.GetInt("ScriptLoadUnloadLoopms", 30);
|
||||||
|
}
|
||||||
|
|
||||||
#region Object init/shutdown
|
#region Object init/shutdown
|
||||||
|
|
||||||
public ScriptEngineBase.ScriptEngine m_scriptEngine;
|
public ScriptEngineBase.ScriptEngine m_scriptEngine;
|
||||||
|
@ -102,6 +107,7 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
|
||||||
public ScriptManager(ScriptEngineBase.ScriptEngine scriptEngine)
|
public ScriptManager(ScriptEngineBase.ScriptEngine scriptEngine)
|
||||||
{
|
{
|
||||||
m_scriptEngine = scriptEngine;
|
m_scriptEngine = scriptEngine;
|
||||||
|
ReadConfig();
|
||||||
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
|
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
|
||||||
scriptLoadUnloadThread = new Thread(ScriptLoadUnloadThreadLoop);
|
scriptLoadUnloadThread = new Thread(ScriptLoadUnloadThreadLoop);
|
||||||
scriptLoadUnloadThread.Name = "ScriptLoadUnloadThread";
|
scriptLoadUnloadThread.Name = "ScriptLoadUnloadThread";
|
||||||
|
@ -238,7 +244,7 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
|
||||||
Console.WriteLine("ScriptEngine: Inside ExecuteEvent for event " + FunctionName);
|
Console.WriteLine("ScriptEngine: Inside ExecuteEvent for event " + FunctionName);
|
||||||
#endif
|
#endif
|
||||||
// Execute a function in the script
|
// Execute a function in the script
|
||||||
//m_scriptEngine.Log.Verbose("ScriptEngine", "Executing Function localID: " + localID + ", itemID: " + itemID + ", FunctionName: " + FunctionName);
|
//m_scriptEngine.Log.Verbose(ScriptEngineName, "Executing Function localID: " + localID + ", itemID: " + itemID + ", FunctionName: " + FunctionName);
|
||||||
//ScriptBaseInterface Script = (ScriptBaseInterface)GetScript(localID, itemID);
|
//ScriptBaseInterface Script = (ScriptBaseInterface)GetScript(localID, itemID);
|
||||||
IScript Script = GetScript(localID, itemID);
|
IScript Script = GetScript(localID, itemID);
|
||||||
if (Script == null)
|
if (Script == null)
|
||||||
|
@ -345,5 +351,16 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// If set to true then threads and stuff should try to make a graceful exit
|
||||||
|
/// </summary>
|
||||||
|
public bool PleaseShutdown
|
||||||
|
{
|
||||||
|
get { return _PleaseShutdown; }
|
||||||
|
set { _PleaseShutdown = value; }
|
||||||
|
}
|
||||||
|
private bool _PleaseShutdown = false;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
|
||||||
|
{
|
||||||
|
public interface iScriptEngineFunctionModule
|
||||||
|
{
|
||||||
|
void ReadConfig();
|
||||||
|
bool PleaseShutdown { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -48,7 +48,7 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine
|
||||||
return new ScriptManager(this);
|
return new ScriptManager(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string ScriptConfigSourceName
|
public override string ScriptEngineName
|
||||||
{
|
{
|
||||||
get { return "ScriptEngine.DotNetEngine"; }
|
get { return "ScriptEngine.DotNetEngine"; }
|
||||||
}
|
}
|
||||||
|
|
|
@ -124,7 +124,7 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine
|
||||||
|
|
||||||
|
|
||||||
// Stop long command on script
|
// Stop long command on script
|
||||||
m_scriptEngine.m_LSLLongCmdHandler.RemoveScript(localID, itemID);
|
m_scriptEngine.m_ASYNCLSLCommandManager.RemoveScript(localID, itemID);
|
||||||
|
|
||||||
IScript LSLBC = GetScript(localID, itemID);
|
IScript LSLBC = GetScript(localID, itemID);
|
||||||
if (LSLBC == null)
|
if (LSLBC == null)
|
||||||
|
|
|
@ -52,7 +52,7 @@ namespace OpenSim.Region.ScriptEngine.LSOEngine
|
||||||
return new ScriptManager(this);
|
return new ScriptManager(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string ScriptConfigSourceName
|
public override string ScriptEngineName
|
||||||
{
|
{
|
||||||
get { return "ScriptEngine.LSOEngine"; }
|
get { return "ScriptEngine.LSOEngine"; }
|
||||||
}
|
}
|
||||||
|
|
|
@ -127,7 +127,7 @@ namespace OpenSim.Region.ScriptEngine.LSOEngine
|
||||||
|
|
||||||
|
|
||||||
// Stop long command on script
|
// Stop long command on script
|
||||||
m_scriptEngine.m_LSLLongCmdHandler.RemoveScript(localID, itemID);
|
m_scriptEngine.m_ASYNCLSLCommandManager.RemoveScript(localID, itemID);
|
||||||
|
|
||||||
IScript LSLBC = GetScript(localID, itemID);
|
IScript LSLBC = GetScript(localID, itemID);
|
||||||
if (LSLBC == null)
|
if (LSLBC == null)
|
||||||
|
|
|
@ -123,6 +123,13 @@ shout_distance = 100
|
||||||
; Same if you have 10 threads, then only 10 scripts can be run simultaneously.
|
; Same if you have 10 threads, then only 10 scripts can be run simultaneously.
|
||||||
; But because most scripts exit after their task, the threads are free to go on to the next script.
|
; But because most scripts exit after their task, the threads are free to go on to the next script.
|
||||||
|
|
||||||
|
; Refresh ScriptEngine config options (these settings) every xx seconds
|
||||||
|
; 0 = Do not refresh
|
||||||
|
; Set it to number of seconds between refresh, for example 30.
|
||||||
|
; Will allow you to change ScriptEngine settings while server is running just by editing this file.
|
||||||
|
; For example to increase or decrease number of threads.
|
||||||
|
RefreshConfig=0
|
||||||
|
|
||||||
; Number of threads to use for script event execution
|
; Number of threads to use for script event execution
|
||||||
; Threads are shared across all regions
|
; Threads are shared across all regions
|
||||||
NumberOfScriptThreads=2
|
NumberOfScriptThreads=2
|
||||||
|
@ -136,6 +143,7 @@ ScriptThreadPriority=BelowNormal
|
||||||
; Number of threads will be <NumberOfScriptThreads>*<NumberOfRegions>
|
; Number of threads will be <NumberOfScriptThreads>*<NumberOfRegions>
|
||||||
; false: All regions share <NumberOfScriptThreads> for all their scripts
|
; false: All regions share <NumberOfScriptThreads> for all their scripts
|
||||||
; Note! If you run multiple script engines based on "OpenSim.Region.ScriptEngine.Common" then all of them will share the same threads.
|
; Note! If you run multiple script engines based on "OpenSim.Region.ScriptEngine.Common" then all of them will share the same threads.
|
||||||
|
; *** This setting will not work until you restart OpenSim
|
||||||
PrivateRegionThreads=false
|
PrivateRegionThreads=false
|
||||||
|
|
||||||
; How long MAX should a script event be allowed to run (per event execution)?
|
; How long MAX should a script event be allowed to run (per event execution)?
|
||||||
|
@ -164,5 +172,14 @@ SleepTimeIfNoScriptExecutionMs=50
|
||||||
; Each AppDomain has some memory overhead. But leaving dead scripts in memory also has memory overhead.
|
; Each AppDomain has some memory overhead. But leaving dead scripts in memory also has memory overhead.
|
||||||
ScriptsPerAppDomain=1
|
ScriptsPerAppDomain=1
|
||||||
|
|
||||||
; ReRead ScriptEngine config options how often?
|
; Script loading / unloading sleep
|
||||||
ReReadConfig=0
|
; How long load/unload thread should sleep if there is nothing to do
|
||||||
|
; Higher value makes it respond slower when scripts are added/removed from prims
|
||||||
|
; But once active it will process all in queue before sleeping again
|
||||||
|
ScriptLoadUnloadLoopms=30
|
||||||
|
|
||||||
|
; Async LL command sleep
|
||||||
|
; If no async LL commands are waiting, how long should thread sleep before checking again
|
||||||
|
; Async LL commands are LSL-commands that causes an event to be fired back with result
|
||||||
|
AsyncLLCommandLoopms=50
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue