aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ScriptEngine/DotNetEngine/EventQueueThreadClass.cs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--OpenSim/Region/ScriptEngine/DotNetEngine/EventQueueThreadClass.cs359
1 files changed, 170 insertions, 189 deletions
diff --git a/OpenSim/Region/ScriptEngine/DotNetEngine/EventQueueThreadClass.cs b/OpenSim/Region/ScriptEngine/DotNetEngine/EventQueueThreadClass.cs
index db3f89f..a9de503 100644
--- a/OpenSim/Region/ScriptEngine/DotNetEngine/EventQueueThreadClass.cs
+++ b/OpenSim/Region/ScriptEngine/DotNetEngine/EventQueueThreadClass.cs
@@ -34,20 +34,18 @@ using System.Globalization;
34using OpenMetaverse; 34using OpenMetaverse;
35using log4net; 35using log4net;
36using OpenSim.Framework; 36using OpenSim.Framework;
37using OpenSim.Region.Environment.Scenes;
37using OpenSim.Region.Environment.Scenes.Scripting; 38using OpenSim.Region.Environment.Scenes.Scripting;
39using OpenSim.Region.ScriptEngine.Shared;
38 40
39namespace OpenSim.Region.ScriptEngine.DotNetEngine 41namespace OpenSim.Region.ScriptEngine.DotNetEngine
40{ 42{
41 /// <summary> 43 // Because every thread needs some data set for it
42 /// Because every thread needs some data set for it (time started to execute current function), it will do its work within a class 44 // (time started to execute current function), it will do its work
43 /// </summary> 45 // within a class
44 public class EventQueueThreadClass : iScriptEngineFunctionModule 46 public class EventQueueThreadClass : iScriptEngineFunctionModule
45 { 47 {
46 // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 48 // How many ms to sleep if queue is empty
47
48 /// <summary>
49 /// How many ms to sleep if queue is empty
50 /// </summary>
51 private static int nothingToDoSleepms;// = 50; 49 private static int nothingToDoSleepms;// = 50;
52 private static ThreadPriority MyThreadPriority; 50 private static ThreadPriority MyThreadPriority;
53 51
@@ -77,13 +75,17 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine
77 { 75 {
78 lock (ScriptEngine.ScriptEngines) 76 lock (ScriptEngine.ScriptEngines)
79 { 77 {
80 foreach (ScriptEngine m_ScriptEngine in ScriptEngine.ScriptEngines) 78 foreach (ScriptEngine m_ScriptEngine in
79 ScriptEngine.ScriptEngines)
81 { 80 {
82 ScriptEngineName = m_ScriptEngine.ScriptEngineName; 81 ScriptEngineName = m_ScriptEngine.ScriptEngineName;
83 nothingToDoSleepms = m_ScriptEngine.ScriptConfigSource.GetInt("SleepTimeIfNoScriptExecutionMs", 50); 82 nothingToDoSleepms =
83 m_ScriptEngine.ScriptConfigSource.GetInt(
84 "SleepTimeIfNoScriptExecutionMs", 50);
85
86 string pri = m_ScriptEngine.ScriptConfigSource.GetString(
87 "ScriptThreadPriority", "BelowNormal");
84 88
85 // Later with ScriptServer we might want to ask OS for stuff too, so doing this a bit manually
86 string pri = m_ScriptEngine.ScriptConfigSource.GetString("ScriptThreadPriority", "BelowNormal");
87 switch (pri.ToLower()) 89 switch (pri.ToLower())
88 { 90 {
89 case "lowest": 91 case "lowest":
@@ -102,9 +104,12 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine
102 MyThreadPriority = ThreadPriority.Highest; 104 MyThreadPriority = ThreadPriority.Highest;
103 break; 105 break;
104 default: 106 default:
105 MyThreadPriority = ThreadPriority.BelowNormal; // Default 107 MyThreadPriority = ThreadPriority.BelowNormal;
106 m_ScriptEngine.Log.Error("[ScriptEngine.DotNetEngine]: Unknown priority type \"" + pri + 108 m_ScriptEngine.Log.Error(
107 "\" in config file. Defaulting to \"BelowNormal\"."); 109 "[ScriptEngine.DotNetEngine]: Unknown "+
110 "priority type \"" + pri +
111 "\" in config file. Defaulting to "+
112 "\"BelowNormal\".");
108 break; 113 break;
109 } 114 }
110 } 115 }
@@ -128,41 +133,41 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine
128 EventQueueThread.Start(); 133 EventQueueThread.Start();
129 ThreadTracker.Add(EventQueueThread); 134 ThreadTracker.Add(EventQueueThread);
130 135
131 // Look at this... Don't you wish everyone did that solid coding everywhere? :P 136 // Look at this... Don't you wish everyone did that solid
137 // coding everywhere? :P
138
132 if (ThreadCount == int.MaxValue) 139 if (ThreadCount == int.MaxValue)
133 ThreadCount = 0; 140 ThreadCount = 0;
141
134 ThreadCount++; 142 ThreadCount++;
135 } 143 }
136 144
137 public void Stop() 145 public void Stop()
138 { 146 {
139 //PleaseShutdown = true; // Set shutdown flag
140 //Thread.Sleep(100); // Wait a bit
141 if (EventQueueThread != null && EventQueueThread.IsAlive == true) 147 if (EventQueueThread != null && EventQueueThread.IsAlive == true)
142 { 148 {
143 try 149 try
144 { 150 {
145 EventQueueThread.Abort(); // Send abort 151 EventQueueThread.Abort(); // Send abort
146 //EventQueueThread.Join(); // Wait for it
147 } 152 }
148 catch (Exception) 153 catch (Exception)
149 { 154 {
150 //myScriptEngine.Log.Info("[" + ScriptEngineName + "]: EventQueueManager Exception killing worker thread: " + e.ToString());
151 } 155 }
152 } 156 }
153 } 157 }
154 158
155 private EventQueueManager.QueueItemStruct BlankQIS = new EventQueueManager.QueueItemStruct(); 159 private EventQueueManager.QueueItemStruct BlankQIS =
160 new EventQueueManager.QueueItemStruct();
161
156 private ScriptEngine lastScriptEngine; 162 private ScriptEngine lastScriptEngine;
157 /// <summary> 163 private uint lastLocalID;
158 /// Queue processing thread loop 164
159 /// </summary> 165 // Queue processing thread loop
160 private void EventQueueThreadLoop() 166 private void EventQueueThreadLoop()
161 { 167 {
162 CultureInfo USCulture = new CultureInfo("en-US"); 168 CultureInfo USCulture = new CultureInfo("en-US");
163 Thread.CurrentThread.CurrentCulture = USCulture; 169 Thread.CurrentThread.CurrentCulture = USCulture;
164 170
165 //myScriptEngine.Log.Info("[" + ScriptEngineName + "]: EventQueueManager Worker thread spawned");
166 try 171 try
167 { 172 {
168 while (true) 173 while (true)
@@ -177,205 +182,181 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine
177 catch (ThreadAbortException) 182 catch (ThreadAbortException)
178 { 183 {
179 if (lastScriptEngine != null) 184 if (lastScriptEngine != null)
180 lastScriptEngine.Log.Info("[" + ScriptEngineName + "]: ThreadAbortException while executing function."); 185 lastScriptEngine.Log.Info("[" + ScriptEngineName +
186 "]: ThreadAbortException while executing "+
187 "function.");
188 }
189 catch (SelfDeleteException) // Must delete SOG
190 {
191 SceneObjectPart part =
192 lastScriptEngine.World.GetSceneObjectPart(
193 lastLocalID);
194
195 if (part != null && part.ParentGroup != null)
196 lastScriptEngine.World.DeleteSceneObject(
197 part.ParentGroup);
181 } 198 }
182 catch (Exception e) 199 catch (Exception e)
183 { 200 {
184 if (lastScriptEngine != null) 201 if (lastScriptEngine != null)
185 lastScriptEngine.Log.Error("[" + ScriptEngineName + "]: Exception in EventQueueThreadLoop: " + e.ToString()); 202 lastScriptEngine.Log.Error("[" + ScriptEngineName +
203 "]: Exception in EventQueueThreadLoop: " +
204 e.ToString());
186 } 205 }
187 } 206 }
188 } 207 }
189 catch (ThreadAbortException) 208 catch (ThreadAbortException)
190 { 209 {
191 //myScriptEngine.Log.Info("[" + ScriptEngineName + "]: EventQueueManager Worker thread killed: " + tae.Message);
192 } 210 }
193 } 211 }
194 212
195 public void DoProcessQueue() 213 public void DoProcessQueue()
196 { 214 {
197 //lock (ScriptEngine.ScriptEngines) 215 foreach (ScriptEngine m_ScriptEngine in
198 //{ 216 new ArrayList(ScriptEngine.ScriptEngines))
199 foreach (ScriptEngine m_ScriptEngine in new ArrayList(ScriptEngine.ScriptEngines)) 217 {
218 lastScriptEngine = m_ScriptEngine;
219
220 EventQueueManager.QueueItemStruct QIS = BlankQIS;
221 bool GotItem = false;
222
223 //if (PleaseShutdown)
224 // return;
225
226 if (m_ScriptEngine.m_EventQueueManager == null ||
227 m_ScriptEngine.m_EventQueueManager.eventQueue == null)
228 continue;
229
230 if (m_ScriptEngine.m_EventQueueManager.eventQueue.Count == 0)
200 { 231 {
201 lastScriptEngine = m_ScriptEngine; 232 // Nothing to do? Sleep a bit waiting for something to do
202 // Every now and then check if we should shut down 233 Thread.Sleep(nothingToDoSleepms);
203 //if (PleaseShutdown || EventQueueManager.ThreadsToExit > 0) 234 }
204 //{ 235 else
205 // // Someone should shut down, lets get exclusive lock 236 {
206 // lock (EventQueueManager.ThreadsToExitLock) 237 // Something in queue, process
207 // { 238
208 // // Lets re-check in case someone grabbed it 239 // OBJECT BASED LOCK - TWO THREADS WORKING ON SAME
209 // if (EventQueueManager.ThreadsToExit > 0) 240 // OBJECT IS NOT GOOD
210 // { 241 lock (m_ScriptEngine.m_EventQueueManager.eventQueue)
211 // // Its crowded here so we'll shut down
212 // EventQueueManager.ThreadsToExit--;
213 // Stop();
214 // return;
215 // }
216 // else
217 // {
218 // // We have been asked to shut down
219 // Stop();
220 // return;
221 // }
222 // }
223 //}
224
225 //try
226 // {
227 EventQueueManager.QueueItemStruct QIS = BlankQIS;
228 bool GotItem = false;
229
230 //if (PleaseShutdown)
231 // return;
232
233 if (m_ScriptEngine.m_EventQueueManager == null || m_ScriptEngine.m_EventQueueManager.eventQueue == null)
234 continue;
235
236 if (m_ScriptEngine.m_EventQueueManager.eventQueue.Count == 0)
237 { 242 {
238 // Nothing to do? Sleep a bit waiting for something to do 243 GotItem = false;
239 Thread.Sleep(nothingToDoSleepms); 244 for (int qc = 0; qc < m_ScriptEngine.m_EventQueueManager.eventQueue.Count; qc++)
245 {
246 // Get queue item
247 QIS = m_ScriptEngine.m_EventQueueManager.eventQueue.Dequeue();
248
249 // Check if object is being processed by
250 // someone else
251 if (m_ScriptEngine.m_EventQueueManager.TryLock(
252 QIS.localID) == false)
253 {
254 // Object is already being processed, requeue it
255 m_ScriptEngine.m_EventQueueManager.
256 eventQueue.Enqueue(QIS);
257 }
258 else
259 {
260 // We have lock on an object and can process it
261 GotItem = true;
262 break;
263 }
264 }
240 } 265 }
241 else
242 {
243 // Something in queue, process
244 //myScriptEngine.Log.Info("[" + ScriptEngineName + "]: Processing event for localID: " + QIS.localID + ", itemID: " + QIS.itemID + ", FunctionName: " + QIS.FunctionName);
245 266
246 // OBJECT BASED LOCK - TWO THREADS WORKING ON SAME OBJECT IS NOT GOOD 267 if (GotItem == true)
247 lock (m_ScriptEngine.m_EventQueueManager.eventQueue) 268 {
269 // Execute function
270 try
248 { 271 {
249 GotItem = false; 272 // Only pipe event if land supports it.
250 for (int qc = 0; qc < m_ScriptEngine.m_EventQueueManager.eventQueue.Count; qc++) 273 if (m_ScriptEngine.World.PipeEventsForScript(
274 QIS.localID))
251 { 275 {
252 // Get queue item 276 lastLocalID = QIS.localID;
253 QIS = m_ScriptEngine.m_EventQueueManager.eventQueue.Dequeue(); 277 LastExecutionStarted = DateTime.Now.Ticks;
278 KillCurrentScript = false;
279 InExecution = true;
280 m_ScriptEngine.m_ScriptManager.ExecuteEvent(
281 QIS.localID,
282 QIS.itemID,
283 QIS.functionName,
284 QIS.llDetectParams,
285 QIS.param);
254 286
255 // Check if object is being processed by someone else 287 InExecution = false;
256 if (m_ScriptEngine.m_EventQueueManager.TryLock(QIS.localID) == false)
257 {
258 // Object is already being processed, requeue it
259 m_ScriptEngine.m_EventQueueManager.eventQueue.Enqueue(QIS);
260 }
261 else
262 {
263 // We have lock on an object and can process it
264 GotItem = true;
265 break;
266 }
267 } 288 }
268 } 289 }
269 290 catch (Exception e)
270 if (GotItem == true)
271 { 291 {
272 // Execute function 292 InExecution = false;
273 try 293 // DISPLAY ERROR INWORLD
294 string text = "Error executing script function \"" +
295 QIS.functionName + "\":\r\n";
296
297 if (e.InnerException != null)
274 { 298 {
275 ///cfk 2-7-08 dont need this right now and the default Linux build has DEBUG defined 299 // Send inner exception
276#if DEBUG 300 string line = " (unknown line)";
277 //eventQueueManager.m_ScriptEngine.Log.Debug("[" + ScriptEngineName + "]: " + 301 Regex rx = new Regex(@"SecondLife\.Script\..+[\s:](?<line>\d+)\.?\r?$", RegexOptions.Compiled);
278 // "Executing event:\r\n" 302 if (rx.Match(e.InnerException.ToString()).Success)
279 // + "QIS.localID: " + QIS.localID 303 line = " (line " + rx.Match(e.InnerException.ToString()).Result("${line}") + ")";
280 // + ", QIS.itemID: " + QIS.itemID 304 text += e.InnerException.Message.ToString() + line;
281 // + ", QIS.functionName: " +
282 // QIS.functionName);
283#endif
284 // Only pipe event if land supports it.
285 if (m_ScriptEngine.World.PipeEventsForScript(QIS.localID))
286 {
287 LastExecutionStarted = DateTime.Now.Ticks;
288 KillCurrentScript = false;
289 InExecution = true;
290 m_ScriptEngine.m_ScriptManager.ExecuteEvent(QIS.localID,
291 QIS.itemID,
292 QIS.functionName,
293 QIS.llDetectParams,
294 QIS.param);
295 InExecution = false;
296 }
297 } 305 }
298 catch (Exception e) 306 else
299 { 307 {
300 InExecution = false; 308 text += "\r\n";
301 // DISPLAY ERROR INWORLD 309 // Send normal
302 string text = "Error executing script function \"" + QIS.functionName + 310 text += e.Message.ToString();
303 "\":\r\n"; 311 }
304 if (e.InnerException != null) 312 if (KillCurrentScript)
305 { 313 text += "\r\nScript will be deactivated!";
306 // Send inner exception
307 string line = " (unknown line)";
308 Regex rx = new Regex(@"SecondLife\.Script\..+[\s:](?<line>\d+)\.?\r?$", RegexOptions.Compiled);
309 if (rx.Match(e.InnerException.ToString()).Success)
310 line = " (line " + rx.Match(e.InnerException.ToString()).Result("${line}") + ")";
311 text += e.InnerException.Message.ToString() + line;
312 }
313 else
314 {
315 text += "\r\n";
316 // Send normal
317 text += e.Message.ToString();
318 }
319 if (KillCurrentScript)
320 text += "\r\nScript will be deactivated!";
321
322 try
323 {
324 if (text.Length > 1500)
325 text = text.Substring(0, 1500);
326 IScriptHost m_host =
327 m_ScriptEngine.World.GetSceneObjectPart(QIS.localID);
328 //if (m_host != null)
329 //{
330 m_ScriptEngine.World.SimChat(Utils.StringToBytes(text),
331 ChatTypeEnum.DebugChannel, 2147483647,
332 m_host.AbsolutePosition,
333 m_host.Name, m_host.UUID, false);
334 }
335 catch (Exception)
336 {
337 //}
338 //else
339 //{
340 // T oconsole
341 m_ScriptEngine.m_EventQueueManager.m_ScriptEngine.Log.Error("[" + ScriptEngineName +
342 "]: " +
343 "Unable to send text in-world:\r\n" +
344 text);
345 }
346 finally
347 {
348 // So we are done sending message in-world
349 if (KillCurrentScript)
350 {
351 m_ScriptEngine.m_EventQueueManager.m_ScriptEngine.m_ScriptManager.StopScript(
352 QIS.localID, QIS.itemID);
353 }
354 }
355 314
356 // Pass it on so it's displayed on the console 315 try
357 // and in the logs (mikem 2008.06.02). 316 {
358 throw e.InnerException; 317 if (text.Length > 1500)
318 text = text.Substring(0, 1500);
319 IScriptHost m_host =
320 m_ScriptEngine.World.GetSceneObjectPart(QIS.localID);
321 m_ScriptEngine.World.SimChat(
322 Utils.StringToBytes(text),
323 ChatTypeEnum.DebugChannel, 2147483647,
324 m_host.AbsolutePosition,
325 m_host.Name, m_host.UUID, false);
326 }
327 catch (Exception)
328 {
329 m_ScriptEngine.m_EventQueueManager.
330 m_ScriptEngine.Log.Error("[" +
331 ScriptEngineName + "]: " +
332 "Unable to send text in-world:\r\n" +
333 text);
359 } 334 }
360 finally 335 finally
361 { 336 {
362 InExecution = false; 337 // So we are done sending message in-world
363 m_ScriptEngine.m_EventQueueManager.ReleaseLock(QIS.localID); 338 if (KillCurrentScript)
339 {
340 m_ScriptEngine.m_EventQueueManager.
341 m_ScriptEngine.m_ScriptManager.
342 StopScript(
343 QIS.localID, QIS.itemID);
344 }
364 } 345 }
346
347 // Pass it on so it's displayed on the console
348 // and in the logs (mikem 2008.06.02).
349 throw e.InnerException;
350 }
351 finally
352 {
353 InExecution = false;
354 m_ScriptEngine.m_EventQueueManager.ReleaseLock(
355 QIS.localID);
365 } 356 }
366 } 357 }
367 } 358 }
368 // } 359 }
369 } 360 }
370
371 ///// <summary>
372 ///// If set to true then threads and stuff should try to make a graceful exit
373 ///// </summary>
374 //public bool PleaseShutdown
375 //{
376 // get { return _PleaseShutdown; }
377 // set { _PleaseShutdown = value; }
378 //}
379 //private bool _PleaseShutdown = false;
380 } 361 }
381} 362}