aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/EventQueueManager.cs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/EventQueueManager.cs (renamed from OpenSim/Region/ScriptEngine/DotNetEngine/EventQueueManager.cs)725
1 files changed, 362 insertions, 363 deletions
diff --git a/OpenSim/Region/ScriptEngine/DotNetEngine/EventQueueManager.cs b/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/EventQueueManager.cs
index e7cb489..62194df 100644
--- a/OpenSim/Region/ScriptEngine/DotNetEngine/EventQueueManager.cs
+++ b/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/EventQueueManager.cs
@@ -1,364 +1,363 @@
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; 30using System.Collections;
31using System.Collections.Generic; 31using System.Collections.Generic;
32using System.Threading; 32using System.Threading;
33using libsecondlife; 33using libsecondlife;
34using OpenSim.Framework; 34using OpenSim.Framework;
35using OpenSim.Region.Environment.Scenes.Scripting; 35using OpenSim.Region.Environment.Scenes.Scripting;
36using OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.LSL; 36
37 37namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
38namespace OpenSim.Region.ScriptEngine.DotNetEngine 38{
39{ 39 /// <summary>
40 /// <summary> 40 /// EventQueueManager handles event queues
41 /// EventQueueManager handles event queues 41 /// Events are queued and executed in separate thread
42 /// Events are queued and executed in separate thread 42 /// </summary>
43 /// </summary> 43 [Serializable]
44 [Serializable] 44 public class EventQueueManager
45 internal class EventQueueManager 45 {
46 { 46
47 47 //
48 // 48 // Class is instanced in "ScriptEngine" and used by "EventManager" also instanced in "ScriptEngine".
49 // Class is instanced in "ScriptEngine" and used by "EventManager" also instanced in "ScriptEngine". 49 //
50 // 50 // Class purpose is to queue and execute functions that are received by "EventManager":
51 // Class purpose is to queue and execute functions that are received by "EventManager": 51 // - allowing "EventManager" to release its event thread immediately, thus not interrupting server execution.
52 // - allowing "EventManager" to release its event thread immediately, thus not interrupting server execution. 52 // - allowing us to prioritize and control execution of script functions.
53 // - allowing us to prioritize and control execution of script functions. 53 // Class can use multiple threads for simultaneous execution. Mutexes are used for thread safety.
54 // Class can use multiple threads for simultaneous execution. Mutexes are used for thread safety. 54 //
55 // 55 // 1. Hold an execution queue for scripts
56 // 1. Hold an execution queue for scripts 56 // 2. Use threads to process queue, each thread executes one script function on each pass.
57 // 2. Use threads to process queue, each thread executes one script function on each pass. 57 // 3. Catch any script error and process it
58 // 3. Catch any script error and process it 58 //
59 // 59 //
60 // 60 // Notes:
61 // Notes: 61 // * Current execution load balancing is optimized for 1 thread, and can cause unfair execute balancing between scripts.
62 // * Current execution load balancing is optimized for 1 thread, and can cause unfair execute balancing between scripts. 62 // Not noticeable unless server is under high load.
63 // Not noticeable unless server is under high load. 63 // * This class contains the number of threads used for script executions. Since we are not microthreading scripts yet,
64 // * This class contains the number of threads used for script executions. Since we are not microthreading scripts yet, 64 // increase number of threads to allow more concurrent script executions in OpenSim.
65 // increase number of threads to allow more concurrent script executions in OpenSim. 65 //
66 // 66
67 67
68 68 /// <summary>
69 /// <summary> 69 /// List of threads processing event queue
70 /// List of threads processing event queue 70 /// </summary>
71 /// </summary> 71 private List<Thread> eventQueueThreads = new List<Thread>();
72 private List<Thread> eventQueueThreads = new List<Thread>(); 72
73 73 private object queueLock = new object(); // Mutex lock object
74 private object queueLock = new object(); // Mutex lock object 74
75 75 /// <summary>
76 /// <summary> 76 /// How many ms to sleep if queue is empty
77 /// How many ms to sleep if queue is empty 77 /// </summary>
78 /// </summary> 78 private int nothingToDoSleepms = 50;
79 private int nothingToDoSleepms = 50; 79
80 80 /// <summary>
81 /// <summary> 81 /// How many threads to process queue with
82 /// How many threads to process queue with 82 /// </summary>
83 /// </summary> 83 private int numberOfThreads = 2;
84 private int numberOfThreads = 2; 84
85 85 /// <summary>
86 /// <summary> 86 /// Queue containing events waiting to be executed
87 /// Queue containing events waiting to be executed 87 /// </summary>
88 /// </summary> 88 private Queue<QueueItemStruct> eventQueue = new Queue<QueueItemStruct>();
89 private Queue<QueueItemStruct> eventQueue = new Queue<QueueItemStruct>(); 89
90 90 /// <summary>
91 /// <summary> 91 /// Queue item structure
92 /// Queue item structure 92 /// </summary>
93 /// </summary> 93 private struct QueueItemStruct
94 private struct QueueItemStruct 94 {
95 { 95 public uint localID;
96 public uint localID; 96 public LLUUID itemID;
97 public LLUUID itemID; 97 public string functionName;
98 public string functionName; 98 public object[] param;
99 public object[] param; 99 }
100 } 100
101 101 /// <summary>
102 /// <summary> 102 /// List of localID locks for mutex processing of script events
103 /// List of localID locks for mutex processing of script events 103 /// </summary>
104 /// </summary> 104 private List<uint> objectLocks = new List<uint>();
105 private List<uint> objectLocks = new List<uint>(); 105
106 106 private object tryLockLock = new object(); // Mutex lock object
107 private object tryLockLock = new object(); // Mutex lock object 107
108 108 private ScriptEngine m_ScriptEngine;
109 private ScriptEngine m_ScriptEngine; 109
110 110 public EventQueueManager(ScriptEngine _ScriptEngine)
111 public EventQueueManager(ScriptEngine _ScriptEngine) 111 {
112 { 112 m_ScriptEngine = _ScriptEngine;
113 m_ScriptEngine = _ScriptEngine; 113
114 114 //
115 // 115 // Start event queue processing threads (worker threads)
116 // Start event queue processing threads (worker threads) 116 //
117 // 117 for (int ThreadCount = 0; ThreadCount <= numberOfThreads; ThreadCount++)
118 for (int ThreadCount = 0; ThreadCount <= numberOfThreads; ThreadCount++) 118 {
119 { 119 Thread EventQueueThread = new Thread(EventQueueThreadLoop);
120 Thread EventQueueThread = new Thread(EventQueueThreadLoop); 120 eventQueueThreads.Add(EventQueueThread);
121 eventQueueThreads.Add(EventQueueThread); 121 EventQueueThread.IsBackground = true;
122 EventQueueThread.IsBackground = true; 122 EventQueueThread.Priority = ThreadPriority.BelowNormal;
123 EventQueueThread.Priority = ThreadPriority.BelowNormal; 123 EventQueueThread.Name = "EventQueueManagerThread_" + ThreadCount;
124 EventQueueThread.Name = "EventQueueManagerThread_" + ThreadCount; 124 EventQueueThread.Start();
125 EventQueueThread.Start(); 125 }
126 } 126 }
127 } 127
128 128 ~EventQueueManager()
129 ~EventQueueManager() 129 {
130 { 130 // Kill worker threads
131 // Kill worker threads 131 foreach (Thread EventQueueThread in new ArrayList(eventQueueThreads))
132 foreach (Thread EventQueueThread in new ArrayList(eventQueueThreads)) 132 {
133 { 133 if (EventQueueThread != null && EventQueueThread.IsAlive == true)
134 if (EventQueueThread != null && EventQueueThread.IsAlive == true) 134 {
135 { 135 try
136 try 136 {
137 { 137 EventQueueThread.Abort();
138 EventQueueThread.Abort(); 138 EventQueueThread.Join();
139 EventQueueThread.Join(); 139 }
140 } 140 catch (Exception)
141 catch (Exception) 141 {
142 { 142 //myScriptEngine.Log.Verbose("ScriptEngine", "EventQueueManager Exception killing worker thread: " + e.ToString());
143 //myScriptEngine.Log.Verbose("ScriptEngine", "EventQueueManager Exception killing worker thread: " + e.ToString()); 143 }
144 } 144 }
145 } 145 }
146 } 146 eventQueueThreads.Clear();
147 eventQueueThreads.Clear(); 147 // Todo: Clean up our queues
148 // Todo: Clean up our queues 148 eventQueue.Clear();
149 eventQueue.Clear(); 149 }
150 } 150
151 151 /// <summary>
152 /// <summary> 152 /// Queue processing thread loop
153 /// Queue processing thread loop 153 /// </summary>
154 /// </summary> 154 private void EventQueueThreadLoop()
155 private void EventQueueThreadLoop() 155 {
156 { 156 //myScriptEngine.m_logger.Verbose("ScriptEngine", "EventQueueManager Worker thread spawned");
157 //myScriptEngine.m_logger.Verbose("ScriptEngine", "EventQueueManager Worker thread spawned"); 157 try
158 try 158 {
159 { 159 QueueItemStruct BlankQIS = new QueueItemStruct();
160 QueueItemStruct BlankQIS = new QueueItemStruct(); 160 while (true)
161 while (true) 161 {
162 { 162 try
163 try 163 {
164 { 164 QueueItemStruct QIS = BlankQIS;
165 QueueItemStruct QIS = BlankQIS; 165 bool GotItem = false;
166 bool GotItem = false; 166
167 167 if (eventQueue.Count == 0)
168 if (eventQueue.Count == 0) 168 {
169 { 169 // Nothing to do? Sleep a bit waiting for something to do
170 // Nothing to do? Sleep a bit waiting for something to do 170 Thread.Sleep(nothingToDoSleepms);
171 Thread.Sleep(nothingToDoSleepms); 171 }
172 } 172 else
173 else 173 {
174 { 174 // Something in queue, process
175 // Something in queue, process 175 //myScriptEngine.m_logger.Verbose("ScriptEngine", "Processing event for localID: " + QIS.localID + ", itemID: " + QIS.itemID + ", FunctionName: " + QIS.FunctionName);
176 //myScriptEngine.m_logger.Verbose("ScriptEngine", "Processing event for localID: " + QIS.localID + ", itemID: " + QIS.itemID + ", FunctionName: " + QIS.FunctionName); 176
177 177 // OBJECT BASED LOCK - TWO THREADS WORKING ON SAME OBJECT IS NOT GOOD
178 // OBJECT BASED LOCK - TWO THREADS WORKING ON SAME OBJECT IS NOT GOOD 178 lock (queueLock)
179 lock (queueLock) 179 {
180 { 180 GotItem = false;
181 GotItem = false; 181 for (int qc = 0; qc < eventQueue.Count; qc++)
182 for (int qc = 0; qc < eventQueue.Count; qc++) 182 {
183 { 183 // Get queue item
184 // Get queue item 184 QIS = eventQueue.Dequeue();
185 QIS = eventQueue.Dequeue(); 185
186 186 // Check if object is being processed by someone else
187 // Check if object is being processed by someone else 187 if (TryLock(QIS.localID) == false)
188 if (TryLock(QIS.localID) == false) 188 {
189 { 189 // Object is already being processed, requeue it
190 // Object is already being processed, requeue it 190 eventQueue.Enqueue(QIS);
191 eventQueue.Enqueue(QIS); 191 }
192 } 192 else
193 else 193 {
194 { 194 // We have lock on an object and can process it
195 // We have lock on an object and can process it 195 GotItem = true;
196 GotItem = true; 196 break;
197 break; 197 }
198 } 198 } // go through queue
199 } // go through queue 199 } // lock
200 } // lock 200
201 201 if (GotItem == true)
202 if (GotItem == true) 202 {
203 { 203 // Execute function
204 // Execute function 204 try
205 try 205 {
206 { 206#if DEBUG
207#if DEBUG 207 m_ScriptEngine.Log.Debug("ScriptEngine", "Executing event:\r\n"
208 m_ScriptEngine.Log.Debug("ScriptEngine", "Executing event:\r\n" 208 + "QIS.localID: " + QIS.localID
209 + "QIS.localID: " + QIS.localID 209 + ", QIS.itemID: " + QIS.itemID
210 + ", QIS.itemID: " + QIS.itemID 210 + ", QIS.functionName: " + QIS.functionName);
211 + ", QIS.functionName: " + QIS.functionName); 211#endif
212#endif 212 m_ScriptEngine.m_ScriptManager.ExecuteEvent(QIS.localID, QIS.itemID,
213 m_ScriptEngine.m_ScriptManager.ExecuteEvent(QIS.localID, QIS.itemID, 213 QIS.functionName, QIS.param);
214 QIS.functionName, QIS.param); 214 }
215 } 215 catch (Exception e)
216 catch (Exception e) 216 {
217 { 217 // DISPLAY ERROR INWORLD
218 // DISPLAY ERROR INWORLD 218 string text = "Error executing script function \"" + QIS.functionName + "\":\r\n";
219 string text = "Error executing script function \"" + QIS.functionName + "\":\r\n"; 219 //if (e.InnerException != null)
220 //if (e.InnerException != null) 220 //{
221 //{ 221 // Send inner exception
222 // Send inner exception 222 text += e.InnerException.Message.ToString();
223 text += e.InnerException.Message.ToString(); 223 //}
224 //} 224 //else
225 //else 225 //{
226 //{ 226 text += "\r\n";
227 text += "\r\n"; 227 // Send normal
228 // Send normal 228 text += e.Message.ToString();
229 text += e.Message.ToString(); 229 //}
230 //} 230 try
231 try 231 {
232 { 232 if (text.Length > 1500)
233 if (text.Length > 1500) 233 text = text.Substring(0, 1500);
234 text = text.Substring(0, 1500); 234 IScriptHost m_host = m_ScriptEngine.World.GetSceneObjectPart(QIS.localID);
235 IScriptHost m_host = m_ScriptEngine.World.GetSceneObjectPart(QIS.localID); 235 //if (m_host != null)
236 //if (m_host != null) 236 //{
237 //{ 237 m_ScriptEngine.World.SimChat(Helpers.StringToField(text), ChatTypeEnum.Say, 0,
238 m_ScriptEngine.World.SimChat(Helpers.StringToField(text), ChatTypeEnum.Say, 0, 238 m_host.AbsolutePosition, m_host.Name, m_host.UUID);
239 m_host.AbsolutePosition, m_host.Name, m_host.UUID); 239 }
240 } 240 catch
241 catch 241 {
242 { 242 //}
243 //} 243 //else
244 //else 244 //{
245 //{ 245 // T oconsole
246 // T oconsole 246 m_ScriptEngine.Log.Error("ScriptEngine",
247 m_ScriptEngine.Log.Error("ScriptEngine", 247 "Unable to send text in-world:\r\n" + text);
248 "Unable to send text in-world:\r\n" + text); 248 }
249 } 249 }
250 } 250 finally
251 finally 251 {
252 { 252 ReleaseLock(QIS.localID);
253 ReleaseLock(QIS.localID); 253 }
254 } 254 }
255 } 255 } // Something in queue
256 } // Something in queue 256 }
257 } 257 catch (ThreadAbortException tae)
258 catch (ThreadAbortException tae) 258 {
259 { 259 throw tae;
260 throw tae; 260 }
261 } 261 catch (Exception e)
262 catch (Exception e) 262 {
263 { 263 m_ScriptEngine.Log.Error("ScriptEngine", "Exception in EventQueueThreadLoop: " + e.ToString());
264 m_ScriptEngine.Log.Error("ScriptEngine", "Exception in EventQueueThreadLoop: " + e.ToString()); 264 }
265 } 265 } // while
266 } // while 266 } // try
267 } // try 267 catch (ThreadAbortException)
268 catch (ThreadAbortException) 268 {
269 { 269 //myScriptEngine.Log.Verbose("ScriptEngine", "EventQueueManager Worker thread killed: " + tae.Message);
270 //myScriptEngine.Log.Verbose("ScriptEngine", "EventQueueManager Worker thread killed: " + tae.Message); 270 }
271 } 271 }
272 } 272
273 273 /// <summary>
274 /// <summary> 274 /// Try to get a mutex lock on localID
275 /// Try to get a mutex lock on localID 275 /// </summary>
276 /// </summary> 276 /// <param name="localID"></param>
277 /// <param name="localID"></param> 277 /// <returns></returns>
278 /// <returns></returns> 278 private bool TryLock(uint localID)
279 private bool TryLock(uint localID) 279 {
280 { 280 lock (tryLockLock)
281 lock (tryLockLock) 281 {
282 { 282 if (objectLocks.Contains(localID) == true)
283 if (objectLocks.Contains(localID) == true) 283 {
284 { 284 return false;
285 return false; 285 }
286 } 286 else
287 else 287 {
288 { 288 objectLocks.Add(localID);
289 objectLocks.Add(localID); 289 return true;
290 return true; 290 }
291 } 291 }
292 } 292 }
293 } 293
294 294 /// <summary>
295 /// <summary> 295 /// Release mutex lock on localID
296 /// Release mutex lock on localID 296 /// </summary>
297 /// </summary> 297 /// <param name="localID"></param>
298 /// <param name="localID"></param> 298 private void ReleaseLock(uint localID)
299 private void ReleaseLock(uint localID) 299 {
300 { 300 lock (tryLockLock)
301 lock (tryLockLock) 301 {
302 { 302 if (objectLocks.Contains(localID) == true)
303 if (objectLocks.Contains(localID) == true) 303 {
304 { 304 objectLocks.Remove(localID);
305 objectLocks.Remove(localID); 305 }
306 } 306 }
307 } 307 }
308 } 308
309 309
310 310 /// <summary>
311 /// <summary> 311 /// Add event to event execution queue
312 /// Add event to event execution queue 312 /// </summary>
313 /// </summary> 313 /// <param name="localID"></param>
314 /// <param name="localID"></param> 314 /// <param name="FunctionName">Name of the function, will be state + "_event_" + FunctionName</param>
315 /// <param name="FunctionName">Name of the function, will be state + "_event_" + FunctionName</param> 315 /// <param name="param">Array of parameters to match event mask</param>
316 /// <param name="param">Array of parameters to match event mask</param> 316 public void AddToObjectQueue(uint localID, string FunctionName, params object[] param)
317 public void AddToObjectQueue(uint localID, string FunctionName, params object[] param) 317 {
318 { 318 // Determine all scripts in Object and add to their queue
319 // Determine all scripts in Object and add to their queue 319 //myScriptEngine.m_logger.Verbose("ScriptEngine", "EventQueueManager Adding localID: " + localID + ", FunctionName: " + FunctionName);
320 //myScriptEngine.m_logger.Verbose("ScriptEngine", "EventQueueManager Adding localID: " + localID + ", FunctionName: " + FunctionName); 320
321 321
322 322 // Do we have any scripts in this object at all? If not, return
323 // Do we have any scripts in this object at all? If not, return 323 if (m_ScriptEngine.m_ScriptManager.Scripts.ContainsKey(localID) == false)
324 if (m_ScriptEngine.m_ScriptManager.Scripts.ContainsKey(localID) == false) 324 {
325 { 325 //Console.WriteLine("Event \"" + FunctionName + "\" for localID: " + localID + ". No scripts found on this localID.");
326 //Console.WriteLine("Event \"" + FunctionName + "\" for localID: " + localID + ". No scripts found on this localID."); 326 return;
327 return; 327 }
328 } 328
329 329 Dictionary<LLUUID, IScript>.KeyCollection scriptKeys =
330 Dictionary<LLUUID, LSL_BaseClass>.KeyCollection scriptKeys = 330 m_ScriptEngine.m_ScriptManager.GetScriptKeys(localID);
331 m_ScriptEngine.m_ScriptManager.GetScriptKeys(localID); 331
332 332 foreach (LLUUID itemID in scriptKeys)
333 foreach (LLUUID itemID in scriptKeys) 333 {
334 { 334 // Add to each script in that object
335 // Add to each script in that object 335 // TODO: Some scripts may not subscribe to this event. Should we NOT add it? Does it matter?
336 // TODO: Some scripts may not subscribe to this event. Should we NOT add it? Does it matter? 336 AddToScriptQueue(localID, itemID, FunctionName, param);
337 AddToScriptQueue(localID, itemID, FunctionName, param); 337 }
338 } 338 }
339 } 339
340 340 /// <summary>
341 /// <summary> 341 /// Add event to event execution queue
342 /// Add event to event execution queue 342 /// </summary>
343 /// </summary> 343 /// <param name="localID"></param>
344 /// <param name="localID"></param> 344 /// <param name="itemID"></param>
345 /// <param name="itemID"></param> 345 /// <param name="FunctionName">Name of the function, will be state + "_event_" + FunctionName</param>
346 /// <param name="FunctionName">Name of the function, will be state + "_event_" + FunctionName</param> 346 /// <param name="param">Array of parameters to match event mask</param>
347 /// <param name="param">Array of parameters to match event mask</param> 347 public void AddToScriptQueue(uint localID, LLUUID itemID, string FunctionName, params object[] param)
348 public void AddToScriptQueue(uint localID, LLUUID itemID, string FunctionName, params object[] param) 348 {
349 { 349 lock (queueLock)
350 lock (queueLock) 350 {
351 { 351 // Create a structure and add data
352 // Create a structure and add data 352 QueueItemStruct QIS = new QueueItemStruct();
353 QueueItemStruct QIS = new QueueItemStruct(); 353 QIS.localID = localID;
354 QIS.localID = localID; 354 QIS.itemID = itemID;
355 QIS.itemID = itemID; 355 QIS.functionName = FunctionName;
356 QIS.functionName = FunctionName; 356 QIS.param = param;
357 QIS.param = param; 357
358 358 // Add it to queue
359 // Add it to queue 359 eventQueue.Enqueue(QIS);
360 eventQueue.Enqueue(QIS); 360 }
361 } 361 }
362 } 362 }
363 }
364} \ No newline at end of file 363} \ No newline at end of file