Sped up EventQueueManager response time (scripts now respond quickly). Added support for multiple threads executing events on objects, but only one thread on one script at the time (to utilize MultiCore/hyperthreading CPU's).

afrisby
Tedd Hansen 2007-08-19 11:09:54 +00:00
parent e70cdbc5ac
commit 7770c65a7e
1 changed files with 115 additions and 37 deletions

View File

@ -42,8 +42,10 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine
[Serializable] [Serializable]
class EventQueueManager class EventQueueManager
{ {
private Thread EventQueueThread; private List<Thread> EventQueueThreads = new List<Thread>();
private int NothingToDoSleepms = 200; private object QueueLock = new object();
private int NothingToDoSleepms = 50;
private int NumberOfThreads = 2;
private Queue<QueueItemStruct> EventQueue = new Queue<QueueItemStruct>(); private Queue<QueueItemStruct> EventQueue = new Queue<QueueItemStruct>();
private struct QueueItemStruct private struct QueueItemStruct
{ {
@ -59,14 +61,22 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine
myScriptEngine = _ScriptEngine; myScriptEngine = _ScriptEngine;
//myScriptEngine.m_logger.Verbose("ScriptEngine", "EventQueueManager Start"); //myScriptEngine.m_logger.Verbose("ScriptEngine", "EventQueueManager Start");
// Start worker thread // Start worker thread
EventQueueThread = new Thread(EventQueueThreadLoop);
for (int ThreadCount = 0; ThreadCount <= NumberOfThreads; ThreadCount++)
{
Thread EventQueueThread = new Thread(EventQueueThreadLoop);
EventQueueThreads.Add(EventQueueThread);
EventQueueThread.IsBackground = true; EventQueueThread.IsBackground = true;
EventQueueThread.Name = "EventQueueManagerThread"; EventQueueThread.Name = "EventQueueManagerThread_" + ThreadCount;
EventQueueThread.Start(); EventQueueThread.Start();
} }
}
~EventQueueManager() ~EventQueueManager()
{ {
// Kill worker thread
// Kill worker threads
foreach (Thread EventQueueThread in new System.Collections.ArrayList(EventQueueThreads))
{
if (EventQueueThread != null && EventQueueThread.IsAlive == true) if (EventQueueThread != null && EventQueueThread.IsAlive == true)
{ {
try try
@ -79,6 +89,8 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine
myScriptEngine.Log.Verbose("ScriptEngine", "EventQueueManager Exception killing worker thread: " + e.ToString()); myScriptEngine.Log.Verbose("ScriptEngine", "EventQueueManager Exception killing worker thread: " + e.ToString());
} }
} }
}
EventQueueThreads.Clear();
// Todo: Clean up our queues // Todo: Clean up our queues
} }
@ -88,8 +100,12 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine
//myScriptEngine.m_logger.Verbose("ScriptEngine", "EventQueueManager Worker thread spawned"); //myScriptEngine.m_logger.Verbose("ScriptEngine", "EventQueueManager Worker thread spawned");
try try
{ {
QueueItemStruct BlankQIS = new QueueItemStruct();
while (true) while (true)
{ {
QueueItemStruct QIS = BlankQIS;
bool GotItem = false;
if (EventQueue.Count == 0) if (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
@ -98,24 +114,85 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine
else else
{ {
// Something in queue, process // Something in queue, process
QueueItemStruct QIS = EventQueue.Dequeue();
//myScriptEngine.m_logger.Verbose("ScriptEngine", "Processing event for ObjectID: " + QIS.ObjectID + ", ScriptID: " + QIS.ScriptID + ", FunctionName: " + QIS.FunctionName); //myScriptEngine.m_logger.Verbose("ScriptEngine", "Processing event for ObjectID: " + QIS.ObjectID + ", ScriptID: " + QIS.ScriptID + ", FunctionName: " + QIS.FunctionName);
// TODO: Execute function
// OBJECT BASED LOCK - TWO THREADS WORKING ON SAME OBJECT IS NOT GOOD
lock (QueueLock)
{
GotItem = false;
for (int qc = 0; qc < EventQueue.Count; qc++)
{
// Get queue item
QIS = EventQueue.Dequeue();
// Check if object is being processed by someone else
if (TryLock(QIS.ObjectID) == false)
{
// Object is already being processed, requeue it
EventQueue.Enqueue(QIS);
}
else
{
// We have lock on an object and can process it
GotItem = true;
break;
}
} // go through queue
} // lock
if (GotItem == true)
{
// Execute function
myScriptEngine.myScriptManager.ExecuteEvent(QIS.ObjectID, QIS.ScriptID, QIS.FunctionName, QIS.param); myScriptEngine.myScriptManager.ExecuteEvent(QIS.ObjectID, QIS.ScriptID, QIS.FunctionName, QIS.param);
ReleaseLock(QIS.ObjectID);
} }
}
} } // Something in queue
} // while
} // try
catch (ThreadAbortException tae) catch (ThreadAbortException tae)
{ {
myScriptEngine.Log.Verbose("ScriptEngine", "EventQueueManager Worker thread killed: " + tae.Message); myScriptEngine.Log.Verbose("ScriptEngine", "EventQueueManager Worker thread killed: " + tae.Message);
} }
} }
private List<IScriptHost> ObjectLocks = new List<IScriptHost>();
private object TryLockLock = new object();
private bool TryLock(IScriptHost ObjectID)
{
lock (TryLockLock)
{
if (ObjectLocks.Contains(ObjectID) == true)
{
return false;
}
else
{
ObjectLocks.Add(ObjectID);
return true;
}
}
}
private void ReleaseLock(IScriptHost ObjectID)
{
lock (TryLockLock)
{
if (ObjectLocks.Contains(ObjectID) == true)
{
ObjectLocks.Remove(ObjectID);
}
}
}
public void AddToObjectQueue(IScriptHost ObjectID, string FunctionName, object[] param) public void AddToObjectQueue(IScriptHost ObjectID, string FunctionName, 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 ObjectID: " + ObjectID + ", FunctionName: " + FunctionName); //myScriptEngine.m_logger.Verbose("ScriptEngine", "EventQueueManager Adding ObjectID: " + ObjectID + ", FunctionName: " + FunctionName);
lock (QueueLock)
{
foreach (string ScriptID in myScriptEngine.myScriptManager.GetScriptKeys(ObjectID)) foreach (string ScriptID in myScriptEngine.myScriptManager.GetScriptKeys(ObjectID))
{ {
// Add to each script in that object // Add to each script in that object
@ -137,6 +214,7 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine
//{ //{
// // Add to script queue // // Add to script queue
//} //}
}
} }
} }