aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ScriptEngine/DotNetEngine/EventQueueManager.cs
diff options
context:
space:
mode:
authorSean Dague2007-09-13 11:41:42 +0000
committerSean Dague2007-09-13 11:41:42 +0000
commitafea5f22055fd645e95c4e1dcad01e68716fa049 (patch)
tree73dbc6fff4cba36c559234b66d24c84e00f3f162 /OpenSim/Region/ScriptEngine/DotNetEngine/EventQueueManager.cs
parentadding eol-style attributes on new files (diff)
downloadopensim-SC-afea5f22055fd645e95c4e1dcad01e68716fa049.zip
opensim-SC-afea5f22055fd645e95c4e1dcad01e68716fa049.tar.gz
opensim-SC-afea5f22055fd645e95c4e1dcad01e68716fa049.tar.bz2
opensim-SC-afea5f22055fd645e95c4e1dcad01e68716fa049.tar.xz
remove ^M, as native storage should be UNIX format, and ^M in/out mashing
will happen on the windows side now that eol-style is correct
Diffstat (limited to 'OpenSim/Region/ScriptEngine/DotNetEngine/EventQueueManager.cs')
-rw-r--r--OpenSim/Region/ScriptEngine/DotNetEngine/EventQueueManager.cs642
1 files changed, 321 insertions, 321 deletions
diff --git a/OpenSim/Region/ScriptEngine/DotNetEngine/EventQueueManager.cs b/OpenSim/Region/ScriptEngine/DotNetEngine/EventQueueManager.cs
index 3dc5d77..955e978 100644
--- a/OpenSim/Region/ScriptEngine/DotNetEngine/EventQueueManager.cs
+++ b/OpenSim/Region/ScriptEngine/DotNetEngine/EventQueueManager.cs
@@ -1,321 +1,321 @@
1/* 1/*
2* Copyright (c) Contributors, http://opensimulator.org/ 2* Copyright (c) Contributors, http://opensimulator.org/
3* See CONTRIBUTORS.TXT for a full list of copyright holders. 3* See CONTRIBUTORS.TXT for a full list of copyright holders.
4* 4*
5* Redistribution and use in source and binary forms, with or without 5* Redistribution and use in source and binary forms, with or without
6* modification, are permitted provided that the following conditions are met: 6* modification, are permitted provided that the following conditions are met:
7* * Redistributions of source code must retain the above copyright 7* * Redistributions of source code must retain the above copyright
8* notice, this list of conditions and the following disclaimer. 8* notice, this list of conditions and the following disclaimer.
9* * Redistributions in binary form must reproduce the above copyright 9* * Redistributions in binary form must reproduce the above copyright
10* notice, this list of conditions and the following disclaimer in the 10* notice, this list of conditions and the following disclaimer in the
11* documentation and/or other materials provided with the distribution. 11* documentation and/or other materials provided with the distribution.
12* * Neither the name of the OpenSim Project nor the 12* * Neither the name of the OpenSim Project nor the
13* names of its contributors may be used to endorse or promote products 13* names of its contributors may be used to endorse or promote products
14* derived from this software without specific prior written permission. 14* derived from this software without specific prior written permission.
15* 15*
16* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS AND ANY 16* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS AND ANY
17* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY 19* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 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 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 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 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. 25* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26* 26*
27*/ 27*/
28/* Original code: Tedd Hansen */ 28/* Original code: Tedd Hansen */
29using System; 29using System;
30using System.Collections.Generic; 30using System.Collections.Generic;
31using System.Text; 31using System.Text;
32using System.Threading; 32using System.Threading;
33using System.Reflection; 33using System.Reflection;
34using OpenSim.Region.Environment.Scenes.Scripting; 34using OpenSim.Region.Environment.Scenes.Scripting;
35using libsecondlife; 35using libsecondlife;
36using OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.LSL; 36using OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.LSL;
37 37
38namespace OpenSim.Region.ScriptEngine.DotNetEngine 38namespace OpenSim.Region.ScriptEngine.DotNetEngine
39{ 39{
40 /// <summary> 40 /// <summary>
41 /// EventQueueManager handles event queues 41 /// EventQueueManager handles event queues
42 /// Events are queued and executed in separate thread 42 /// Events are queued and executed in separate thread
43 /// </summary> 43 /// </summary>
44 [Serializable] 44 [Serializable]
45 class EventQueueManager 45 class EventQueueManager
46 { 46 {
47 /// <summary> 47 /// <summary>
48 /// List of threads processing event queue 48 /// List of threads processing event queue
49 /// </summary> 49 /// </summary>
50 private List<Thread> eventQueueThreads = new List<Thread>(); 50 private List<Thread> eventQueueThreads = new List<Thread>();
51 private object queueLock = new object(); // Mutex lock object 51 private object queueLock = new object(); // Mutex lock object
52 /// <summary> 52 /// <summary>
53 /// How many ms to sleep if queue is empty 53 /// How many ms to sleep if queue is empty
54 /// </summary> 54 /// </summary>
55 private int nothingToDoSleepms = 50; 55 private int nothingToDoSleepms = 50;
56 /// <summary> 56 /// <summary>
57 /// How many threads to process queue with 57 /// How many threads to process queue with
58 /// </summary> 58 /// </summary>
59 private int numberOfThreads = 2; 59 private int numberOfThreads = 2;
60 /// <summary> 60 /// <summary>
61 /// Queue containing events waiting to be executed 61 /// Queue containing events waiting to be executed
62 /// </summary> 62 /// </summary>
63 private Queue<QueueItemStruct> eventQueue = new Queue<QueueItemStruct>(); 63 private Queue<QueueItemStruct> eventQueue = new Queue<QueueItemStruct>();
64 /// <summary> 64 /// <summary>
65 /// Queue item structure 65 /// Queue item structure
66 /// </summary> 66 /// </summary>
67 private struct QueueItemStruct 67 private struct QueueItemStruct
68 { 68 {
69 public uint localID; 69 public uint localID;
70 public LLUUID itemID; 70 public LLUUID itemID;
71 public string functionName; 71 public string functionName;
72 public object[] param; 72 public object[] param;
73 } 73 }
74 74
75 /// <summary> 75 /// <summary>
76 /// List of localID locks for mutex processing of script events 76 /// List of localID locks for mutex processing of script events
77 /// </summary> 77 /// </summary>
78 private List<uint> objectLocks = new List<uint>(); 78 private List<uint> objectLocks = new List<uint>();
79 private object tryLockLock = new object(); // Mutex lock object 79 private object tryLockLock = new object(); // Mutex lock object
80 80
81 private ScriptEngine m_ScriptEngine; 81 private ScriptEngine m_ScriptEngine;
82 public EventQueueManager(ScriptEngine _ScriptEngine) 82 public EventQueueManager(ScriptEngine _ScriptEngine)
83 { 83 {
84 m_ScriptEngine = _ScriptEngine; 84 m_ScriptEngine = _ScriptEngine;
85 85
86 // 86 //
87 // Start event queue processing threads (worker threads) 87 // Start event queue processing threads (worker threads)
88 // 88 //
89 for (int ThreadCount = 0; ThreadCount <= numberOfThreads; ThreadCount++) 89 for (int ThreadCount = 0; ThreadCount <= numberOfThreads; ThreadCount++)
90 { 90 {
91 Thread EventQueueThread = new Thread(EventQueueThreadLoop); 91 Thread EventQueueThread = new Thread(EventQueueThreadLoop);
92 eventQueueThreads.Add(EventQueueThread); 92 eventQueueThreads.Add(EventQueueThread);
93 EventQueueThread.IsBackground = true; 93 EventQueueThread.IsBackground = true;
94 EventQueueThread.Priority = ThreadPriority.BelowNormal; 94 EventQueueThread.Priority = ThreadPriority.BelowNormal;
95 EventQueueThread.Name = "EventQueueManagerThread_" + ThreadCount; 95 EventQueueThread.Name = "EventQueueManagerThread_" + ThreadCount;
96 EventQueueThread.Start(); 96 EventQueueThread.Start();
97 } 97 }
98 } 98 }
99 ~EventQueueManager() 99 ~EventQueueManager()
100 { 100 {
101 101
102 // Kill worker threads 102 // Kill worker threads
103 foreach (Thread EventQueueThread in new System.Collections.ArrayList(eventQueueThreads)) 103 foreach (Thread EventQueueThread in new System.Collections.ArrayList(eventQueueThreads))
104 { 104 {
105 if (EventQueueThread != null && EventQueueThread.IsAlive == true) 105 if (EventQueueThread != null && EventQueueThread.IsAlive == true)
106 { 106 {
107 try 107 try
108 { 108 {
109 EventQueueThread.Abort(); 109 EventQueueThread.Abort();
110 EventQueueThread.Join(); 110 EventQueueThread.Join();
111 } 111 }
112 catch (Exception) 112 catch (Exception)
113 { 113 {
114 //myScriptEngine.Log.Verbose("ScriptEngine", "EventQueueManager Exception killing worker thread: " + e.ToString()); 114 //myScriptEngine.Log.Verbose("ScriptEngine", "EventQueueManager Exception killing worker thread: " + e.ToString());
115 } 115 }
116 } 116 }
117 } 117 }
118 eventQueueThreads.Clear(); 118 eventQueueThreads.Clear();
119 // Todo: Clean up our queues 119 // Todo: Clean up our queues
120 eventQueue.Clear(); 120 eventQueue.Clear();
121 121
122 } 122 }
123 123
124 /// <summary> 124 /// <summary>
125 /// Queue processing thread loop 125 /// Queue processing thread loop
126 /// </summary> 126 /// </summary>
127 private void EventQueueThreadLoop() 127 private void EventQueueThreadLoop()
128 { 128 {
129 //myScriptEngine.m_logger.Verbose("ScriptEngine", "EventQueueManager Worker thread spawned"); 129 //myScriptEngine.m_logger.Verbose("ScriptEngine", "EventQueueManager Worker thread spawned");
130 try 130 try
131 { 131 {
132 QueueItemStruct BlankQIS = new QueueItemStruct(); 132 QueueItemStruct BlankQIS = new QueueItemStruct();
133 while (true) 133 while (true)
134 { 134 {
135 try 135 try
136 { 136 {
137 QueueItemStruct QIS = BlankQIS; 137 QueueItemStruct QIS = BlankQIS;
138 bool GotItem = false; 138 bool GotItem = false;
139 139
140 if (eventQueue.Count == 0) 140 if (eventQueue.Count == 0)
141 { 141 {
142 // Nothing to do? Sleep a bit waiting for something to do 142 // Nothing to do? Sleep a bit waiting for something to do
143 Thread.Sleep(nothingToDoSleepms); 143 Thread.Sleep(nothingToDoSleepms);
144 } 144 }
145 else 145 else
146 { 146 {
147 // Something in queue, process 147 // Something in queue, process
148 //myScriptEngine.m_logger.Verbose("ScriptEngine", "Processing event for localID: " + QIS.localID + ", itemID: " + QIS.itemID + ", FunctionName: " + QIS.FunctionName); 148 //myScriptEngine.m_logger.Verbose("ScriptEngine", "Processing event for localID: " + QIS.localID + ", itemID: " + QIS.itemID + ", FunctionName: " + QIS.FunctionName);
149 149
150 // OBJECT BASED LOCK - TWO THREADS WORKING ON SAME OBJECT IS NOT GOOD 150 // OBJECT BASED LOCK - TWO THREADS WORKING ON SAME OBJECT IS NOT GOOD
151 lock (queueLock) 151 lock (queueLock)
152 { 152 {
153 GotItem = false; 153 GotItem = false;
154 for (int qc = 0; qc < eventQueue.Count; qc++) 154 for (int qc = 0; qc < eventQueue.Count; qc++)
155 { 155 {
156 // Get queue item 156 // Get queue item
157 QIS = eventQueue.Dequeue(); 157 QIS = eventQueue.Dequeue();
158 158
159 // Check if object is being processed by someone else 159 // Check if object is being processed by someone else
160 if (TryLock(QIS.localID) == false) 160 if (TryLock(QIS.localID) == false)
161 { 161 {
162 // Object is already being processed, requeue it 162 // Object is already being processed, requeue it
163 eventQueue.Enqueue(QIS); 163 eventQueue.Enqueue(QIS);
164 } 164 }
165 else 165 else
166 { 166 {
167 // We have lock on an object and can process it 167 // We have lock on an object and can process it
168 GotItem = true; 168 GotItem = true;
169 break; 169 break;
170 } 170 }
171 } // go through queue 171 } // go through queue
172 } // lock 172 } // lock
173 173
174 if (GotItem == true) 174 if (GotItem == true)
175 { 175 {
176 // Execute function 176 // Execute function
177 try 177 try
178 { 178 {
179 m_ScriptEngine.m_ScriptManager.ExecuteEvent(QIS.localID, QIS.itemID, QIS.functionName, QIS.param); 179 m_ScriptEngine.m_ScriptManager.ExecuteEvent(QIS.localID, QIS.itemID, QIS.functionName, QIS.param);
180 } 180 }
181 catch (Exception e) 181 catch (Exception e)
182 { 182 {
183 // DISPLAY ERROR INWORLD 183 // DISPLAY ERROR INWORLD
184 string text = "Error executing script function \"" + QIS.functionName + "\":\r\n"; 184 string text = "Error executing script function \"" + QIS.functionName + "\":\r\n";
185 if (e.InnerException != null) 185 if (e.InnerException != null)
186 { // Send inner exception 186 { // Send inner exception
187 text += e.InnerException.Message.ToString(); 187 text += e.InnerException.Message.ToString();
188 } 188 }
189 else 189 else
190 { // Send normal 190 { // Send normal
191 text += e.Message.ToString(); 191 text += e.Message.ToString();
192 } 192 }
193 try 193 try
194 { 194 {
195 if (text.Length > 1500) 195 if (text.Length > 1500)
196 text = text.Substring(0, 1500); 196 text = text.Substring(0, 1500);
197 IScriptHost m_host = m_ScriptEngine.World.GetSceneObjectPart(QIS.localID); 197 IScriptHost m_host = m_ScriptEngine.World.GetSceneObjectPart(QIS.localID);
198 //if (m_host != null) 198 //if (m_host != null)
199 //{ 199 //{
200 m_ScriptEngine.World.SimChat(Helpers.StringToField(text), 1, m_host.AbsolutePosition, m_host.Name, m_host.UUID); 200 m_ScriptEngine.World.SimChat(Helpers.StringToField(text), 1, m_host.AbsolutePosition, m_host.Name, m_host.UUID);
201 } catch { 201 } catch {
202 //} 202 //}
203 //else 203 //else
204 //{ 204 //{
205 // T oconsole 205 // T oconsole
206 Console.WriteLine("Unable to send text in-world:\r\n" + text); 206 Console.WriteLine("Unable to send text in-world:\r\n" + text);
207 } 207 }
208 208
209 } 209 }
210 finally 210 finally
211 { 211 {
212 ReleaseLock(QIS.localID); 212 ReleaseLock(QIS.localID);
213 } 213 }
214 } 214 }
215 215
216 } // Something in queue 216 } // Something in queue
217 } catch (ThreadAbortException tae) { 217 } catch (ThreadAbortException tae) {
218 throw tae; 218 throw tae;
219 } catch (Exception e) { 219 } catch (Exception e) {
220 Console.WriteLine("Exception in EventQueueThreadLoop: " + e.ToString()); 220 Console.WriteLine("Exception in EventQueueThreadLoop: " + e.ToString());
221 } 221 }
222 } // while 222 } // while
223 } // try 223 } // try
224 catch (ThreadAbortException) 224 catch (ThreadAbortException)
225 { 225 {
226 //myScriptEngine.Log.Verbose("ScriptEngine", "EventQueueManager Worker thread killed: " + tae.Message); 226 //myScriptEngine.Log.Verbose("ScriptEngine", "EventQueueManager Worker thread killed: " + tae.Message);
227 } 227 }
228 } 228 }
229 229
230 /// <summary> 230 /// <summary>
231 /// Try to get a mutex lock on localID 231 /// Try to get a mutex lock on localID
232 /// </summary> 232 /// </summary>
233 /// <param name="localID"></param> 233 /// <param name="localID"></param>
234 /// <returns></returns> 234 /// <returns></returns>
235 private bool TryLock(uint localID) 235 private bool TryLock(uint localID)
236 { 236 {
237 lock (tryLockLock) 237 lock (tryLockLock)
238 { 238 {
239 if (objectLocks.Contains(localID) == true) 239 if (objectLocks.Contains(localID) == true)
240 { 240 {
241 return false; 241 return false;
242 } 242 }
243 else 243 else
244 { 244 {
245 objectLocks.Add(localID); 245 objectLocks.Add(localID);
246 return true; 246 return true;
247 } 247 }
248 } 248 }
249 } 249 }
250 250
251 /// <summary> 251 /// <summary>
252 /// Release mutex lock on localID 252 /// Release mutex lock on localID
253 /// </summary> 253 /// </summary>
254 /// <param name="localID"></param> 254 /// <param name="localID"></param>
255 private void ReleaseLock(uint localID) 255 private void ReleaseLock(uint localID)
256 { 256 {
257 lock (tryLockLock) 257 lock (tryLockLock)
258 { 258 {
259 if (objectLocks.Contains(localID) == true) 259 if (objectLocks.Contains(localID) == true)
260 { 260 {
261 objectLocks.Remove(localID); 261 objectLocks.Remove(localID);
262 } 262 }
263 } 263 }
264 } 264 }
265 265
266 266
267 /// <summary> 267 /// <summary>
268 /// Add event to event execution queue 268 /// Add event to event execution queue
269 /// </summary> 269 /// </summary>
270 /// <param name="localID"></param> 270 /// <param name="localID"></param>
271 /// <param name="FunctionName">Name of the function, will be state + "_event_" + FunctionName</param> 271 /// <param name="FunctionName">Name of the function, will be state + "_event_" + FunctionName</param>
272 /// <param name="param">Array of parameters to match event mask</param> 272 /// <param name="param">Array of parameters to match event mask</param>
273 public void AddToObjectQueue(uint localID, string FunctionName, object[] param) 273 public void AddToObjectQueue(uint localID, string FunctionName, object[] param)
274 { 274 {
275 // Determine all scripts in Object and add to their queue 275 // Determine all scripts in Object and add to their queue
276 //myScriptEngine.m_logger.Verbose("ScriptEngine", "EventQueueManager Adding localID: " + localID + ", FunctionName: " + FunctionName); 276 //myScriptEngine.m_logger.Verbose("ScriptEngine", "EventQueueManager Adding localID: " + localID + ", FunctionName: " + FunctionName);
277 277
278 278
279 // Do we have any scripts in this object at all? If not, return 279 // Do we have any scripts in this object at all? If not, return
280 if (m_ScriptEngine.m_ScriptManager.Scripts.ContainsKey(localID) == false) 280 if (m_ScriptEngine.m_ScriptManager.Scripts.ContainsKey(localID) == false)
281 { 281 {
282 //Console.WriteLine("Event \"" + FunctionName + "\" for localID: " + localID + ". No scripts found on this localID."); 282 //Console.WriteLine("Event \"" + FunctionName + "\" for localID: " + localID + ". No scripts found on this localID.");
283 return; 283 return;
284 } 284 }
285 285
286 Dictionary<LLUUID, LSL_BaseClass>.KeyCollection scriptKeys = m_ScriptEngine.m_ScriptManager.GetScriptKeys(localID); 286 Dictionary<LLUUID, LSL_BaseClass>.KeyCollection scriptKeys = m_ScriptEngine.m_ScriptManager.GetScriptKeys(localID);
287 287
288 foreach ( LLUUID itemID in scriptKeys ) 288 foreach ( LLUUID itemID in scriptKeys )
289 { 289 {
290 // Add to each script in that object 290 // Add to each script in that object
291 // TODO: Some scripts may not subscribe to this event. Should we NOT add it? Does it matter? 291 // TODO: Some scripts may not subscribe to this event. Should we NOT add it? Does it matter?
292 AddToScriptQueue(localID, itemID, FunctionName, param); 292 AddToScriptQueue(localID, itemID, FunctionName, param);
293 } 293 }
294 294
295 } 295 }
296 296
297 /// <summary> 297 /// <summary>
298 /// Add event to event execution queue 298 /// Add event to event execution queue
299 /// </summary> 299 /// </summary>
300 /// <param name="localID"></param> 300 /// <param name="localID"></param>
301 /// <param name="itemID"></param> 301 /// <param name="itemID"></param>
302 /// <param name="FunctionName">Name of the function, will be state + "_event_" + FunctionName</param> 302 /// <param name="FunctionName">Name of the function, will be state + "_event_" + FunctionName</param>
303 /// <param name="param">Array of parameters to match event mask</param> 303 /// <param name="param">Array of parameters to match event mask</param>
304 public void AddToScriptQueue(uint localID, LLUUID itemID, string FunctionName, object[] param) 304 public void AddToScriptQueue(uint localID, LLUUID itemID, string FunctionName, object[] param)
305 { 305 {
306 lock (queueLock) 306 lock (queueLock)
307 { 307 {
308 // Create a structure and add data 308 // Create a structure and add data
309 QueueItemStruct QIS = new QueueItemStruct(); 309 QueueItemStruct QIS = new QueueItemStruct();
310 QIS.localID = localID; 310 QIS.localID = localID;
311 QIS.itemID = itemID; 311 QIS.itemID = itemID;
312 QIS.functionName = FunctionName; 312 QIS.functionName = FunctionName;
313 QIS.param = param; 313 QIS.param = param;
314 314
315 // Add it to queue 315 // Add it to queue
316 eventQueue.Enqueue(QIS); 316 eventQueue.Enqueue(QIS);
317 } 317 }
318 } 318 }
319 319
320 } 320 }
321} 321}