aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorTedd Hansen2008-02-22 14:09:38 +0000
committerTedd Hansen2008-02-22 14:09:38 +0000
commita43bb10000ca0b58af2f33750ea17cb94bfbad7d (patch)
tree9f913c185d3ee90a3e88507bbd32e7c6bbab0c9d
parentMaintenance thread in charge of loading/unloading of scripts. 1 thread less p... (diff)
downloadopensim-SC-a43bb10000ca0b58af2f33750ea17cb94bfbad7d.zip
opensim-SC-a43bb10000ca0b58af2f33750ea17cb94bfbad7d.tar.gz
opensim-SC-a43bb10000ca0b58af2f33750ea17cb94bfbad7d.tar.bz2
opensim-SC-a43bb10000ca0b58af2f33750ea17cb94bfbad7d.tar.xz
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.
Diffstat (limited to '')
-rw-r--r--OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/EventQueueManager.cs64
-rw-r--r--OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/EventQueueThreadClass.cs402
-rw-r--r--OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/MaintenanceThread.cs5
3 files changed, 229 insertions, 242 deletions
diff --git a/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/EventQueueManager.cs b/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/EventQueueManager.cs
index e3d448c..581c7a0 100644
--- a/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/EventQueueManager.cs
+++ b/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/EventQueueManager.cs
@@ -45,7 +45,7 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
45 public class EventQueueManager : iScriptEngineFunctionModule 45 public class EventQueueManager : iScriptEngineFunctionModule
46 { 46 {
47 // 47 //
48 // Class is instanced in "ScriptEngine" and used by "EventManager" also instanced in "ScriptEngine". 48 // Class is instanced in "ScriptEngine" and used by "EventManager" which is also instanced in "ScriptEngine".
49 // 49 //
50 // Class purpose is to queue and execute functions that are received by "EventManager": 50 // Class purpose is to queue and execute functions that are received by "EventManager":
51 // - allowing "EventManager" to release its event thread immediately, thus not interrupting server execution. 51 // - allowing "EventManager" to release its event thread immediately, thus not interrupting server execution.
@@ -68,25 +68,25 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
68 /// List of threads (classes) processing event queue 68 /// List of threads (classes) processing event queue
69 /// Note that this may or may not be a reference to a static object depending on PrivateRegionThreads config setting. 69 /// Note that this may or may not be a reference to a static object depending on PrivateRegionThreads config setting.
70 /// </summary> 70 /// </summary>
71 internal List<EventQueueThreadClass> eventQueueThreads; // Thread pool that we work on 71 internal static List<EventQueueThreadClass> eventQueueThreads; // Thread pool that we work on
72 /// <summary> 72 /// <summary>
73 /// Locking access to eventQueueThreads AND staticGlobalEventQueueThreads. 73 /// Locking access to eventQueueThreads AND staticGlobalEventQueueThreads.
74 /// </summary> 74 /// </summary>
75// private object eventQueueThreadsLock = new object(); 75// private object eventQueueThreadsLock = new object();
76 // Static objects for referencing the objects above if we don't have private threads: 76 // Static objects for referencing the objects above if we don't have private threads:
77 internal static List<EventQueueThreadClass> staticEventQueueThreads; // A static reference used if we don't use private threads 77 //internal static List<EventQueueThreadClass> staticEventQueueThreads; // A static reference used if we don't use private threads
78// internal static object staticEventQueueThreadsLock; // Statick lock object reference for same reason 78// internal static object staticEventQueueThreadsLock; // Statick lock object reference for same reason
79 79
80 /// <summary> 80 /// <summary>
81 /// Global static list of all threads (classes) processing event queue -- used by max enforcment thread 81 /// Global static list of all threads (classes) processing event queue -- used by max enforcment thread
82 /// </summary> 82 /// </summary>
83 private List<EventQueueThreadClass> staticGlobalEventQueueThreads = new List<EventQueueThreadClass>(); 83 //private List<EventQueueThreadClass> staticGlobalEventQueueThreads = new List<EventQueueThreadClass>();
84 84
85 /// <summary> 85 /// <summary>
86 /// Used internally to specify how many threads should exit gracefully 86 /// Used internally to specify how many threads should exit gracefully
87 /// </summary> 87 /// </summary>
88 public int ThreadsToExit; 88 public static int ThreadsToExit;
89 public object ThreadsToExitLock = new object(); 89 public static object ThreadsToExitLock = new object();
90 90
91 91
92 //public object queueLock = new object(); // Mutex lock object 92 //public object queueLock = new object(); // Mutex lock object
@@ -94,14 +94,14 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
94 /// <summary> 94 /// <summary>
95 /// How many threads to process queue with 95 /// How many threads to process queue with
96 /// </summary> 96 /// </summary>
97 internal int numberOfThreads; 97 internal static int numberOfThreads;
98 98
99 internal static int EventExecutionMaxQueueSize; 99 internal static int EventExecutionMaxQueueSize;
100 100
101 /// <summary> 101 /// <summary>
102 /// Maximum time one function can use for execution before we perform a thread kill. 102 /// Maximum time one function can use for execution before we perform a thread kill.
103 /// </summary> 103 /// </summary>
104 private int maxFunctionExecutionTimems 104 private static int maxFunctionExecutionTimems
105 { 105 {
106 get { return (int)(maxFunctionExecutionTimens / 10000); } 106 get { return (int)(maxFunctionExecutionTimens / 10000); }
107 set { maxFunctionExecutionTimens = value * 10000; } 107 set { maxFunctionExecutionTimens = value * 10000; }
@@ -111,15 +111,15 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
111 /// Contains nanoseconds version of maxFunctionExecutionTimems so that it matches time calculations better (performance reasons). 111 /// Contains nanoseconds version of maxFunctionExecutionTimems so that it matches time calculations better (performance reasons).
112 /// WARNING! ONLY UPDATE maxFunctionExecutionTimems, NEVER THIS DIRECTLY. 112 /// WARNING! ONLY UPDATE maxFunctionExecutionTimems, NEVER THIS DIRECTLY.
113 /// </summary> 113 /// </summary>
114 public long maxFunctionExecutionTimens; 114 public static long maxFunctionExecutionTimens;
115 /// <summary> 115 /// <summary>
116 /// Enforce max execution time 116 /// Enforce max execution time
117 /// </summary> 117 /// </summary>
118 public bool EnforceMaxExecutionTime; 118 public static bool EnforceMaxExecutionTime;
119 /// <summary> 119 /// <summary>
120 /// Kill script (unload) when it exceeds execution time 120 /// Kill script (unload) when it exceeds execution time
121 /// </summary> 121 /// </summary>
122 private bool KillScriptOnMaxFunctionExecutionTime; 122 private static bool KillScriptOnMaxFunctionExecutionTime;
123 123
124 /// <summary> 124 /// <summary>
125 /// List of localID locks for mutex processing of script events 125 /// List of localID locks for mutex processing of script events
@@ -172,33 +172,8 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
172 { 172 {
173 m_ScriptEngine = _ScriptEngine; 173 m_ScriptEngine = _ScriptEngine;
174 174
175 // TODO: We need to move from single EventQueueManager to list of it in to share threads 175 eventQueueThreads = new List<EventQueueThreadClass>();
176 bool PrivateRegionThreads = true; // m_ScriptEngine.ScriptConfigSource.GetBoolean("PrivateRegionThreads", false);
177
178 // Create thread pool list and lock object
179 // Determine from config if threads should be dedicated to regions or shared
180 if (PrivateRegionThreads)
181 {
182 // PRIVATE THREAD POOL PER REGION
183 eventQueueThreads = new List<EventQueueThreadClass>();
184 // eventQueueThreadsLock = new object();
185 }
186 else
187 {
188 // SHARED THREAD POOL
189 // Crate the static objects
190 if (staticEventQueueThreads == null)
191 staticEventQueueThreads = new List<EventQueueThreadClass>();
192 // if (staticEventQueueThreadsLock == null)
193 // staticEventQueueThreadsLock = new object();
194
195 // Now reference our locals to them
196 eventQueueThreads = staticEventQueueThreads;
197 //eventQueueThreadsLock = staticEventQueueThreadsLock;
198 }
199
200 ReadConfig(); 176 ReadConfig();
201
202 } 177 }
203 178
204 public void ReadConfig() 179 public void ReadConfig()
@@ -230,18 +205,18 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
230 205
231 private void Stop() 206 private void Stop()
232 { 207 {
233 if (eventQueueThreads != null && eventQueueThreads != null) 208 if (eventQueueThreads != null)
234 { 209 {
235 // Kill worker threads 210 // Kill worker threads
236 //lock (eventQueueThreads) 211 lock (eventQueueThreads)
237 //{ 212 {
238 foreach (EventQueueThreadClass EventQueueThread in new ArrayList(eventQueueThreads)) 213 foreach (EventQueueThreadClass EventQueueThread in new ArrayList(eventQueueThreads))
239 { 214 {
240 AbortThreadClass(EventQueueThread); 215 AbortThreadClass(EventQueueThread);
241 } 216 }
242 //eventQueueThreads.Clear(); 217 //eventQueueThreads.Clear();
243 //staticGlobalEventQueueThreads.Clear(); 218 //staticGlobalEventQueueThreads.Clear();
244 //} 219 }
245 } 220 }
246 221
247 // Remove all entries from our event queue 222 // Remove all entries from our event queue
@@ -256,9 +231,8 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
256 #region " Start / stop script execution threads (ThreadClasses) " 231 #region " Start / stop script execution threads (ThreadClasses) "
257 private void StartNewThreadClass() 232 private void StartNewThreadClass()
258 { 233 {
259 EventQueueThreadClass eqtc = new EventQueueThreadClass(this); 234 EventQueueThreadClass eqtc = new EventQueueThreadClass();
260 eventQueueThreads.Add(eqtc); 235 eventQueueThreads.Add(eqtc);
261 staticGlobalEventQueueThreads.Add(eqtc);
262 m_ScriptEngine.Log.Debug("[" + m_ScriptEngine.ScriptEngineName + "]: Started new script execution thread. Current thread count: " + eventQueueThreads.Count); 236 m_ScriptEngine.Log.Debug("[" + m_ScriptEngine.ScriptEngineName + "]: Started new script execution thread. Current thread count: " + eventQueueThreads.Count);
263 } 237 }
264 238
@@ -266,8 +240,6 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
266 { 240 {
267 if (eventQueueThreads.Contains(threadClass)) 241 if (eventQueueThreads.Contains(threadClass))
268 eventQueueThreads.Remove(threadClass); 242 eventQueueThreads.Remove(threadClass);
269 if (staticGlobalEventQueueThreads.Contains(threadClass))
270 staticGlobalEventQueueThreads.Remove(threadClass);
271 243
272 try 244 try
273 { 245 {
@@ -426,7 +398,7 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
426 // Iterate through all ScriptThreadClasses and check how long their current function has been executing 398 // Iterate through all ScriptThreadClasses and check how long their current function has been executing
427 lock (eventQueueThreads) 399 lock (eventQueueThreads)
428 { 400 {
429 foreach (EventQueueThreadClass EventQueueThread in staticGlobalEventQueueThreads) 401 foreach (EventQueueThreadClass EventQueueThread in eventQueueThreads)
430 { 402 {
431 // Is thread currently executing anything? 403 // Is thread currently executing anything?
432 if (EventQueueThread.InExecution) 404 if (EventQueueThread.InExecution)
diff --git a/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/EventQueueThreadClass.cs b/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/EventQueueThreadClass.cs
index 11fd896..f36baa7 100644
--- a/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/EventQueueThreadClass.cs
+++ b/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/EventQueueThreadClass.cs
@@ -40,27 +40,27 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
40 /// <summary> 40 /// <summary>
41 /// Because every thread needs some data set for it (time started to execute current function), it will do its work within a class 41 /// Because every thread needs some data set for it (time started to execute current function), it will do its work within a class
42 /// </summary> 42 /// </summary>
43 public class EventQueueThreadClass: iScriptEngineFunctionModule 43 public class EventQueueThreadClass : iScriptEngineFunctionModule
44 { 44 {
45 /// <summary> 45 /// <summary>
46 /// How many ms to sleep if queue is empty 46 /// How many ms to sleep if queue is empty
47 /// </summary> 47 /// </summary>
48 private int nothingToDoSleepms;// = 50; 48 private static int nothingToDoSleepms;// = 50;
49 private ThreadPriority MyThreadPriority; 49 private static ThreadPriority MyThreadPriority;
50 50
51 public long LastExecutionStarted; 51 public long LastExecutionStarted;
52 public bool InExecution = false; 52 public bool InExecution = false;
53 public bool KillCurrentScript = false; 53 public bool KillCurrentScript = false;
54 54
55 private EventQueueManager eventQueueManager; 55 //private EventQueueManager eventQueueManager;
56 public Thread EventQueueThread; 56 public Thread EventQueueThread;
57 private static int ThreadCount = 0; 57 private static int ThreadCount = 0;
58 58
59 private string ScriptEngineName = "ScriptEngine.Common"; 59 private string ScriptEngineName = "ScriptEngine.Common";
60 60
61 public EventQueueThreadClass(EventQueueManager eqm) 61 public EventQueueThreadClass()//EventQueueManager eqm
62 { 62 {
63 eventQueueManager = eqm; 63 //eventQueueManager = eqm;
64 ReadConfig(); 64 ReadConfig();
65 Start(); 65 Start();
66 } 66 }
@@ -72,32 +72,36 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
72 72
73 public void ReadConfig() 73 public void ReadConfig()
74 { 74 {
75 ScriptEngineName = eventQueueManager.m_ScriptEngine.ScriptEngineName; 75 foreach (ScriptEngine m_ScriptEngine in ScriptEngine.ScriptEngines)
76 nothingToDoSleepms = eventQueueManager.m_ScriptEngine.ScriptConfigSource.GetInt("SleepTimeIfNoScriptExecutionMs", 50);
77
78 // Later with ScriptServer we might want to ask OS for stuff too, so doing this a bit manually
79 string pri = eventQueueManager.m_ScriptEngine.ScriptConfigSource.GetString("ScriptThreadPriority", "BelowNormal");
80 switch (pri.ToLower())
81 { 76 {
82 case "lowest": 77 ScriptEngineName = m_ScriptEngine.ScriptEngineName;
83 MyThreadPriority = ThreadPriority.Lowest; 78 nothingToDoSleepms = m_ScriptEngine.ScriptConfigSource.GetInt("SleepTimeIfNoScriptExecutionMs", 50);
84 break; 79
85 case "belownormal": 80 // Later with ScriptServer we might want to ask OS for stuff too, so doing this a bit manually
86 MyThreadPriority = ThreadPriority.BelowNormal; 81 string pri = m_ScriptEngine.ScriptConfigSource.GetString("ScriptThreadPriority", "BelowNormal");
87 break; 82 switch (pri.ToLower())
88 case "normal": 83 {
89 MyThreadPriority = ThreadPriority.Normal; 84 case "lowest":
90 break; 85 MyThreadPriority = ThreadPriority.Lowest;
91 case "abovenormal": 86 break;
92 MyThreadPriority = ThreadPriority.AboveNormal; 87 case "belownormal":
93 break; 88 MyThreadPriority = ThreadPriority.BelowNormal;
94 case "highest": 89 break;
95 MyThreadPriority = ThreadPriority.Highest; 90 case "normal":
96 break; 91 MyThreadPriority = ThreadPriority.Normal;
97 default: 92 break;
98 MyThreadPriority = ThreadPriority.BelowNormal; // Default 93 case "abovenormal":
99 eventQueueManager.m_ScriptEngine.Log.Error("[ScriptEngineBase]: Unknown priority type \"" + pri + "\" in config file. Defaulting to \"BelowNormal\"."); 94 MyThreadPriority = ThreadPriority.AboveNormal;
100 break; 95 break;
96 case "highest":
97 MyThreadPriority = ThreadPriority.Highest;
98 break;
99 default:
100 MyThreadPriority = ThreadPriority.BelowNormal; // Default
101 m_ScriptEngine.Log.Error("[ScriptEngineBase]: Unknown priority type \"" + pri +
102 "\" in config file. Defaulting to \"BelowNormal\".");
103 break;
104 }
101 } 105 }
102 106
103 // Now set that priority 107 // Now set that priority
@@ -113,7 +117,7 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
113 { 117 {
114 EventQueueThread = new Thread(EventQueueThreadLoop); 118 EventQueueThread = new Thread(EventQueueThreadLoop);
115 EventQueueThread.IsBackground = true; 119 EventQueueThread.IsBackground = true;
116 120
117 EventQueueThread.Priority = MyThreadPriority; 121 EventQueueThread.Priority = MyThreadPriority;
118 EventQueueThread.Name = "EventQueueManagerThread_" + ThreadCount; 122 EventQueueThread.Name = "EventQueueManagerThread_" + ThreadCount;
119 EventQueueThread.Start(); 123 EventQueueThread.Start();
@@ -127,8 +131,8 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
127 131
128 public void Stop() 132 public void Stop()
129 { 133 {
130 PleaseShutdown = true; // Set shutdown flag 134 //PleaseShutdown = true; // Set shutdown flag
131 Thread.Sleep(100); // Wait a bit 135 //Thread.Sleep(100); // Wait a bit
132 if (EventQueueThread != null && EventQueueThread.IsAlive == true) 136 if (EventQueueThread != null && EventQueueThread.IsAlive == true)
133 { 137 {
134 try 138 try
@@ -143,6 +147,8 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
143 } 147 }
144 } 148 }
145 149
150 private EventQueueManager.QueueItemStruct BlankQIS = new EventQueueManager.QueueItemStruct();
151 private ScriptEngine lastScriptEngine;
146 /// <summary> 152 /// <summary>
147 /// Queue processing thread loop 153 /// Queue processing thread loop
148 /// </summary> 154 /// </summary>
@@ -151,188 +157,198 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
151 //myScriptEngine.Log.Info("[" + ScriptEngineName + "]: EventQueueManager Worker thread spawned"); 157 //myScriptEngine.Log.Info("[" + ScriptEngineName + "]: EventQueueManager Worker thread spawned");
152 try 158 try
153 { 159 {
154 while (true) 160 while (true)
155 { 161 {
156 try 162 try
157 { 163 {
158 EventQueueManager.QueueItemStruct BlankQIS = new EventQueueManager.QueueItemStruct();
159 while (true) 164 while (true)
160 { 165 {
161 // Every now and then check if we should shut down 166 DoProcessQueue();
162 if (PleaseShutdown || eventQueueManager.ThreadsToExit > 0) 167 }
163 { 168 }
164 // Someone should shut down, lets get exclusive lock 169 catch (ThreadAbortException tae)
165 lock (eventQueueManager.ThreadsToExitLock) 170 {
166 { 171 if (lastScriptEngine != null)
167 // Lets re-check in case someone grabbed it 172 lastScriptEngine.Log.Info("[" + ScriptEngineName + "]: ThreadAbortException while executing function.");
168 if (eventQueueManager.ThreadsToExit > 0) 173 }
169 { 174 catch (Exception e)
170 // Its crowded here so we'll shut down 175 {
171 eventQueueManager.ThreadsToExit--; 176 if (lastScriptEngine != null)
172 Stop(); 177 lastScriptEngine.Log.Error("[" + ScriptEngineName + "]: Exception in EventQueueThreadLoop: " + e.ToString());
173 return; 178 }
174 } 179 }
175 else 180 }
176 { 181 catch (ThreadAbortException)
177 // We have been asked to shut down 182 {
178 Stop(); 183 //myScriptEngine.Log.Info("[" + ScriptEngineName + "]: EventQueueManager Worker thread killed: " + tae.Message);
179 return; 184 }
180 } 185 }
181 } 186
182 } 187 public void DoProcessQueue()
188 {
189 foreach (ScriptEngine m_ScriptEngine in ScriptEngine.ScriptEngines)
190 {
191 lastScriptEngine = m_ScriptEngine;
192 // Every now and then check if we should shut down
193 //if (PleaseShutdown || EventQueueManager.ThreadsToExit > 0)
194 //{
195 // // Someone should shut down, lets get exclusive lock
196 // lock (EventQueueManager.ThreadsToExitLock)
197 // {
198 // // Lets re-check in case someone grabbed it
199 // if (EventQueueManager.ThreadsToExit > 0)
200 // {
201 // // Its crowded here so we'll shut down
202 // EventQueueManager.ThreadsToExit--;
203 // Stop();
204 // return;
205 // }
206 // else
207 // {
208 // // We have been asked to shut down
209 // Stop();
210 // return;
211 // }
212 // }
213 //}
214
215 //try
216 // {
217 EventQueueManager.QueueItemStruct QIS = BlankQIS;
218 bool GotItem = false;
183 219
184 //try 220 //if (PleaseShutdown)
185 // { 221 // return;
186 EventQueueManager.QueueItemStruct QIS = BlankQIS;
187 bool GotItem = false;
188 222
189 if (PleaseShutdown) 223 if (m_ScriptEngine.m_EventQueueManager.eventQueue.Count == 0)
190 return; 224 {
225 // Nothing to do? Sleep a bit waiting for something to do
226 Thread.Sleep(nothingToDoSleepms);
227 }
228 else
229 {
230 // Something in queue, process
231 //myScriptEngine.Log.Info("[" + ScriptEngineName + "]: Processing event for localID: " + QIS.localID + ", itemID: " + QIS.itemID + ", FunctionName: " + QIS.FunctionName);
191 232
192 if (eventQueueManager.eventQueue.Count == 0) 233 // OBJECT BASED LOCK - TWO THREADS WORKING ON SAME OBJECT IS NOT GOOD
234 lock (m_ScriptEngine.m_EventQueueManager.eventQueue)
235 {
236 GotItem = false;
237 for (int qc = 0; qc < m_ScriptEngine.m_EventQueueManager.eventQueue.Count; qc++)
238 {
239 // Get queue item
240 QIS = m_ScriptEngine.m_EventQueueManager.eventQueue.Dequeue();
241
242 // Check if object is being processed by someone else
243 if (m_ScriptEngine.m_EventQueueManager.TryLock(QIS.localID) == false)
193 { 244 {
194 // Nothing to do? Sleep a bit waiting for something to do 245 // Object is already being processed, requeue it
195 Thread.Sleep(nothingToDoSleepms); 246 m_ScriptEngine.m_EventQueueManager.eventQueue.Enqueue(QIS);
196 } 247 }
197 else 248 else
198 { 249 {
199 // Something in queue, process 250 // We have lock on an object and can process it
200 //myScriptEngine.Log.Info("[" + ScriptEngineName + "]: Processing event for localID: " + QIS.localID + ", itemID: " + QIS.itemID + ", FunctionName: " + QIS.FunctionName); 251 GotItem = true;
201 252 break;
202 // OBJECT BASED LOCK - TWO THREADS WORKING ON SAME OBJECT IS NOT GOOD 253 }
203 lock (eventQueueManager.eventQueue) 254 }
204 { 255 }
205 GotItem = false;
206 for (int qc = 0; qc < eventQueueManager.eventQueue.Count; qc++)
207 {
208 // Get queue item
209 QIS = eventQueueManager.eventQueue.Dequeue();
210
211 // Check if object is being processed by someone else
212 if (eventQueueManager.TryLock(QIS.localID) == false)
213 {
214 // Object is already being processed, requeue it
215 eventQueueManager.eventQueue.Enqueue(QIS);
216 }
217 else
218 {
219 // We have lock on an object and can process it
220 GotItem = true;
221 break;
222 }
223 }
224 }
225 256
226 if (GotItem == true) 257 if (GotItem == true)
227 { 258 {
228 // Execute function 259 // Execute function
229 try 260 try
230 { 261 {
231///cfk 2-7-08 dont need this right now and the default Linux build has DEBUG defined 262 ///cfk 2-7-08 dont need this right now and the default Linux build has DEBUG defined
232#if DEBUG 263#if DEBUG
233 //eventQueueManager.m_ScriptEngine.Log.Debug("[" + ScriptEngineName + "]: " + 264 //eventQueueManager.m_ScriptEngine.Log.Debug("[" + ScriptEngineName + "]: " +
234 // "Executing event:\r\n" 265 // "Executing event:\r\n"
235 // + "QIS.localID: " + QIS.localID 266 // + "QIS.localID: " + QIS.localID
236 // + ", QIS.itemID: " + QIS.itemID 267 // + ", QIS.itemID: " + QIS.itemID
237 // + ", QIS.functionName: " + 268 // + ", QIS.functionName: " +
238 // QIS.functionName); 269 // QIS.functionName);
239#endif 270#endif
240 LastExecutionStarted = DateTime.Now.Ticks; 271 LastExecutionStarted = DateTime.Now.Ticks;
241 KillCurrentScript = false; 272 KillCurrentScript = false;
242 InExecution = true; 273 InExecution = true;
243 eventQueueManager.m_ScriptEngine.m_ScriptManager.ExecuteEvent(QIS.localID, 274 m_ScriptEngine.m_ScriptManager.ExecuteEvent(QIS.localID,
244 QIS.itemID, 275 QIS.itemID,
245 QIS.functionName, 276 QIS.functionName,
246 QIS.llDetectParams, 277 QIS.llDetectParams,
247 QIS.param); 278 QIS.param);
248 InExecution = false; 279 InExecution = false;
249 } 280 }
250 catch (Exception e) 281 catch (Exception e)
251 { 282 {
252 InExecution = false; 283 InExecution = false;
253 // DISPLAY ERROR INWORLD 284 // DISPLAY ERROR INWORLD
254 string text = "Error executing script function \"" + QIS.functionName + 285 string text = "Error executing script function \"" + QIS.functionName +
255 "\":\r\n"; 286 "\":\r\n";
256 if (e.InnerException != null) 287 if (e.InnerException != null)
257 { 288 {
258 // Send inner exception 289 // Send inner exception
259 text += e.InnerException.Message.ToString(); 290 text += e.InnerException.Message.ToString();
260 } 291 }
261 else 292 else
262 { 293 {
263 text += "\r\n"; 294 text += "\r\n";
264 // Send normal 295 // Send normal
265 text += e.Message.ToString(); 296 text += e.Message.ToString();
266 } 297 }
267 if (KillCurrentScript) 298 if (KillCurrentScript)
268 text += "\r\nScript will be deactivated!"; 299 text += "\r\nScript will be deactivated!";
269 300
270 try 301 try
271 { 302 {
272 if (text.Length > 1500) 303 if (text.Length > 1500)
273 text = text.Substring(0, 1500); 304 text = text.Substring(0, 1500);
274 IScriptHost m_host = 305 IScriptHost m_host =
275 eventQueueManager.m_ScriptEngine.World.GetSceneObjectPart(QIS.localID); 306 m_ScriptEngine.World.GetSceneObjectPart(QIS.localID);
276 //if (m_host != null) 307 //if (m_host != null)
277 //{ 308 //{
278 eventQueueManager.m_ScriptEngine.World.SimChat(Helpers.StringToField(text), 309 m_ScriptEngine.World.SimChat(Helpers.StringToField(text),
279 ChatTypeEnum.Say, 0, 310 ChatTypeEnum.Say, 0,
280 m_host.AbsolutePosition, 311 m_host.AbsolutePosition,
281 m_host.Name, m_host.UUID); 312 m_host.Name, m_host.UUID);
282 } 313 }
283 catch 314 catch
284 { 315 {
285 //} 316 //}
286 //else 317 //else
287 //{ 318 //{
288 // T oconsole 319 // T oconsole
289 eventQueueManager.m_ScriptEngine.Log.Error("[" + ScriptEngineName + "]: " + 320 m_ScriptEngine.m_EventQueueManager.m_ScriptEngine.Log.Error("[" + ScriptEngineName + "]: " +
290 "Unable to send text in-world:\r\n" + 321 "Unable to send text in-world:\r\n" +
291 text); 322 text);
292 } 323 }
293 finally 324 finally
294 { 325 {
295 // So we are done sending message in-world 326 // So we are done sending message in-world
296 if (KillCurrentScript) 327 if (KillCurrentScript)
297 { 328 {
298 eventQueueManager.m_ScriptEngine.m_ScriptManager.StopScript( 329 m_ScriptEngine.m_EventQueueManager.m_ScriptEngine.m_ScriptManager.StopScript(
299 QIS.localID, QIS.itemID); 330 QIS.localID, QIS.itemID);
300 }
301 }
302 }
303 finally
304 {
305 InExecution = false;
306 eventQueueManager.ReleaseLock(QIS.localID);
307 }
308 } 331 }
309 } 332 }
310 } 333 }
311 } 334 finally
312 catch (ThreadAbortException tae) 335 {
313 { 336 InExecution = false;
314 eventQueueManager.m_ScriptEngine.Log.Info("[" + ScriptEngineName + "]: ThreadAbortException while executing function."); 337 m_ScriptEngine.m_EventQueueManager.ReleaseLock(QIS.localID);
315 } 338 }
316 catch (Exception e)
317 {
318 eventQueueManager.m_ScriptEngine.Log.Error("[" + ScriptEngineName + "]: Exception in EventQueueThreadLoop: " + e.ToString());
319 } 339 }
320 } 340 }
321 } 341 }
322 catch (ThreadAbortException)
323 {
324 //myScriptEngine.Log.Info("[" + ScriptEngineName + "]: EventQueueManager Worker thread killed: " + tae.Message);
325 }
326 } 342 }
327 343
328 /// <summary> 344 ///// <summary>
329 /// If set to true then threads and stuff should try to make a graceful exit 345 ///// If set to true then threads and stuff should try to make a graceful exit
330 /// </summary> 346 ///// </summary>
331 public bool PleaseShutdown 347 //public bool PleaseShutdown
332 { 348 //{
333 get { return _PleaseShutdown; } 349 // get { return _PleaseShutdown; }
334 set { _PleaseShutdown = value; } 350 // set { _PleaseShutdown = value; }
335 } 351 //}
336 private bool _PleaseShutdown = false; 352 //private bool _PleaseShutdown = false;
337 } 353 }
338} 354}
diff --git a/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/MaintenanceThread.cs b/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/MaintenanceThread.cs
index 5c9f76d..0911afb 100644
--- a/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/MaintenanceThread.cs
+++ b/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/MaintenanceThread.cs
@@ -156,12 +156,11 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
156 m_ScriptEngine.m_EventQueueManager.AdjustNumberOfScriptThreads(); 156 m_ScriptEngine.m_EventQueueManager.AdjustNumberOfScriptThreads();
157 157
158 // Check if any script has exceeded its max execution time 158 // Check if any script has exceeded its max execution time
159 if (m_ScriptEngine.m_EventQueueManager != null && 159 if (EventQueueManager.EnforceMaxExecutionTime)
160 m_ScriptEngine.m_EventQueueManager.EnforceMaxExecutionTime)
161 { 160 {
162 // We are enforcing execution time 161 // We are enforcing execution time
163 if (DateTime.Now.Ticks - Last_maxFunctionExecutionTimens > 162 if (DateTime.Now.Ticks - Last_maxFunctionExecutionTimens >
164 m_ScriptEngine.m_EventQueueManager.maxFunctionExecutionTimens) 163 EventQueueManager.maxFunctionExecutionTimens)
165 { 164 {
166 // Its time to check again 165 // Its time to check again
167 m_ScriptEngine.m_EventQueueManager.CheckScriptMaxExecTime(); // Do check 166 m_ScriptEngine.m_EventQueueManager.CheckScriptMaxExecTime(); // Do check