diff options
author | Tedd Hansen | 2008-01-12 14:30:22 +0000 |
---|---|---|
committer | Tedd Hansen | 2008-01-12 14:30:22 +0000 |
commit | bacbade369a5244f9bcc611488b59f3bd4c8a564 (patch) | |
tree | 2cd909eff401066a69dba96615cbf736fdd73be5 /OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/EventQueueManager.cs | |
parent | * Trying something to see if it helps teleports and border crossings (diff) | |
download | opensim-SC_OLD-bacbade369a5244f9bcc611488b59f3bd4c8a564.zip opensim-SC_OLD-bacbade369a5244f9bcc611488b59f3bd4c8a564.tar.gz opensim-SC_OLD-bacbade369a5244f9bcc611488b59f3bd4c8a564.tar.bz2 opensim-SC_OLD-bacbade369a5244f9bcc611488b59f3bd4c8a564.tar.xz |
Major reorganizing of DotNetEngine. Moved common script engine parts to ScriptEngine.Common, only .Net-specific code in DotNetEngine. AppDomains, event handling, event execution queue and multithreading, script load/unload queue, etc has been moved to ScriptEngine.Common.
Loads of things has been put into interfaces instead of the specific class.
We are now one step closer to ScriptServer, and its very easy to implement new script languages. Just a few lines required to make them a OpenSim script module with all its glory.
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 */ |
29 | using System; | 29 | using System; |
30 | using System.Collections; | 30 | using System.Collections; |
31 | using System.Collections.Generic; | 31 | using System.Collections.Generic; |
32 | using System.Threading; | 32 | using System.Threading; |
33 | using libsecondlife; | 33 | using libsecondlife; |
34 | using OpenSim.Framework; | 34 | using OpenSim.Framework; |
35 | using OpenSim.Region.Environment.Scenes.Scripting; | 35 | using OpenSim.Region.Environment.Scenes.Scripting; |
36 | using OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.LSL; | 36 | |
37 | 37 | namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase | |
38 | namespace 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 |