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 MaintenanceThread
ThreadPoolClientBranch
Tedd Hansen 2008-02-01 23:36:36 +00:00
parent a6726b0c9d
commit d02a90823f
17 changed files with 621 additions and 404 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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