Execution threads are now shared between regions too. Default thread count regardless of number of regions is now 3. This will save you around 33 threads for a normal 3x3 region server.
But, this is totally completely untested. So it probably won't work for another patch or five.afrisby-rexmerge
parent
3bb0fe098f
commit
a43bb10000
|
@ -45,7 +45,7 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
|
||||||
public class EventQueueManager : iScriptEngineFunctionModule
|
public class EventQueueManager : iScriptEngineFunctionModule
|
||||||
{
|
{
|
||||||
//
|
//
|
||||||
// Class is instanced in "ScriptEngine" and used by "EventManager" also instanced in "ScriptEngine".
|
// Class is instanced in "ScriptEngine" and used by "EventManager" which is also instanced in "ScriptEngine".
|
||||||
//
|
//
|
||||||
// Class purpose is to queue and execute functions that are received by "EventManager":
|
// Class purpose is to queue and execute functions that are received by "EventManager":
|
||||||
// - allowing "EventManager" to release its event thread immediately, thus not interrupting server execution.
|
// - allowing "EventManager" to release its event thread immediately, thus not interrupting server execution.
|
||||||
|
@ -68,25 +68,25 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
|
||||||
/// List of threads (classes) processing event queue
|
/// List of threads (classes) processing event queue
|
||||||
/// Note that this may or may not be a reference to a static object depending on PrivateRegionThreads config setting.
|
/// Note that this may or may not be a reference to a static object depending on PrivateRegionThreads config setting.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal List<EventQueueThreadClass> eventQueueThreads; // Thread pool that we work on
|
internal static List<EventQueueThreadClass> eventQueueThreads; // Thread pool that we work on
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Locking access to eventQueueThreads AND staticGlobalEventQueueThreads.
|
/// Locking access to eventQueueThreads AND staticGlobalEventQueueThreads.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
// private object eventQueueThreadsLock = new object();
|
// private object eventQueueThreadsLock = new object();
|
||||||
// Static objects for referencing the objects above if we don't have private threads:
|
// Static objects for referencing the objects above if we don't have private threads:
|
||||||
internal static List<EventQueueThreadClass> staticEventQueueThreads; // A static reference used if we don't use private threads
|
//internal static List<EventQueueThreadClass> staticEventQueueThreads; // A static reference used if we don't use private threads
|
||||||
// internal static object staticEventQueueThreadsLock; // Statick lock object reference for same reason
|
// internal static object staticEventQueueThreadsLock; // Statick lock object reference for same reason
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Global static list of all threads (classes) processing event queue -- used by max enforcment thread
|
/// Global static list of all threads (classes) processing event queue -- used by max enforcment thread
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private List<EventQueueThreadClass> staticGlobalEventQueueThreads = new List<EventQueueThreadClass>();
|
//private List<EventQueueThreadClass> staticGlobalEventQueueThreads = new List<EventQueueThreadClass>();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Used internally to specify how many threads should exit gracefully
|
/// Used internally to specify how many threads should exit gracefully
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int ThreadsToExit;
|
public static int ThreadsToExit;
|
||||||
public object ThreadsToExitLock = new object();
|
public static object ThreadsToExitLock = new object();
|
||||||
|
|
||||||
|
|
||||||
//public object queueLock = new object(); // Mutex lock object
|
//public object queueLock = new object(); // Mutex lock object
|
||||||
|
@ -94,14 +94,14 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// How many threads to process queue with
|
/// How many threads to process queue with
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal int numberOfThreads;
|
internal static int numberOfThreads;
|
||||||
|
|
||||||
internal static int EventExecutionMaxQueueSize;
|
internal static int EventExecutionMaxQueueSize;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Maximum time one function can use for execution before we perform a thread kill.
|
/// Maximum time one function can use for execution before we perform a thread kill.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private int maxFunctionExecutionTimems
|
private static int maxFunctionExecutionTimems
|
||||||
{
|
{
|
||||||
get { return (int)(maxFunctionExecutionTimens / 10000); }
|
get { return (int)(maxFunctionExecutionTimens / 10000); }
|
||||||
set { maxFunctionExecutionTimens = value * 10000; }
|
set { maxFunctionExecutionTimens = value * 10000; }
|
||||||
|
@ -111,15 +111,15 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
|
||||||
/// Contains nanoseconds version of maxFunctionExecutionTimems so that it matches time calculations better (performance reasons).
|
/// Contains nanoseconds version of maxFunctionExecutionTimems so that it matches time calculations better (performance reasons).
|
||||||
/// WARNING! ONLY UPDATE maxFunctionExecutionTimems, NEVER THIS DIRECTLY.
|
/// WARNING! ONLY UPDATE maxFunctionExecutionTimems, NEVER THIS DIRECTLY.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public long maxFunctionExecutionTimens;
|
public static long maxFunctionExecutionTimens;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Enforce max execution time
|
/// Enforce max execution time
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool EnforceMaxExecutionTime;
|
public static bool EnforceMaxExecutionTime;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Kill script (unload) when it exceeds execution time
|
/// Kill script (unload) when it exceeds execution time
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private bool KillScriptOnMaxFunctionExecutionTime;
|
private static bool KillScriptOnMaxFunctionExecutionTime;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// List of localID locks for mutex processing of script events
|
/// List of localID locks for mutex processing of script events
|
||||||
|
@ -172,33 +172,8 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
|
||||||
{
|
{
|
||||||
m_ScriptEngine = _ScriptEngine;
|
m_ScriptEngine = _ScriptEngine;
|
||||||
|
|
||||||
// TODO: We need to move from single EventQueueManager to list of it in to share threads
|
eventQueueThreads = new List<EventQueueThreadClass>();
|
||||||
bool PrivateRegionThreads = true; // m_ScriptEngine.ScriptConfigSource.GetBoolean("PrivateRegionThreads", false);
|
|
||||||
|
|
||||||
// Create thread pool list and lock object
|
|
||||||
// Determine from config if threads should be dedicated to regions or shared
|
|
||||||
if (PrivateRegionThreads)
|
|
||||||
{
|
|
||||||
// PRIVATE THREAD POOL PER REGION
|
|
||||||
eventQueueThreads = new List<EventQueueThreadClass>();
|
|
||||||
// eventQueueThreadsLock = new object();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// SHARED THREAD POOL
|
|
||||||
// Crate the static objects
|
|
||||||
if (staticEventQueueThreads == null)
|
|
||||||
staticEventQueueThreads = new List<EventQueueThreadClass>();
|
|
||||||
// if (staticEventQueueThreadsLock == null)
|
|
||||||
// staticEventQueueThreadsLock = new object();
|
|
||||||
|
|
||||||
// Now reference our locals to them
|
|
||||||
eventQueueThreads = staticEventQueueThreads;
|
|
||||||
//eventQueueThreadsLock = staticEventQueueThreadsLock;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReadConfig();
|
ReadConfig();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ReadConfig()
|
public void ReadConfig()
|
||||||
|
@ -230,18 +205,18 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
|
||||||
|
|
||||||
private void Stop()
|
private void Stop()
|
||||||
{
|
{
|
||||||
if (eventQueueThreads != null && eventQueueThreads != null)
|
if (eventQueueThreads != null)
|
||||||
{
|
{
|
||||||
// Kill worker threads
|
// Kill worker threads
|
||||||
//lock (eventQueueThreads)
|
lock (eventQueueThreads)
|
||||||
//{
|
{
|
||||||
foreach (EventQueueThreadClass EventQueueThread in new ArrayList(eventQueueThreads))
|
foreach (EventQueueThreadClass EventQueueThread in new ArrayList(eventQueueThreads))
|
||||||
{
|
{
|
||||||
AbortThreadClass(EventQueueThread);
|
AbortThreadClass(EventQueueThread);
|
||||||
}
|
}
|
||||||
//eventQueueThreads.Clear();
|
//eventQueueThreads.Clear();
|
||||||
//staticGlobalEventQueueThreads.Clear();
|
//staticGlobalEventQueueThreads.Clear();
|
||||||
//}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove all entries from our event queue
|
// Remove all entries from our event queue
|
||||||
|
@ -256,9 +231,8 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
|
||||||
#region " Start / stop script execution threads (ThreadClasses) "
|
#region " Start / stop script execution threads (ThreadClasses) "
|
||||||
private void StartNewThreadClass()
|
private void StartNewThreadClass()
|
||||||
{
|
{
|
||||||
EventQueueThreadClass eqtc = new EventQueueThreadClass(this);
|
EventQueueThreadClass eqtc = new EventQueueThreadClass();
|
||||||
eventQueueThreads.Add(eqtc);
|
eventQueueThreads.Add(eqtc);
|
||||||
staticGlobalEventQueueThreads.Add(eqtc);
|
|
||||||
m_ScriptEngine.Log.Debug("[" + m_ScriptEngine.ScriptEngineName + "]: 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -266,8 +240,6 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
|
||||||
{
|
{
|
||||||
if (eventQueueThreads.Contains(threadClass))
|
if (eventQueueThreads.Contains(threadClass))
|
||||||
eventQueueThreads.Remove(threadClass);
|
eventQueueThreads.Remove(threadClass);
|
||||||
if (staticGlobalEventQueueThreads.Contains(threadClass))
|
|
||||||
staticGlobalEventQueueThreads.Remove(threadClass);
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -426,7 +398,7 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
|
||||||
// Iterate through all ScriptThreadClasses and check how long their current function has been executing
|
// Iterate through all ScriptThreadClasses and check how long their current function has been executing
|
||||||
lock (eventQueueThreads)
|
lock (eventQueueThreads)
|
||||||
{
|
{
|
||||||
foreach (EventQueueThreadClass EventQueueThread in staticGlobalEventQueueThreads)
|
foreach (EventQueueThreadClass EventQueueThread in eventQueueThreads)
|
||||||
{
|
{
|
||||||
// Is thread currently executing anything?
|
// Is thread currently executing anything?
|
||||||
if (EventQueueThread.InExecution)
|
if (EventQueueThread.InExecution)
|
||||||
|
|
|
@ -40,27 +40,27 @@ 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: iScriptEngineFunctionModule
|
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 static int nothingToDoSleepms;// = 50;
|
||||||
private ThreadPriority MyThreadPriority;
|
private static ThreadPriority MyThreadPriority;
|
||||||
|
|
||||||
public long LastExecutionStarted;
|
public long LastExecutionStarted;
|
||||||
public bool InExecution = false;
|
public bool InExecution = false;
|
||||||
public bool KillCurrentScript = false;
|
public bool KillCurrentScript = false;
|
||||||
|
|
||||||
private EventQueueManager eventQueueManager;
|
//private EventQueueManager eventQueueManager;
|
||||||
public Thread EventQueueThread;
|
public Thread EventQueueThread;
|
||||||
private static int ThreadCount = 0;
|
private static int ThreadCount = 0;
|
||||||
|
|
||||||
private string ScriptEngineName = "ScriptEngine.Common";
|
private string ScriptEngineName = "ScriptEngine.Common";
|
||||||
|
|
||||||
public EventQueueThreadClass(EventQueueManager eqm)
|
public EventQueueThreadClass()//EventQueueManager eqm
|
||||||
{
|
{
|
||||||
eventQueueManager = eqm;
|
//eventQueueManager = eqm;
|
||||||
ReadConfig();
|
ReadConfig();
|
||||||
Start();
|
Start();
|
||||||
}
|
}
|
||||||
|
@ -72,32 +72,36 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
|
||||||
|
|
||||||
public void ReadConfig()
|
public void ReadConfig()
|
||||||
{
|
{
|
||||||
ScriptEngineName = eventQueueManager.m_ScriptEngine.ScriptEngineName;
|
foreach (ScriptEngine m_ScriptEngine in ScriptEngine.ScriptEngines)
|
||||||
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
|
|
||||||
string pri = eventQueueManager.m_ScriptEngine.ScriptConfigSource.GetString("ScriptThreadPriority", "BelowNormal");
|
|
||||||
switch (pri.ToLower())
|
|
||||||
{
|
{
|
||||||
case "lowest":
|
ScriptEngineName = m_ScriptEngine.ScriptEngineName;
|
||||||
MyThreadPriority = ThreadPriority.Lowest;
|
nothingToDoSleepms = m_ScriptEngine.ScriptConfigSource.GetInt("SleepTimeIfNoScriptExecutionMs", 50);
|
||||||
break;
|
|
||||||
case "belownormal":
|
// Later with ScriptServer we might want to ask OS for stuff too, so doing this a bit manually
|
||||||
MyThreadPriority = ThreadPriority.BelowNormal;
|
string pri = m_ScriptEngine.ScriptConfigSource.GetString("ScriptThreadPriority", "BelowNormal");
|
||||||
break;
|
switch (pri.ToLower())
|
||||||
case "normal":
|
{
|
||||||
MyThreadPriority = ThreadPriority.Normal;
|
case "lowest":
|
||||||
break;
|
MyThreadPriority = ThreadPriority.Lowest;
|
||||||
case "abovenormal":
|
break;
|
||||||
MyThreadPriority = ThreadPriority.AboveNormal;
|
case "belownormal":
|
||||||
break;
|
MyThreadPriority = ThreadPriority.BelowNormal;
|
||||||
case "highest":
|
break;
|
||||||
MyThreadPriority = ThreadPriority.Highest;
|
case "normal":
|
||||||
break;
|
MyThreadPriority = ThreadPriority.Normal;
|
||||||
default:
|
break;
|
||||||
MyThreadPriority = ThreadPriority.BelowNormal; // Default
|
case "abovenormal":
|
||||||
eventQueueManager.m_ScriptEngine.Log.Error("[ScriptEngineBase]: Unknown priority type \"" + pri + "\" in config file. Defaulting to \"BelowNormal\".");
|
MyThreadPriority = ThreadPriority.AboveNormal;
|
||||||
break;
|
break;
|
||||||
|
case "highest":
|
||||||
|
MyThreadPriority = ThreadPriority.Highest;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
MyThreadPriority = ThreadPriority.BelowNormal; // Default
|
||||||
|
m_ScriptEngine.Log.Error("[ScriptEngineBase]: Unknown priority type \"" + pri +
|
||||||
|
"\" in config file. Defaulting to \"BelowNormal\".");
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now set that priority
|
// Now set that priority
|
||||||
|
@ -127,8 +131,8 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
|
||||||
|
|
||||||
public void Stop()
|
public void Stop()
|
||||||
{
|
{
|
||||||
PleaseShutdown = true; // Set shutdown flag
|
//PleaseShutdown = true; // Set shutdown flag
|
||||||
Thread.Sleep(100); // Wait a bit
|
//Thread.Sleep(100); // Wait a bit
|
||||||
if (EventQueueThread != null && EventQueueThread.IsAlive == true)
|
if (EventQueueThread != null && EventQueueThread.IsAlive == true)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
@ -143,6 +147,8 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private EventQueueManager.QueueItemStruct BlankQIS = new EventQueueManager.QueueItemStruct();
|
||||||
|
private ScriptEngine lastScriptEngine;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Queue processing thread loop
|
/// Queue processing thread loop
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -151,171 +157,24 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
|
||||||
//myScriptEngine.Log.Info("[" + ScriptEngineName + "]: EventQueueManager Worker thread spawned");
|
//myScriptEngine.Log.Info("[" + ScriptEngineName + "]: EventQueueManager Worker thread spawned");
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
EventQueueManager.QueueItemStruct BlankQIS = new EventQueueManager.QueueItemStruct();
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
// Every now and then check if we should shut down
|
DoProcessQueue();
|
||||||
if (PleaseShutdown || eventQueueManager.ThreadsToExit > 0)
|
|
||||||
{
|
|
||||||
// Someone should shut down, lets get exclusive lock
|
|
||||||
lock (eventQueueManager.ThreadsToExitLock)
|
|
||||||
{
|
|
||||||
// Lets re-check in case someone grabbed it
|
|
||||||
if (eventQueueManager.ThreadsToExit > 0)
|
|
||||||
{
|
|
||||||
// Its crowded here so we'll shut down
|
|
||||||
eventQueueManager.ThreadsToExit--;
|
|
||||||
Stop();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// We have been asked to shut down
|
|
||||||
Stop();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//try
|
|
||||||
// {
|
|
||||||
EventQueueManager.QueueItemStruct QIS = BlankQIS;
|
|
||||||
bool GotItem = false;
|
|
||||||
|
|
||||||
if (PleaseShutdown)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (eventQueueManager.eventQueue.Count == 0)
|
|
||||||
{
|
|
||||||
// Nothing to do? Sleep a bit waiting for something to do
|
|
||||||
Thread.Sleep(nothingToDoSleepms);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Something in queue, process
|
|
||||||
//myScriptEngine.Log.Info("[" + 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
|
|
||||||
lock (eventQueueManager.eventQueue)
|
|
||||||
{
|
|
||||||
GotItem = false;
|
|
||||||
for (int qc = 0; qc < eventQueueManager.eventQueue.Count; qc++)
|
|
||||||
{
|
|
||||||
// Get queue item
|
|
||||||
QIS = eventQueueManager.eventQueue.Dequeue();
|
|
||||||
|
|
||||||
// Check if object is being processed by someone else
|
|
||||||
if (eventQueueManager.TryLock(QIS.localID) == false)
|
|
||||||
{
|
|
||||||
// Object is already being processed, requeue it
|
|
||||||
eventQueueManager.eventQueue.Enqueue(QIS);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// We have lock on an object and can process it
|
|
||||||
GotItem = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (GotItem == true)
|
|
||||||
{
|
|
||||||
// Execute function
|
|
||||||
try
|
|
||||||
{
|
|
||||||
///cfk 2-7-08 dont need this right now and the default Linux build has DEBUG defined
|
|
||||||
#if DEBUG
|
|
||||||
//eventQueueManager.m_ScriptEngine.Log.Debug("[" + ScriptEngineName + "]: " +
|
|
||||||
// "Executing event:\r\n"
|
|
||||||
// + "QIS.localID: " + QIS.localID
|
|
||||||
// + ", QIS.itemID: " + QIS.itemID
|
|
||||||
// + ", QIS.functionName: " +
|
|
||||||
// QIS.functionName);
|
|
||||||
#endif
|
|
||||||
LastExecutionStarted = DateTime.Now.Ticks;
|
|
||||||
KillCurrentScript = false;
|
|
||||||
InExecution = true;
|
|
||||||
eventQueueManager.m_ScriptEngine.m_ScriptManager.ExecuteEvent(QIS.localID,
|
|
||||||
QIS.itemID,
|
|
||||||
QIS.functionName,
|
|
||||||
QIS.llDetectParams,
|
|
||||||
QIS.param);
|
|
||||||
InExecution = false;
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
InExecution = false;
|
|
||||||
// DISPLAY ERROR INWORLD
|
|
||||||
string text = "Error executing script function \"" + QIS.functionName +
|
|
||||||
"\":\r\n";
|
|
||||||
if (e.InnerException != null)
|
|
||||||
{
|
|
||||||
// Send inner exception
|
|
||||||
text += e.InnerException.Message.ToString();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
text += "\r\n";
|
|
||||||
// Send normal
|
|
||||||
text += e.Message.ToString();
|
|
||||||
}
|
|
||||||
if (KillCurrentScript)
|
|
||||||
text += "\r\nScript will be deactivated!";
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (text.Length > 1500)
|
|
||||||
text = text.Substring(0, 1500);
|
|
||||||
IScriptHost m_host =
|
|
||||||
eventQueueManager.m_ScriptEngine.World.GetSceneObjectPart(QIS.localID);
|
|
||||||
//if (m_host != null)
|
|
||||||
//{
|
|
||||||
eventQueueManager.m_ScriptEngine.World.SimChat(Helpers.StringToField(text),
|
|
||||||
ChatTypeEnum.Say, 0,
|
|
||||||
m_host.AbsolutePosition,
|
|
||||||
m_host.Name, m_host.UUID);
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
//}
|
|
||||||
//else
|
|
||||||
//{
|
|
||||||
// T oconsole
|
|
||||||
eventQueueManager.m_ScriptEngine.Log.Error("[" + ScriptEngineName + "]: " +
|
|
||||||
"Unable to send text in-world:\r\n" +
|
|
||||||
text);
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
// So we are done sending message in-world
|
|
||||||
if (KillCurrentScript)
|
|
||||||
{
|
|
||||||
eventQueueManager.m_ScriptEngine.m_ScriptManager.StopScript(
|
|
||||||
QIS.localID, QIS.itemID);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
InExecution = false;
|
|
||||||
eventQueueManager.ReleaseLock(QIS.localID);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (ThreadAbortException tae)
|
catch (ThreadAbortException tae)
|
||||||
{
|
{
|
||||||
eventQueueManager.m_ScriptEngine.Log.Info("[" + ScriptEngineName + "]: ThreadAbortException while executing function.");
|
if (lastScriptEngine != null)
|
||||||
|
lastScriptEngine.Log.Info("[" + ScriptEngineName + "]: ThreadAbortException while executing function.");
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
eventQueueManager.m_ScriptEngine.Log.Error("[" + ScriptEngineName + "]: Exception in EventQueueThreadLoop: " + e.ToString());
|
if (lastScriptEngine != null)
|
||||||
|
lastScriptEngine.Log.Error("[" + ScriptEngineName + "]: Exception in EventQueueThreadLoop: " + e.ToString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -325,14 +184,171 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
public void DoProcessQueue()
|
||||||
/// If set to true then threads and stuff should try to make a graceful exit
|
|
||||||
/// </summary>
|
|
||||||
public bool PleaseShutdown
|
|
||||||
{
|
{
|
||||||
get { return _PleaseShutdown; }
|
foreach (ScriptEngine m_ScriptEngine in ScriptEngine.ScriptEngines)
|
||||||
set { _PleaseShutdown = value; }
|
{
|
||||||
|
lastScriptEngine = m_ScriptEngine;
|
||||||
|
// Every now and then check if we should shut down
|
||||||
|
//if (PleaseShutdown || EventQueueManager.ThreadsToExit > 0)
|
||||||
|
//{
|
||||||
|
// // Someone should shut down, lets get exclusive lock
|
||||||
|
// lock (EventQueueManager.ThreadsToExitLock)
|
||||||
|
// {
|
||||||
|
// // Lets re-check in case someone grabbed it
|
||||||
|
// if (EventQueueManager.ThreadsToExit > 0)
|
||||||
|
// {
|
||||||
|
// // Its crowded here so we'll shut down
|
||||||
|
// EventQueueManager.ThreadsToExit--;
|
||||||
|
// Stop();
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
// else
|
||||||
|
// {
|
||||||
|
// // We have been asked to shut down
|
||||||
|
// Stop();
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
|
//try
|
||||||
|
// {
|
||||||
|
EventQueueManager.QueueItemStruct QIS = BlankQIS;
|
||||||
|
bool GotItem = false;
|
||||||
|
|
||||||
|
//if (PleaseShutdown)
|
||||||
|
// return;
|
||||||
|
|
||||||
|
if (m_ScriptEngine.m_EventQueueManager.eventQueue.Count == 0)
|
||||||
|
{
|
||||||
|
// Nothing to do? Sleep a bit waiting for something to do
|
||||||
|
Thread.Sleep(nothingToDoSleepms);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Something in queue, process
|
||||||
|
//myScriptEngine.Log.Info("[" + 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
|
||||||
|
lock (m_ScriptEngine.m_EventQueueManager.eventQueue)
|
||||||
|
{
|
||||||
|
GotItem = false;
|
||||||
|
for (int qc = 0; qc < m_ScriptEngine.m_EventQueueManager.eventQueue.Count; qc++)
|
||||||
|
{
|
||||||
|
// Get queue item
|
||||||
|
QIS = m_ScriptEngine.m_EventQueueManager.eventQueue.Dequeue();
|
||||||
|
|
||||||
|
// Check if object is being processed by someone else
|
||||||
|
if (m_ScriptEngine.m_EventQueueManager.TryLock(QIS.localID) == false)
|
||||||
|
{
|
||||||
|
// Object is already being processed, requeue it
|
||||||
|
m_ScriptEngine.m_EventQueueManager.eventQueue.Enqueue(QIS);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// We have lock on an object and can process it
|
||||||
|
GotItem = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GotItem == true)
|
||||||
|
{
|
||||||
|
// Execute function
|
||||||
|
try
|
||||||
|
{
|
||||||
|
///cfk 2-7-08 dont need this right now and the default Linux build has DEBUG defined
|
||||||
|
#if DEBUG
|
||||||
|
//eventQueueManager.m_ScriptEngine.Log.Debug("[" + ScriptEngineName + "]: " +
|
||||||
|
// "Executing event:\r\n"
|
||||||
|
// + "QIS.localID: " + QIS.localID
|
||||||
|
// + ", QIS.itemID: " + QIS.itemID
|
||||||
|
// + ", QIS.functionName: " +
|
||||||
|
// QIS.functionName);
|
||||||
|
#endif
|
||||||
|
LastExecutionStarted = DateTime.Now.Ticks;
|
||||||
|
KillCurrentScript = false;
|
||||||
|
InExecution = true;
|
||||||
|
m_ScriptEngine.m_ScriptManager.ExecuteEvent(QIS.localID,
|
||||||
|
QIS.itemID,
|
||||||
|
QIS.functionName,
|
||||||
|
QIS.llDetectParams,
|
||||||
|
QIS.param);
|
||||||
|
InExecution = false;
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
InExecution = false;
|
||||||
|
// DISPLAY ERROR INWORLD
|
||||||
|
string text = "Error executing script function \"" + QIS.functionName +
|
||||||
|
"\":\r\n";
|
||||||
|
if (e.InnerException != null)
|
||||||
|
{
|
||||||
|
// Send inner exception
|
||||||
|
text += e.InnerException.Message.ToString();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
text += "\r\n";
|
||||||
|
// Send normal
|
||||||
|
text += e.Message.ToString();
|
||||||
|
}
|
||||||
|
if (KillCurrentScript)
|
||||||
|
text += "\r\nScript will be deactivated!";
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (text.Length > 1500)
|
||||||
|
text = text.Substring(0, 1500);
|
||||||
|
IScriptHost m_host =
|
||||||
|
m_ScriptEngine.World.GetSceneObjectPart(QIS.localID);
|
||||||
|
//if (m_host != null)
|
||||||
|
//{
|
||||||
|
m_ScriptEngine.World.SimChat(Helpers.StringToField(text),
|
||||||
|
ChatTypeEnum.Say, 0,
|
||||||
|
m_host.AbsolutePosition,
|
||||||
|
m_host.Name, m_host.UUID);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
//}
|
||||||
|
//else
|
||||||
|
//{
|
||||||
|
// T oconsole
|
||||||
|
m_ScriptEngine.m_EventQueueManager.m_ScriptEngine.Log.Error("[" + ScriptEngineName + "]: " +
|
||||||
|
"Unable to send text in-world:\r\n" +
|
||||||
|
text);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
// So we are done sending message in-world
|
||||||
|
if (KillCurrentScript)
|
||||||
|
{
|
||||||
|
m_ScriptEngine.m_EventQueueManager.m_ScriptEngine.m_ScriptManager.StopScript(
|
||||||
|
QIS.localID, QIS.itemID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
InExecution = false;
|
||||||
|
m_ScriptEngine.m_EventQueueManager.ReleaseLock(QIS.localID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
private bool _PleaseShutdown = false;
|
|
||||||
|
///// <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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -156,12 +156,11 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
|
||||||
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 != null &&
|
if (EventQueueManager.EnforceMaxExecutionTime)
|
||||||
m_ScriptEngine.m_EventQueueManager.EnforceMaxExecutionTime)
|
|
||||||
{
|
{
|
||||||
// We are enforcing execution time
|
// We are enforcing execution time
|
||||||
if (DateTime.Now.Ticks - Last_maxFunctionExecutionTimens >
|
if (DateTime.Now.Ticks - Last_maxFunctionExecutionTimens >
|
||||||
m_ScriptEngine.m_EventQueueManager.maxFunctionExecutionTimens)
|
EventQueueManager.maxFunctionExecutionTimens)
|
||||||
{
|
{
|
||||||
// Its time to check again
|
// Its time to check again
|
||||||
m_ScriptEngine.m_EventQueueManager.CheckScriptMaxExecTime(); // Do check
|
m_ScriptEngine.m_EventQueueManager.CheckScriptMaxExecTime(); // Do check
|
||||||
|
|
Loading…
Reference in New Issue