aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/EventQueueThreadClass.cs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/EventQueueThreadClass.cs628
1 files changed, 314 insertions, 314 deletions
diff --git a/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/EventQueueThreadClass.cs b/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/EventQueueThreadClass.cs
index c19d641..b239965 100644
--- a/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/EventQueueThreadClass.cs
+++ b/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/EventQueueThreadClass.cs
@@ -1,314 +1,314 @@
1using System; 1using System;
2using System.Collections.Generic; 2using System.Collections.Generic;
3using System.Text; 3using System.Text;
4using System.Threading; 4using System.Threading;
5using libsecondlife; 5using libsecondlife;
6using Nini.Config; 6using Nini.Config;
7using OpenSim.Framework; 7using OpenSim.Framework;
8using OpenSim.Region.Environment.Scenes.Scripting; 8using OpenSim.Region.Environment.Scenes.Scripting;
9 9
10namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase 10namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
11{ 11{
12 /// <summary> 12 /// <summary>
13 /// Because every thread needs some data set for it (time started to execute current function), it will do its work within a class 13 /// Because every thread needs some data set for it (time started to execute current function), it will do its work within a class
14 /// </summary> 14 /// </summary>
15 public class EventQueueThreadClass: iScriptEngineFunctionModule 15 public class EventQueueThreadClass: iScriptEngineFunctionModule
16 { 16 {
17 /// <summary> 17 /// <summary>
18 /// How many ms to sleep if queue is empty 18 /// How many ms to sleep if queue is empty
19 /// </summary> 19 /// </summary>
20 private int nothingToDoSleepms;// = 50; 20 private int nothingToDoSleepms;// = 50;
21 private ThreadPriority MyThreadPriority; 21 private ThreadPriority MyThreadPriority;
22 22
23 public long LastExecutionStarted; 23 public long LastExecutionStarted;
24 public bool InExecution = false; 24 public bool InExecution = false;
25 public bool KillCurrentScript = false; 25 public bool KillCurrentScript = false;
26 26
27 private EventQueueManager eventQueueManager; 27 private EventQueueManager eventQueueManager;
28 public Thread EventQueueThread; 28 public Thread EventQueueThread;
29 private static int ThreadCount = 0; 29 private static int ThreadCount = 0;
30 30
31 private string ScriptEngineName = "ScriptEngine.Common"; 31 private string ScriptEngineName = "ScriptEngine.Common";
32 32
33 public EventQueueThreadClass(EventQueueManager eqm) 33 public EventQueueThreadClass(EventQueueManager eqm)
34 { 34 {
35 eventQueueManager = eqm; 35 eventQueueManager = eqm;
36 ReadConfig(); 36 ReadConfig();
37 Start(); 37 Start();
38 } 38 }
39 39
40 ~EventQueueThreadClass() 40 ~EventQueueThreadClass()
41 { 41 {
42 Stop(); 42 Stop();
43 } 43 }
44 44
45 45
46 public void ReadConfig() 46 public void ReadConfig()
47 { 47 {
48 ScriptEngineName = eventQueueManager.m_ScriptEngine.ScriptEngineName; 48 ScriptEngineName = eventQueueManager.m_ScriptEngine.ScriptEngineName;
49 nothingToDoSleepms = eventQueueManager.m_ScriptEngine.ScriptConfigSource.GetInt("SleepTimeIfNoScriptExecutionMs", 50); 49 nothingToDoSleepms = eventQueueManager.m_ScriptEngine.ScriptConfigSource.GetInt("SleepTimeIfNoScriptExecutionMs", 50);
50 50
51 // Later with ScriptServer we might want to ask OS for stuff too, so doing this a bit manually 51 // Later with ScriptServer we might want to ask OS for stuff too, so doing this a bit manually
52 string pri = eventQueueManager.m_ScriptEngine.ScriptConfigSource.GetString("ScriptThreadPriority", "BelowNormal"); 52 string pri = eventQueueManager.m_ScriptEngine.ScriptConfigSource.GetString("ScriptThreadPriority", "BelowNormal");
53 switch (pri.ToLower()) 53 switch (pri.ToLower())
54 { 54 {
55 case "lowest": 55 case "lowest":
56 MyThreadPriority = ThreadPriority.Lowest; 56 MyThreadPriority = ThreadPriority.Lowest;
57 break; 57 break;
58 case "belownormal": 58 case "belownormal":
59 MyThreadPriority = ThreadPriority.BelowNormal; 59 MyThreadPriority = ThreadPriority.BelowNormal;
60 break; 60 break;
61 case "normal": 61 case "normal":
62 MyThreadPriority = ThreadPriority.Normal; 62 MyThreadPriority = ThreadPriority.Normal;
63 break; 63 break;
64 case "abovenormal": 64 case "abovenormal":
65 MyThreadPriority = ThreadPriority.AboveNormal; 65 MyThreadPriority = ThreadPriority.AboveNormal;
66 break; 66 break;
67 case "highest": 67 case "highest":
68 MyThreadPriority = ThreadPriority.Highest; 68 MyThreadPriority = ThreadPriority.Highest;
69 break; 69 break;
70 default: 70 default:
71 MyThreadPriority = ThreadPriority.BelowNormal; // Default 71 MyThreadPriority = ThreadPriority.BelowNormal; // Default
72 eventQueueManager.m_ScriptEngine.Log.Error("ScriptEngineBase", "Unknown priority type \"" + pri + "\" in config file. Defaulting to \"BelowNormal\"."); 72 eventQueueManager.m_ScriptEngine.Log.Error("ScriptEngineBase", "Unknown priority type \"" + pri + "\" in config file. Defaulting to \"BelowNormal\".");
73 break; 73 break;
74 } 74 }
75 75
76 // Now set that priority 76 // Now set that priority
77 if (EventQueueThread != null) 77 if (EventQueueThread != null)
78 if (EventQueueThread.IsAlive) 78 if (EventQueueThread.IsAlive)
79 EventQueueThread.Priority = MyThreadPriority; 79 EventQueueThread.Priority = MyThreadPriority;
80 80
81 } 81 }
82 82
83 83
84 /// <summary> 84 /// <summary>
85 /// Start thread 85 /// Start thread
86 /// </summary> 86 /// </summary>
87 private void Start() 87 private void Start()
88 { 88 {
89 89
90 EventQueueThread = new Thread(EventQueueThreadLoop); 90 EventQueueThread = new Thread(EventQueueThreadLoop);
91 EventQueueThread.IsBackground = true; 91 EventQueueThread.IsBackground = true;
92 92
93 EventQueueThread.Priority = MyThreadPriority; 93 EventQueueThread.Priority = MyThreadPriority;
94 EventQueueThread.Name = "EventQueueManagerThread_" + ThreadCount; 94 EventQueueThread.Name = "EventQueueManagerThread_" + ThreadCount;
95 EventQueueThread.Start(); 95 EventQueueThread.Start();
96 96
97 // Look at this... Don't you wish everyone did that solid coding everywhere? :P 97 // Look at this... Don't you wish everyone did that solid coding everywhere? :P
98 if (ThreadCount == int.MaxValue) 98 if (ThreadCount == int.MaxValue)
99 ThreadCount = 0; 99 ThreadCount = 0;
100 ThreadCount++; 100 ThreadCount++;
101 } 101 }
102 102
103 public void Stop() 103 public void Stop()
104 { 104 {
105 PleaseShutdown = true; // Set shutdown flag 105 PleaseShutdown = true; // Set shutdown flag
106 Thread.Sleep(100); // Wait a bit 106 Thread.Sleep(100); // Wait a bit
107 if (EventQueueThread != null && EventQueueThread.IsAlive == true) 107 if (EventQueueThread != null && EventQueueThread.IsAlive == true)
108 { 108 {
109 try 109 try
110 { 110 {
111 EventQueueThread.Abort(); // Send abort 111 EventQueueThread.Abort(); // Send abort
112 EventQueueThread.Join(); // Wait for it 112 EventQueueThread.Join(); // Wait for it
113 } 113 }
114 catch (Exception) 114 catch (Exception)
115 { 115 {
116 //myScriptEngine.Log.Verbose(ScriptEngineName, "EventQueueManager Exception killing worker thread: " + e.ToString()); 116 //myScriptEngine.Log.Verbose(ScriptEngineName, "EventQueueManager Exception killing worker thread: " + e.ToString());
117 } 117 }
118 } 118 }
119 } 119 }
120 120
121 121
122 /// <summary> 122 /// <summary>
123 /// Queue processing thread loop 123 /// Queue processing thread loop
124 /// </summary> 124 /// </summary>
125 private void EventQueueThreadLoop() 125 private void EventQueueThreadLoop()
126 { 126 {
127 //myScriptEngine.m_logger.Verbose(ScriptEngineName, "EventQueueManager Worker thread spawned"); 127 //myScriptEngine.m_logger.Verbose(ScriptEngineName, "EventQueueManager Worker thread spawned");
128 try 128 try
129 { 129 {
130 while (true) 130 while (true)
131 { 131 {
132 try 132 try
133 { 133 {
134 EventQueueManager.QueueItemStruct BlankQIS = new EventQueueManager.QueueItemStruct(); 134 EventQueueManager.QueueItemStruct BlankQIS = new EventQueueManager.QueueItemStruct();
135 while (true) 135 while (true)
136 { 136 {
137 // Every now and then check if we should shut down 137 // Every now and then check if we should shut down
138 if (PleaseShutdown || eventQueueManager.ThreadsToExit > 0) 138 if (PleaseShutdown || eventQueueManager.ThreadsToExit > 0)
139 { 139 {
140 // Someone should shut down, lets get exclusive lock 140 // Someone should shut down, lets get exclusive lock
141 lock (eventQueueManager.ThreadsToExitLock) 141 lock (eventQueueManager.ThreadsToExitLock)
142 { 142 {
143 // Lets re-check in case someone grabbed it 143 // Lets re-check in case someone grabbed it
144 if (eventQueueManager.ThreadsToExit > 0) 144 if (eventQueueManager.ThreadsToExit > 0)
145 { 145 {
146 // Its crowded here so we'll shut down 146 // Its crowded here so we'll shut down
147 eventQueueManager.ThreadsToExit--; 147 eventQueueManager.ThreadsToExit--;
148 Stop(); 148 Stop();
149 return; 149 return;
150 } 150 }
151 else 151 else
152 { 152 {
153 // We have been asked to shut down 153 // We have been asked to shut down
154 Stop(); 154 Stop();
155 return; 155 return;
156 } 156 }
157 } 157 }
158 } 158 }
159 159
160 160
161 //try 161 //try
162 // { 162 // {
163 EventQueueManager.QueueItemStruct QIS = BlankQIS; 163 EventQueueManager.QueueItemStruct QIS = BlankQIS;
164 bool GotItem = false; 164 bool GotItem = false;
165 165
166 if (PleaseShutdown) 166 if (PleaseShutdown)
167 return; 167 return;
168 168
169 if (eventQueueManager.eventQueue.Count == 0) 169 if (eventQueueManager.eventQueue.Count == 0)
170 { 170 {
171 // Nothing to do? Sleep a bit waiting for something to do 171 // Nothing to do? Sleep a bit waiting for something to do
172 Thread.Sleep(nothingToDoSleepms); 172 Thread.Sleep(nothingToDoSleepms);
173 } 173 }
174 else 174 else
175 { 175 {
176 // Something in queue, process 176 // Something in queue, process
177 //myScriptEngine.m_logger.Verbose(ScriptEngineName, "Processing event for localID: " + QIS.localID + ", itemID: " + QIS.itemID + ", FunctionName: " + QIS.FunctionName); 177 //myScriptEngine.m_logger.Verbose(ScriptEngineName, "Processing event for localID: " + QIS.localID + ", itemID: " + QIS.itemID + ", FunctionName: " + QIS.FunctionName);
178 178
179 // OBJECT BASED LOCK - TWO THREADS WORKING ON SAME OBJECT IS NOT GOOD 179 // OBJECT BASED LOCK - TWO THREADS WORKING ON SAME OBJECT IS NOT GOOD
180 lock (eventQueueManager.queueLock) 180 lock (eventQueueManager.queueLock)
181 { 181 {
182 GotItem = false; 182 GotItem = false;
183 for (int qc = 0; qc < eventQueueManager.eventQueue.Count; qc++) 183 for (int qc = 0; qc < eventQueueManager.eventQueue.Count; qc++)
184 { 184 {
185 // Get queue item 185 // Get queue item
186 QIS = eventQueueManager.eventQueue.Dequeue(); 186 QIS = eventQueueManager.eventQueue.Dequeue();
187 187
188 // Check if object is being processed by someone else 188 // Check if object is being processed by someone else
189 if (eventQueueManager.TryLock(QIS.localID) == false) 189 if (eventQueueManager.TryLock(QIS.localID) == false)
190 { 190 {
191 // Object is already being processed, requeue it 191 // Object is already being processed, requeue it
192 eventQueueManager.eventQueue.Enqueue(QIS); 192 eventQueueManager.eventQueue.Enqueue(QIS);
193 } 193 }
194 else 194 else
195 { 195 {
196 // We have lock on an object and can process it 196 // We have lock on an object and can process it
197 GotItem = true; 197 GotItem = true;
198 break; 198 break;
199 } 199 }
200 } // go through queue 200 } // go through queue
201 } // lock 201 } // lock
202 202
203 if (GotItem == true) 203 if (GotItem == true)
204 { 204 {
205 // Execute function 205 // Execute function
206 try 206 try
207 { 207 {
208#if DEBUG 208#if DEBUG
209 eventQueueManager.m_ScriptEngine.Log.Debug(ScriptEngineName, 209 eventQueueManager.m_ScriptEngine.Log.Debug(ScriptEngineName,
210 "Executing event:\r\n" 210 "Executing event:\r\n"
211 + "QIS.localID: " + QIS.localID 211 + "QIS.localID: " + QIS.localID
212 + ", QIS.itemID: " + QIS.itemID 212 + ", QIS.itemID: " + QIS.itemID
213 + ", QIS.functionName: " + 213 + ", QIS.functionName: " +
214 QIS.functionName); 214 QIS.functionName);
215#endif 215#endif
216 LastExecutionStarted = DateTime.Now.Ticks; 216 LastExecutionStarted = DateTime.Now.Ticks;
217 KillCurrentScript = false; 217 KillCurrentScript = false;
218 InExecution = true; 218 InExecution = true;
219 eventQueueManager.m_ScriptEngine.m_ScriptManager.ExecuteEvent(QIS.localID, 219 eventQueueManager.m_ScriptEngine.m_ScriptManager.ExecuteEvent(QIS.localID,
220 QIS.itemID, 220 QIS.itemID,
221 QIS.functionName, 221 QIS.functionName,
222 QIS.llDetectParams, 222 QIS.llDetectParams,
223 QIS.param); 223 QIS.param);
224 InExecution = false; 224 InExecution = false;
225 } 225 }
226 catch (Exception e) 226 catch (Exception e)
227 { 227 {
228 InExecution = false; 228 InExecution = false;
229 // DISPLAY ERROR INWORLD 229 // DISPLAY ERROR INWORLD
230 string text = "Error executing script function \"" + QIS.functionName + 230 string text = "Error executing script function \"" + QIS.functionName +
231 "\":\r\n"; 231 "\":\r\n";
232 if (e.InnerException != null) 232 if (e.InnerException != null)
233 { 233 {
234 // Send inner exception 234 // Send inner exception
235 text += e.InnerException.Message.ToString(); 235 text += e.InnerException.Message.ToString();
236 } 236 }
237 else 237 else
238 { 238 {
239 text += "\r\n"; 239 text += "\r\n";
240 // Send normal 240 // Send normal
241 text += e.Message.ToString(); 241 text += e.Message.ToString();
242 } 242 }
243 if (KillCurrentScript) 243 if (KillCurrentScript)
244 text += "\r\nScript will be deactivated!"; 244 text += "\r\nScript will be deactivated!";
245 245
246 try 246 try
247 { 247 {
248 if (text.Length > 1500) 248 if (text.Length > 1500)
249 text = text.Substring(0, 1500); 249 text = text.Substring(0, 1500);
250 IScriptHost m_host = 250 IScriptHost m_host =
251 eventQueueManager.m_ScriptEngine.World.GetSceneObjectPart(QIS.localID); 251 eventQueueManager.m_ScriptEngine.World.GetSceneObjectPart(QIS.localID);
252 //if (m_host != null) 252 //if (m_host != null)
253 //{ 253 //{
254 eventQueueManager.m_ScriptEngine.World.SimChat(Helpers.StringToField(text), 254 eventQueueManager.m_ScriptEngine.World.SimChat(Helpers.StringToField(text),
255 ChatTypeEnum.Say, 0, 255 ChatTypeEnum.Say, 0,
256 m_host.AbsolutePosition, 256 m_host.AbsolutePosition,
257 m_host.Name, m_host.UUID); 257 m_host.Name, m_host.UUID);
258 } 258 }
259 catch 259 catch
260 { 260 {
261 //} 261 //}
262 //else 262 //else
263 //{ 263 //{
264 // T oconsole 264 // T oconsole
265 eventQueueManager.m_ScriptEngine.Log.Error(ScriptEngineName, 265 eventQueueManager.m_ScriptEngine.Log.Error(ScriptEngineName,
266 "Unable to send text in-world:\r\n" + 266 "Unable to send text in-world:\r\n" +
267 text); 267 text);
268 } 268 }
269 finally 269 finally
270 { 270 {
271 // So we are done sending message in-world 271 // So we are done sending message in-world
272 if (KillCurrentScript) 272 if (KillCurrentScript)
273 { 273 {
274 eventQueueManager.m_ScriptEngine.m_ScriptManager.StopScript( 274 eventQueueManager.m_ScriptEngine.m_ScriptManager.StopScript(
275 QIS.localID, QIS.itemID); 275 QIS.localID, QIS.itemID);
276 } 276 }
277 } 277 }
278 } 278 }
279 finally 279 finally
280 { 280 {
281 InExecution = false; 281 InExecution = false;
282 eventQueueManager.ReleaseLock(QIS.localID); 282 eventQueueManager.ReleaseLock(QIS.localID);
283 } 283 }
284 } 284 }
285 } // Something in queue 285 } // Something in queue
286 } 286 }
287 } 287 }
288 catch (ThreadAbortException tae) 288 catch (ThreadAbortException tae)
289 { 289 {
290 eventQueueManager.m_ScriptEngine.Log.Notice(ScriptEngineName, "ThreadAbortException while executing function."); 290 eventQueueManager.m_ScriptEngine.Log.Notice(ScriptEngineName, "ThreadAbortException while executing function.");
291 } 291 }
292 catch (Exception e) 292 catch (Exception e)
293 { 293 {
294 eventQueueManager.m_ScriptEngine.Log.Error(ScriptEngineName, "Exception in EventQueueThreadLoop: " + e.ToString()); 294 eventQueueManager.m_ScriptEngine.Log.Error(ScriptEngineName, "Exception in EventQueueThreadLoop: " + e.ToString());
295 } 295 }
296 } // while 296 } // while
297 } // try 297 } // try
298 catch (ThreadAbortException) 298 catch (ThreadAbortException)
299 { 299 {
300 //myScriptEngine.Log.Verbose(ScriptEngineName, "EventQueueManager Worker thread killed: " + tae.Message); 300 //myScriptEngine.Log.Verbose(ScriptEngineName, "EventQueueManager Worker thread killed: " + tae.Message);
301 } 301 }
302 } 302 }
303 303
304 /// <summary> 304 /// <summary>
305 /// If set to true then threads and stuff should try to make a graceful exit 305 /// If set to true then threads and stuff should try to make a graceful exit
306 /// </summary> 306 /// </summary>
307 public bool PleaseShutdown 307 public bool PleaseShutdown
308 { 308 {
309 get { return _PleaseShutdown; } 309 get { return _PleaseShutdown; }
310 set { _PleaseShutdown = value; } 310 set { _PleaseShutdown = value; }
311 } 311 }
312 private bool _PleaseShutdown = false; 312 private bool _PleaseShutdown = false;
313 } 313 }
314} 314}