From afea5f22055fd645e95c4e1dcad01e68716fa049 Mon Sep 17 00:00:00 2001 From: Sean Dague Date: Thu, 13 Sep 2007 11:41:42 +0000 Subject: remove ^M, as native storage should be UNIX format, and ^M in/out mashing will happen on the windows side now that eol-style is correct --- .../ScriptEngine/DotNetEngine/EventQueueManager.cs | 642 ++++++++++----------- 1 file changed, 321 insertions(+), 321 deletions(-) (limited to 'OpenSim/Region/ScriptEngine/DotNetEngine/EventQueueManager.cs') diff --git a/OpenSim/Region/ScriptEngine/DotNetEngine/EventQueueManager.cs b/OpenSim/Region/ScriptEngine/DotNetEngine/EventQueueManager.cs index 3dc5d77..955e978 100644 --- a/OpenSim/Region/ScriptEngine/DotNetEngine/EventQueueManager.cs +++ b/OpenSim/Region/ScriptEngine/DotNetEngine/EventQueueManager.cs @@ -1,321 +1,321 @@ -/* -* Copyright (c) Contributors, http://opensimulator.org/ -* See CONTRIBUTORS.TXT for a full list of copyright holders. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are met: -* * Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* * Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* * Neither the name of the OpenSim Project nor the -* names of its contributors may be used to endorse or promote products -* derived from this software without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS AND ANY -* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY -* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* -*/ -/* Original code: Tedd Hansen */ -using System; -using System.Collections.Generic; -using System.Text; -using System.Threading; -using System.Reflection; -using OpenSim.Region.Environment.Scenes.Scripting; -using libsecondlife; -using OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.LSL; - -namespace OpenSim.Region.ScriptEngine.DotNetEngine -{ - /// - /// EventQueueManager handles event queues - /// Events are queued and executed in separate thread - /// - [Serializable] - class EventQueueManager - { - /// - /// List of threads processing event queue - /// - private List eventQueueThreads = new List(); - private object queueLock = new object(); // Mutex lock object - /// - /// How many ms to sleep if queue is empty - /// - private int nothingToDoSleepms = 50; - /// - /// How many threads to process queue with - /// - private int numberOfThreads = 2; - /// - /// Queue containing events waiting to be executed - /// - private Queue eventQueue = new Queue(); - /// - /// Queue item structure - /// - private struct QueueItemStruct - { - public uint localID; - public LLUUID itemID; - public string functionName; - public object[] param; - } - - /// - /// List of localID locks for mutex processing of script events - /// - private List objectLocks = new List(); - private object tryLockLock = new object(); // Mutex lock object - - private ScriptEngine m_ScriptEngine; - public EventQueueManager(ScriptEngine _ScriptEngine) - { - m_ScriptEngine = _ScriptEngine; - - // - // Start event queue processing threads (worker threads) - // - for (int ThreadCount = 0; ThreadCount <= numberOfThreads; ThreadCount++) - { - Thread EventQueueThread = new Thread(EventQueueThreadLoop); - eventQueueThreads.Add(EventQueueThread); - EventQueueThread.IsBackground = true; - EventQueueThread.Priority = ThreadPriority.BelowNormal; - EventQueueThread.Name = "EventQueueManagerThread_" + ThreadCount; - EventQueueThread.Start(); - } - } - ~EventQueueManager() - { - - // Kill worker threads - foreach (Thread EventQueueThread in new System.Collections.ArrayList(eventQueueThreads)) - { - if (EventQueueThread != null && EventQueueThread.IsAlive == true) - { - try - { - EventQueueThread.Abort(); - EventQueueThread.Join(); - } - catch (Exception) - { - //myScriptEngine.Log.Verbose("ScriptEngine", "EventQueueManager Exception killing worker thread: " + e.ToString()); - } - } - } - eventQueueThreads.Clear(); - // Todo: Clean up our queues - eventQueue.Clear(); - - } - - /// - /// Queue processing thread loop - /// - private void EventQueueThreadLoop() - { - //myScriptEngine.m_logger.Verbose("ScriptEngine", "EventQueueManager Worker thread spawned"); - try - { - QueueItemStruct BlankQIS = new QueueItemStruct(); - while (true) - { - try - { - QueueItemStruct QIS = BlankQIS; - bool GotItem = false; - - if (eventQueue.Count == 0) - { - // Nothing to do? Sleep a bit waiting for something to do - Thread.Sleep(nothingToDoSleepms); - } - else - { - // Something in queue, process - //myScriptEngine.m_logger.Verbose("ScriptEngine", "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 (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.localID) == 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 - try - { - m_ScriptEngine.m_ScriptManager.ExecuteEvent(QIS.localID, QIS.itemID, QIS.functionName, QIS.param); - } - catch (Exception e) - { - // 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 - { // Send normal - text += e.Message.ToString(); - } - 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), 1, m_host.AbsolutePosition, m_host.Name, m_host.UUID); - } catch { - //} - //else - //{ - // T oconsole - Console.WriteLine("Unable to send text in-world:\r\n" + text); - } - - } - finally - { - ReleaseLock(QIS.localID); - } - } - - } // Something in queue - } catch (ThreadAbortException tae) { - throw tae; - } catch (Exception e) { - Console.WriteLine("Exception in EventQueueThreadLoop: " + e.ToString()); - } - } // while - } // try - catch (ThreadAbortException) - { - //myScriptEngine.Log.Verbose("ScriptEngine", "EventQueueManager Worker thread killed: " + tae.Message); - } - } - - /// - /// Try to get a mutex lock on localID - /// - /// - /// - private bool TryLock(uint localID) - { - lock (tryLockLock) - { - if (objectLocks.Contains(localID) == true) - { - return false; - } - else - { - objectLocks.Add(localID); - return true; - } - } - } - - /// - /// Release mutex lock on localID - /// - /// - private void ReleaseLock(uint localID) - { - lock (tryLockLock) - { - if (objectLocks.Contains(localID) == true) - { - objectLocks.Remove(localID); - } - } - } - - - /// - /// Add event to event execution queue - /// - /// - /// Name of the function, will be state + "_event_" + FunctionName - /// Array of parameters to match event mask - public void AddToObjectQueue(uint localID, string FunctionName, object[] param) - { - // Determine all scripts in Object and add to their queue - //myScriptEngine.m_logger.Verbose("ScriptEngine", "EventQueueManager Adding localID: " + localID + ", FunctionName: " + FunctionName); - - - // Do we have any scripts in this object at all? If not, return - if (m_ScriptEngine.m_ScriptManager.Scripts.ContainsKey(localID) == false) - { - //Console.WriteLine("Event \"" + FunctionName + "\" for localID: " + localID + ". No scripts found on this localID."); - return; - } - - Dictionary.KeyCollection scriptKeys = m_ScriptEngine.m_ScriptManager.GetScriptKeys(localID); - - foreach ( LLUUID itemID in scriptKeys ) - { - // Add to each script in that object - // TODO: Some scripts may not subscribe to this event. Should we NOT add it? Does it matter? - AddToScriptQueue(localID, itemID, FunctionName, param); - } - - } - - /// - /// Add event to event execution queue - /// - /// - /// - /// Name of the function, will be state + "_event_" + FunctionName - /// Array of parameters to match event mask - public void AddToScriptQueue(uint localID, LLUUID itemID, string FunctionName, object[] param) - { - lock (queueLock) - { - // Create a structure and add data - QueueItemStruct QIS = new QueueItemStruct(); - QIS.localID = localID; - QIS.itemID = itemID; - QIS.functionName = FunctionName; - QIS.param = param; - - // Add it to queue - eventQueue.Enqueue(QIS); - } - } - - } -} +/* +* Copyright (c) Contributors, http://opensimulator.org/ +* See CONTRIBUTORS.TXT for a full list of copyright holders. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* * Neither the name of the OpenSim Project nor the +* names of its contributors may be used to endorse or promote products +* derived from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS AND ANY +* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY +* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +*/ +/* Original code: Tedd Hansen */ +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading; +using System.Reflection; +using OpenSim.Region.Environment.Scenes.Scripting; +using libsecondlife; +using OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.LSL; + +namespace OpenSim.Region.ScriptEngine.DotNetEngine +{ + /// + /// EventQueueManager handles event queues + /// Events are queued and executed in separate thread + /// + [Serializable] + class EventQueueManager + { + /// + /// List of threads processing event queue + /// + private List eventQueueThreads = new List(); + private object queueLock = new object(); // Mutex lock object + /// + /// How many ms to sleep if queue is empty + /// + private int nothingToDoSleepms = 50; + /// + /// How many threads to process queue with + /// + private int numberOfThreads = 2; + /// + /// Queue containing events waiting to be executed + /// + private Queue eventQueue = new Queue(); + /// + /// Queue item structure + /// + private struct QueueItemStruct + { + public uint localID; + public LLUUID itemID; + public string functionName; + public object[] param; + } + + /// + /// List of localID locks for mutex processing of script events + /// + private List objectLocks = new List(); + private object tryLockLock = new object(); // Mutex lock object + + private ScriptEngine m_ScriptEngine; + public EventQueueManager(ScriptEngine _ScriptEngine) + { + m_ScriptEngine = _ScriptEngine; + + // + // Start event queue processing threads (worker threads) + // + for (int ThreadCount = 0; ThreadCount <= numberOfThreads; ThreadCount++) + { + Thread EventQueueThread = new Thread(EventQueueThreadLoop); + eventQueueThreads.Add(EventQueueThread); + EventQueueThread.IsBackground = true; + EventQueueThread.Priority = ThreadPriority.BelowNormal; + EventQueueThread.Name = "EventQueueManagerThread_" + ThreadCount; + EventQueueThread.Start(); + } + } + ~EventQueueManager() + { + + // Kill worker threads + foreach (Thread EventQueueThread in new System.Collections.ArrayList(eventQueueThreads)) + { + if (EventQueueThread != null && EventQueueThread.IsAlive == true) + { + try + { + EventQueueThread.Abort(); + EventQueueThread.Join(); + } + catch (Exception) + { + //myScriptEngine.Log.Verbose("ScriptEngine", "EventQueueManager Exception killing worker thread: " + e.ToString()); + } + } + } + eventQueueThreads.Clear(); + // Todo: Clean up our queues + eventQueue.Clear(); + + } + + /// + /// Queue processing thread loop + /// + private void EventQueueThreadLoop() + { + //myScriptEngine.m_logger.Verbose("ScriptEngine", "EventQueueManager Worker thread spawned"); + try + { + QueueItemStruct BlankQIS = new QueueItemStruct(); + while (true) + { + try + { + QueueItemStruct QIS = BlankQIS; + bool GotItem = false; + + if (eventQueue.Count == 0) + { + // Nothing to do? Sleep a bit waiting for something to do + Thread.Sleep(nothingToDoSleepms); + } + else + { + // Something in queue, process + //myScriptEngine.m_logger.Verbose("ScriptEngine", "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 (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.localID) == 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 + try + { + m_ScriptEngine.m_ScriptManager.ExecuteEvent(QIS.localID, QIS.itemID, QIS.functionName, QIS.param); + } + catch (Exception e) + { + // 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 + { // Send normal + text += e.Message.ToString(); + } + 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), 1, m_host.AbsolutePosition, m_host.Name, m_host.UUID); + } catch { + //} + //else + //{ + // T oconsole + Console.WriteLine("Unable to send text in-world:\r\n" + text); + } + + } + finally + { + ReleaseLock(QIS.localID); + } + } + + } // Something in queue + } catch (ThreadAbortException tae) { + throw tae; + } catch (Exception e) { + Console.WriteLine("Exception in EventQueueThreadLoop: " + e.ToString()); + } + } // while + } // try + catch (ThreadAbortException) + { + //myScriptEngine.Log.Verbose("ScriptEngine", "EventQueueManager Worker thread killed: " + tae.Message); + } + } + + /// + /// Try to get a mutex lock on localID + /// + /// + /// + private bool TryLock(uint localID) + { + lock (tryLockLock) + { + if (objectLocks.Contains(localID) == true) + { + return false; + } + else + { + objectLocks.Add(localID); + return true; + } + } + } + + /// + /// Release mutex lock on localID + /// + /// + private void ReleaseLock(uint localID) + { + lock (tryLockLock) + { + if (objectLocks.Contains(localID) == true) + { + objectLocks.Remove(localID); + } + } + } + + + /// + /// Add event to event execution queue + /// + /// + /// Name of the function, will be state + "_event_" + FunctionName + /// Array of parameters to match event mask + public void AddToObjectQueue(uint localID, string FunctionName, object[] param) + { + // Determine all scripts in Object and add to their queue + //myScriptEngine.m_logger.Verbose("ScriptEngine", "EventQueueManager Adding localID: " + localID + ", FunctionName: " + FunctionName); + + + // Do we have any scripts in this object at all? If not, return + if (m_ScriptEngine.m_ScriptManager.Scripts.ContainsKey(localID) == false) + { + //Console.WriteLine("Event \"" + FunctionName + "\" for localID: " + localID + ". No scripts found on this localID."); + return; + } + + Dictionary.KeyCollection scriptKeys = m_ScriptEngine.m_ScriptManager.GetScriptKeys(localID); + + foreach ( LLUUID itemID in scriptKeys ) + { + // Add to each script in that object + // TODO: Some scripts may not subscribe to this event. Should we NOT add it? Does it matter? + AddToScriptQueue(localID, itemID, FunctionName, param); + } + + } + + /// + /// Add event to event execution queue + /// + /// + /// + /// Name of the function, will be state + "_event_" + FunctionName + /// Array of parameters to match event mask + public void AddToScriptQueue(uint localID, LLUUID itemID, string FunctionName, object[] param) + { + lock (queueLock) + { + // Create a structure and add data + QueueItemStruct QIS = new QueueItemStruct(); + QIS.localID = localID; + QIS.itemID = itemID; + QIS.functionName = FunctionName; + QIS.param = param; + + // Add it to queue + eventQueue.Enqueue(QIS); + } + } + + } +} -- cgit v1.1