aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ScriptEngine/DotNetEngine/EventQueueThreadClass.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/ScriptEngine/DotNetEngine/EventQueueThreadClass.cs')
-rw-r--r--OpenSim/Region/ScriptEngine/DotNetEngine/EventQueueThreadClass.cs428
1 files changed, 0 insertions, 428 deletions
diff --git a/OpenSim/Region/ScriptEngine/DotNetEngine/EventQueueThreadClass.cs b/OpenSim/Region/ScriptEngine/DotNetEngine/EventQueueThreadClass.cs
deleted file mode 100644
index 51fd41a..0000000
--- a/OpenSim/Region/ScriptEngine/DotNetEngine/EventQueueThreadClass.cs
+++ /dev/null
@@ -1,428 +0,0 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections;
30using System.Collections.Generic;
31using System.Reflection;
32using System.Text.RegularExpressions;
33using System.Threading;
34using System.Globalization;
35using OpenMetaverse;
36using log4net;
37using OpenSim.Framework;
38using OpenSim.Region.Framework.Scenes;
39using OpenSim.Region.Framework.Scenes.Scripting;
40using OpenSim.Region.ScriptEngine.Shared;
41using OpenSim.Region.ScriptEngine.Shared.CodeTools;
42
43namespace OpenSim.Region.ScriptEngine.DotNetEngine
44{
45 // Because every thread needs some data set for it
46 // (time started to execute current function), it will do its work
47 // within a class
48 public class EventQueueThreadClass
49 {
50 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
51
52 // How many ms to sleep if queue is empty
53 private static int nothingToDoSleepms;// = 50;
54 private static ThreadPriority MyThreadPriority;
55
56 public long LastExecutionStarted;
57 public bool InExecution = false;
58 public bool KillCurrentScript = false;
59
60 //private EventQueueManager eventQueueManager;
61 public Thread EventQueueThread;
62 private static int ThreadCount = 0;
63
64 private string ScriptEngineName = "ScriptEngine.Common";
65
66 public EventQueueThreadClass()//EventQueueManager eqm
67 {
68 CultureInfo USCulture = new CultureInfo("en-US");
69 Thread.CurrentThread.CurrentCulture = USCulture;
70
71 //eventQueueManager = eqm;
72 ReadConfig();
73 Start();
74 }
75
76 ~EventQueueThreadClass()
77 {
78 Stop();
79 }
80
81 public void ReadConfig()
82 {
83 lock (ScriptEngine.ScriptEngines)
84 {
85 foreach (ScriptEngine m_ScriptEngine in
86 ScriptEngine.ScriptEngines)
87 {
88 ScriptEngineName = m_ScriptEngine.ScriptEngineName;
89 nothingToDoSleepms =
90 m_ScriptEngine.ScriptConfigSource.GetInt(
91 "SleepTimeIfNoScriptExecutionMs", 50);
92
93 string pri = m_ScriptEngine.ScriptConfigSource.GetString(
94 "ScriptThreadPriority", "BelowNormal");
95
96 switch (pri.ToLower())
97 {
98 case "lowest":
99 MyThreadPriority = ThreadPriority.Lowest;
100 break;
101 case "belownormal":
102 MyThreadPriority = ThreadPriority.BelowNormal;
103 break;
104 case "normal":
105 MyThreadPriority = ThreadPriority.Normal;
106 break;
107 case "abovenormal":
108 MyThreadPriority = ThreadPriority.AboveNormal;
109 break;
110 case "highest":
111 MyThreadPriority = ThreadPriority.Highest;
112 break;
113 default:
114 MyThreadPriority = ThreadPriority.BelowNormal;
115 m_log.Error(
116 "[ScriptEngine.DotNetEngine]: Unknown "+
117 "priority type \"" + pri +
118 "\" in config file. Defaulting to "+
119 "\"BelowNormal\".");
120 break;
121 }
122 }
123 }
124 // Now set that priority
125 if (EventQueueThread != null)
126 if (EventQueueThread.IsAlive)
127 EventQueueThread.Priority = MyThreadPriority;
128 }
129
130 /// <summary>
131 /// Start thread
132 /// </summary>
133 private void Start()
134 {
135 EventQueueThread = Watchdog.StartThread(EventQueueThreadLoop, "EventQueueManagerThread_" + ThreadCount, MyThreadPriority, true);
136
137 // Look at this... Don't you wish everyone did that solid
138 // coding everywhere? :P
139
140 if (ThreadCount == int.MaxValue)
141 ThreadCount = 0;
142
143 ThreadCount++;
144 }
145
146 public void Stop()
147 {
148 if (EventQueueThread != null && EventQueueThread.IsAlive == true)
149 {
150 try
151 {
152 EventQueueThread.Abort(); // Send abort
153 }
154 catch (Exception)
155 {
156 }
157 }
158 }
159
160 private EventQueueManager.QueueItemStruct BlankQIS =
161 new EventQueueManager.QueueItemStruct();
162
163 private ScriptEngine lastScriptEngine;
164 private uint lastLocalID;
165 private UUID lastItemID;
166
167 // Queue processing thread loop
168 private void EventQueueThreadLoop()
169 {
170 CultureInfo USCulture = new CultureInfo("en-US");
171 Thread.CurrentThread.CurrentCulture = USCulture;
172
173 try
174 {
175 while (true)
176 {
177 try
178 {
179 while (true)
180 {
181 DoProcessQueue();
182 Watchdog.UpdateThread();
183 }
184 }
185 catch (ThreadAbortException)
186 {
187 m_log.Info("[" + ScriptEngineName +
188 "]: ThreadAbortException while executing "+
189 "function.");
190 }
191 catch (SelfDeleteException) // Must delete SOG
192 {
193 SceneObjectPart part =
194 lastScriptEngine.World.GetSceneObjectPart(
195 lastLocalID);
196 if (part != null && part.ParentGroup != null)
197 lastScriptEngine.World.DeleteSceneObject(
198 part.ParentGroup, false);
199 }
200 catch (ScriptDeleteException) // Must delete item
201 {
202 SceneObjectPart part =
203 lastScriptEngine.World.GetSceneObjectPart(
204 lastLocalID);
205 if (part != null && part.ParentGroup != null)
206 part.Inventory.RemoveInventoryItem(lastItemID);
207 }
208 catch (Exception e)
209 {
210 m_log.ErrorFormat("[{0}]: Exception {1} thrown", ScriptEngineName, e.GetType().ToString());
211 throw e;
212 }
213
214 Watchdog.UpdateThread();
215 }
216 }
217 catch (ThreadAbortException)
218 {
219 }
220 catch (Exception e)
221 {
222 // TODO: Let users in the sim and those entering it and possibly an external watchdog know what has happened
223 m_log.ErrorFormat(
224 "[{0}]: Event queue thread terminating with exception. PLEASE REBOOT YOUR SIM - SCRIPT EVENTS WILL NOT WORK UNTIL YOU DO. Exception is {1}",
225 ScriptEngineName, e);
226 }
227
228 Watchdog.RemoveThread();
229 }
230
231 public void DoProcessQueue()
232 {
233 foreach (ScriptEngine m_ScriptEngine in
234 new ArrayList(ScriptEngine.ScriptEngines))
235 {
236 lastScriptEngine = m_ScriptEngine;
237
238 EventQueueManager.QueueItemStruct QIS = BlankQIS;
239 bool GotItem = false;
240
241 //if (PleaseShutdown)
242 // return;
243
244 if (m_ScriptEngine.m_EventQueueManager == null ||
245 m_ScriptEngine.m_EventQueueManager.eventQueue == null)
246 continue;
247
248 if (m_ScriptEngine.m_EventQueueManager.eventQueue.Count == 0)
249 {
250 // Nothing to do? Sleep a bit waiting for something to do
251 Thread.Sleep(nothingToDoSleepms);
252 }
253 else
254 {
255 // Something in queue, process
256
257 // OBJECT BASED LOCK - TWO THREADS WORKING ON SAME
258 // OBJECT IS NOT GOOD
259 lock (m_ScriptEngine.m_EventQueueManager.eventQueue)
260 {
261 GotItem = false;
262 for (int qc = 0; qc < m_ScriptEngine.m_EventQueueManager.eventQueue.Count; qc++)
263 {
264 // Get queue item
265 QIS = m_ScriptEngine.m_EventQueueManager.eventQueue.Dequeue();
266
267 // Check if object is being processed by
268 // someone else
269 if (m_ScriptEngine.m_EventQueueManager.TryLock(
270 QIS.localID) == false)
271 {
272 // Object is already being processed, requeue it
273 m_ScriptEngine.m_EventQueueManager.
274 eventQueue.Enqueue(QIS);
275 }
276 else
277 {
278 // We have lock on an object and can process it
279 GotItem = true;
280 break;
281 }
282 }
283 }
284
285 if (GotItem == true)
286 {
287 // Execute function
288 try
289 {
290 // Only pipe event if land supports it.
291 if (m_ScriptEngine.World.PipeEventsForScript(
292 QIS.localID))
293 {
294 lastLocalID = QIS.localID;
295 lastItemID = QIS.itemID;
296 LastExecutionStarted = DateTime.Now.Ticks;
297 KillCurrentScript = false;
298 InExecution = true;
299 m_ScriptEngine.m_ScriptManager.ExecuteEvent(
300 QIS.localID,
301 QIS.itemID,
302 QIS.functionName,
303 QIS.llDetectParams,
304 QIS.param);
305
306 InExecution = false;
307 }
308 }
309 catch (TargetInvocationException tie)
310 {
311 Exception e = tie.InnerException;
312
313 if (e is SelfDeleteException) // Forward it
314 throw e;
315
316 InExecution = false;
317 string text = FormatException(tie, QIS.LineMap);
318
319 // DISPLAY ERROR INWORLD
320
321// if (e.InnerException != null)
322// {
323// // Send inner exception
324// string line = " (unknown line)";
325// Regex rx = new Regex(@"SecondLife\.Script\..+[\s:](?<line>\d+)\.?\r?$", RegexOptions.Compiled);
326// if (rx.Match(e.InnerException.ToString()).Success)
327// line = " (line " + rx.Match(e.InnerException.ToString()).Result("${line}") + ")";
328// text += e.InnerException.Message.ToString() + line;
329// }
330// else
331// {
332// text += "\r\n";
333// // Send normal
334// text += e.Message.ToString();
335// }
336// if (KillCurrentScript)
337// text += "\r\nScript will be deactivated!";
338
339 try
340 {
341 if (text.Length >= 1100)
342 text = text.Substring(0, 1099);
343 IScriptHost m_host =
344 m_ScriptEngine.World.GetSceneObjectPart(QIS.localID);
345 m_ScriptEngine.World.SimChat(
346 Utils.StringToBytes(text),
347 ChatTypeEnum.DebugChannel, 2147483647,
348 m_host.AbsolutePosition,
349 m_host.Name, m_host.UUID, false);
350 }
351 catch (Exception)
352 {
353 m_log.Error("[" +
354 ScriptEngineName + "]: " +
355 "Unable to send text in-world:\r\n" +
356 text);
357 }
358 finally
359 {
360 // So we are done sending message in-world
361 if (KillCurrentScript)
362 {
363 m_ScriptEngine.m_EventQueueManager.
364 m_ScriptEngine.m_ScriptManager.
365 StopScript(
366 QIS.localID, QIS.itemID);
367 }
368 }
369 }
370 catch (Exception)
371 {
372 throw;
373 }
374 finally
375 {
376 InExecution = false;
377 m_ScriptEngine.m_EventQueueManager.ReleaseLock(
378 QIS.localID);
379 }
380 }
381 }
382 }
383 }
384
385 string FormatException(Exception e, Dictionary<KeyValuePair<int,int>,
386 KeyValuePair<int,int>> LineMap)
387 {
388 if (e.InnerException == null)
389 return e.ToString();
390
391 string message = "Runtime error:\n" + e.InnerException.StackTrace;
392 string[] lines = message.Split(new char[] {'\n'});
393
394 foreach (string line in lines)
395 {
396 if (line.Contains("SecondLife.Script"))
397 {
398 int idx = line.IndexOf(':');
399 if (idx != -1)
400 {
401 string val = line.Substring(idx+1);
402 int lineNum = 0;
403 if (int.TryParse(val, out lineNum))
404 {
405 KeyValuePair<int, int> pos =
406 Compiler.FindErrorPosition(
407 lineNum, 0, LineMap);
408
409 int scriptLine = pos.Key;
410 int col = pos.Value;
411 if (scriptLine == 0)
412 scriptLine++;
413 if (col == 0)
414 col++;
415 message = string.Format("Runtime error:\n" +
416 "Line ({0}): {1}", scriptLine - 1,
417 e.InnerException.Message);
418
419 return message;
420 }
421 }
422 }
423 }
424
425 return message;
426 }
427 }
428}