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