aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/EventQueueThreadClass.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/EventQueueThreadClass.cs')
-rw-r--r--OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/EventQueueThreadClass.cs402
1 files changed, 209 insertions, 193 deletions
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}