diff options
author | Tedd Hansen | 2008-02-22 14:09:38 +0000 |
---|---|---|
committer | Tedd Hansen | 2008-02-22 14:09:38 +0000 |
commit | a43bb10000ca0b58af2f33750ea17cb94bfbad7d (patch) | |
tree | 9f913c185d3ee90a3e88507bbd32e7c6bbab0c9d /OpenSim/Region/ScriptEngine/Common/ScriptEngineBase | |
parent | Maintenance thread in charge of loading/unloading of scripts. 1 thread less p... (diff) | |
download | opensim-SC_OLD-a43bb10000ca0b58af2f33750ea17cb94bfbad7d.zip opensim-SC_OLD-a43bb10000ca0b58af2f33750ea17cb94bfbad7d.tar.gz opensim-SC_OLD-a43bb10000ca0b58af2f33750ea17cb94bfbad7d.tar.bz2 opensim-SC_OLD-a43bb10000ca0b58af2f33750ea17cb94bfbad7d.tar.xz |
Execution threads are now shared between regions too. Default thread count regardless of number of regions is now 3. This will save you around 33 threads for a normal 3x3 region server.
But, this is totally completely untested. So it probably won't work for another patch or five.
Diffstat (limited to 'OpenSim/Region/ScriptEngine/Common/ScriptEngineBase')
3 files changed, 229 insertions, 242 deletions
diff --git a/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/EventQueueManager.cs b/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/EventQueueManager.cs index e3d448c..581c7a0 100644 --- a/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/EventQueueManager.cs +++ b/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/EventQueueManager.cs | |||
@@ -45,7 +45,7 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase | |||
45 | public class EventQueueManager : iScriptEngineFunctionModule | 45 | public class EventQueueManager : iScriptEngineFunctionModule |
46 | { | 46 | { |
47 | // | 47 | // |
48 | // Class is instanced in "ScriptEngine" and used by "EventManager" also instanced in "ScriptEngine". | 48 | // Class is instanced in "ScriptEngine" and used by "EventManager" which is also instanced in "ScriptEngine". |
49 | // | 49 | // |
50 | // Class purpose is to queue and execute functions that are received by "EventManager": | 50 | // 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. | 51 | // - allowing "EventManager" to release its event thread immediately, thus not interrupting server execution. |
@@ -68,25 +68,25 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase | |||
68 | /// List of threads (classes) processing event queue | 68 | /// List of threads (classes) processing event queue |
69 | /// Note that this may or may not be a reference to a static object depending on PrivateRegionThreads config setting. | 69 | /// Note that this may or may not be a reference to a static object depending on PrivateRegionThreads config setting. |
70 | /// </summary> | 70 | /// </summary> |
71 | internal List<EventQueueThreadClass> eventQueueThreads; // Thread pool that we work on | 71 | internal static List<EventQueueThreadClass> eventQueueThreads; // Thread pool that we work on |
72 | /// <summary> | 72 | /// <summary> |
73 | /// Locking access to eventQueueThreads AND staticGlobalEventQueueThreads. | 73 | /// Locking access to eventQueueThreads AND staticGlobalEventQueueThreads. |
74 | /// </summary> | 74 | /// </summary> |
75 | // private object eventQueueThreadsLock = new object(); | 75 | // private object eventQueueThreadsLock = new object(); |
76 | // Static objects for referencing the objects above if we don't have private threads: | 76 | // Static objects for referencing the objects above if we don't have private threads: |
77 | internal static List<EventQueueThreadClass> staticEventQueueThreads; // A static reference used if we don't use private threads | 77 | //internal static List<EventQueueThreadClass> staticEventQueueThreads; // A static reference used if we don't use private threads |
78 | // internal static object staticEventQueueThreadsLock; // Statick lock object reference for same reason | 78 | // internal static object staticEventQueueThreadsLock; // Statick lock object reference for same reason |
79 | 79 | ||
80 | /// <summary> | 80 | /// <summary> |
81 | /// Global static list of all threads (classes) processing event queue -- used by max enforcment thread | 81 | /// Global static list of all threads (classes) processing event queue -- used by max enforcment thread |
82 | /// </summary> | 82 | /// </summary> |
83 | private List<EventQueueThreadClass> staticGlobalEventQueueThreads = new List<EventQueueThreadClass>(); | 83 | //private List<EventQueueThreadClass> staticGlobalEventQueueThreads = new List<EventQueueThreadClass>(); |
84 | 84 | ||
85 | /// <summary> | 85 | /// <summary> |
86 | /// Used internally to specify how many threads should exit gracefully | 86 | /// Used internally to specify how many threads should exit gracefully |
87 | /// </summary> | 87 | /// </summary> |
88 | public int ThreadsToExit; | 88 | public static int ThreadsToExit; |
89 | public object ThreadsToExitLock = new object(); | 89 | public static object ThreadsToExitLock = new object(); |
90 | 90 | ||
91 | 91 | ||
92 | //public object queueLock = new object(); // Mutex lock object | 92 | //public object queueLock = new object(); // Mutex lock object |
@@ -94,14 +94,14 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase | |||
94 | /// <summary> | 94 | /// <summary> |
95 | /// How many threads to process queue with | 95 | /// How many threads to process queue with |
96 | /// </summary> | 96 | /// </summary> |
97 | internal int numberOfThreads; | 97 | internal static int numberOfThreads; |
98 | 98 | ||
99 | internal static int EventExecutionMaxQueueSize; | 99 | internal static int EventExecutionMaxQueueSize; |
100 | 100 | ||
101 | /// <summary> | 101 | /// <summary> |
102 | /// Maximum time one function can use for execution before we perform a thread kill. | 102 | /// Maximum time one function can use for execution before we perform a thread kill. |
103 | /// </summary> | 103 | /// </summary> |
104 | private int maxFunctionExecutionTimems | 104 | private static int maxFunctionExecutionTimems |
105 | { | 105 | { |
106 | get { return (int)(maxFunctionExecutionTimens / 10000); } | 106 | get { return (int)(maxFunctionExecutionTimens / 10000); } |
107 | set { maxFunctionExecutionTimens = value * 10000; } | 107 | set { maxFunctionExecutionTimens = value * 10000; } |
@@ -111,15 +111,15 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase | |||
111 | /// Contains nanoseconds version of maxFunctionExecutionTimems so that it matches time calculations better (performance reasons). | 111 | /// Contains nanoseconds version of maxFunctionExecutionTimems so that it matches time calculations better (performance reasons). |
112 | /// WARNING! ONLY UPDATE maxFunctionExecutionTimems, NEVER THIS DIRECTLY. | 112 | /// WARNING! ONLY UPDATE maxFunctionExecutionTimems, NEVER THIS DIRECTLY. |
113 | /// </summary> | 113 | /// </summary> |
114 | public long maxFunctionExecutionTimens; | 114 | public static long maxFunctionExecutionTimens; |
115 | /// <summary> | 115 | /// <summary> |
116 | /// Enforce max execution time | 116 | /// Enforce max execution time |
117 | /// </summary> | 117 | /// </summary> |
118 | public bool EnforceMaxExecutionTime; | 118 | public static bool EnforceMaxExecutionTime; |
119 | /// <summary> | 119 | /// <summary> |
120 | /// Kill script (unload) when it exceeds execution time | 120 | /// Kill script (unload) when it exceeds execution time |
121 | /// </summary> | 121 | /// </summary> |
122 | private bool KillScriptOnMaxFunctionExecutionTime; | 122 | private static bool KillScriptOnMaxFunctionExecutionTime; |
123 | 123 | ||
124 | /// <summary> | 124 | /// <summary> |
125 | /// List of localID locks for mutex processing of script events | 125 | /// List of localID locks for mutex processing of script events |
@@ -172,33 +172,8 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase | |||
172 | { | 172 | { |
173 | m_ScriptEngine = _ScriptEngine; | 173 | m_ScriptEngine = _ScriptEngine; |
174 | 174 | ||
175 | // TODO: We need to move from single EventQueueManager to list of it in to share threads | 175 | eventQueueThreads = new List<EventQueueThreadClass>(); |
176 | bool PrivateRegionThreads = true; // m_ScriptEngine.ScriptConfigSource.GetBoolean("PrivateRegionThreads", false); | ||
177 | |||
178 | // Create thread pool list and lock object | ||
179 | // Determine from config if threads should be dedicated to regions or shared | ||
180 | if (PrivateRegionThreads) | ||
181 | { | ||
182 | // PRIVATE THREAD POOL PER REGION | ||
183 | eventQueueThreads = new List<EventQueueThreadClass>(); | ||
184 | // eventQueueThreadsLock = new object(); | ||
185 | } | ||
186 | else | ||
187 | { | ||
188 | // SHARED THREAD POOL | ||
189 | // Crate the static objects | ||
190 | if (staticEventQueueThreads == null) | ||
191 | staticEventQueueThreads = new List<EventQueueThreadClass>(); | ||
192 | // if (staticEventQueueThreadsLock == null) | ||
193 | // staticEventQueueThreadsLock = new object(); | ||
194 | |||
195 | // Now reference our locals to them | ||
196 | eventQueueThreads = staticEventQueueThreads; | ||
197 | //eventQueueThreadsLock = staticEventQueueThreadsLock; | ||
198 | } | ||
199 | |||
200 | ReadConfig(); | 176 | ReadConfig(); |
201 | |||
202 | } | 177 | } |
203 | 178 | ||
204 | public void ReadConfig() | 179 | public void ReadConfig() |
@@ -230,18 +205,18 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase | |||
230 | 205 | ||
231 | private void Stop() | 206 | private void Stop() |
232 | { | 207 | { |
233 | if (eventQueueThreads != null && eventQueueThreads != null) | 208 | if (eventQueueThreads != null) |
234 | { | 209 | { |
235 | // Kill worker threads | 210 | // Kill worker threads |
236 | //lock (eventQueueThreads) | 211 | lock (eventQueueThreads) |
237 | //{ | 212 | { |
238 | foreach (EventQueueThreadClass EventQueueThread in new ArrayList(eventQueueThreads)) | 213 | foreach (EventQueueThreadClass EventQueueThread in new ArrayList(eventQueueThreads)) |
239 | { | 214 | { |
240 | AbortThreadClass(EventQueueThread); | 215 | AbortThreadClass(EventQueueThread); |
241 | } | 216 | } |
242 | //eventQueueThreads.Clear(); | 217 | //eventQueueThreads.Clear(); |
243 | //staticGlobalEventQueueThreads.Clear(); | 218 | //staticGlobalEventQueueThreads.Clear(); |
244 | //} | 219 | } |
245 | } | 220 | } |
246 | 221 | ||
247 | // Remove all entries from our event queue | 222 | // Remove all entries from our event queue |
@@ -256,9 +231,8 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase | |||
256 | #region " Start / stop script execution threads (ThreadClasses) " | 231 | #region " Start / stop script execution threads (ThreadClasses) " |
257 | private void StartNewThreadClass() | 232 | private void StartNewThreadClass() |
258 | { | 233 | { |
259 | EventQueueThreadClass eqtc = new EventQueueThreadClass(this); | 234 | EventQueueThreadClass eqtc = new EventQueueThreadClass(); |
260 | eventQueueThreads.Add(eqtc); | 235 | eventQueueThreads.Add(eqtc); |
261 | staticGlobalEventQueueThreads.Add(eqtc); | ||
262 | m_ScriptEngine.Log.Debug("[" + m_ScriptEngine.ScriptEngineName + "]: Started new script execution thread. Current thread count: " + eventQueueThreads.Count); | 236 | m_ScriptEngine.Log.Debug("[" + m_ScriptEngine.ScriptEngineName + "]: Started new script execution thread. Current thread count: " + eventQueueThreads.Count); |
263 | } | 237 | } |
264 | 238 | ||
@@ -266,8 +240,6 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase | |||
266 | { | 240 | { |
267 | if (eventQueueThreads.Contains(threadClass)) | 241 | if (eventQueueThreads.Contains(threadClass)) |
268 | eventQueueThreads.Remove(threadClass); | 242 | eventQueueThreads.Remove(threadClass); |
269 | if (staticGlobalEventQueueThreads.Contains(threadClass)) | ||
270 | staticGlobalEventQueueThreads.Remove(threadClass); | ||
271 | 243 | ||
272 | try | 244 | try |
273 | { | 245 | { |
@@ -426,7 +398,7 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase | |||
426 | // Iterate through all ScriptThreadClasses and check how long their current function has been executing | 398 | // Iterate through all ScriptThreadClasses and check how long their current function has been executing |
427 | lock (eventQueueThreads) | 399 | lock (eventQueueThreads) |
428 | { | 400 | { |
429 | foreach (EventQueueThreadClass EventQueueThread in staticGlobalEventQueueThreads) | 401 | foreach (EventQueueThreadClass EventQueueThread in eventQueueThreads) |
430 | { | 402 | { |
431 | // Is thread currently executing anything? | 403 | // Is thread currently executing anything? |
432 | if (EventQueueThread.InExecution) | 404 | if (EventQueueThread.InExecution) |
diff --git a/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/EventQueueThreadClass.cs b/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/EventQueueThreadClass.cs index 11fd896..f36baa7 100644 --- a/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/EventQueueThreadClass.cs +++ b/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/EventQueueThreadClass.cs | |||
@@ -40,27 +40,27 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase | |||
40 | /// <summary> | 40 | /// <summary> |
41 | /// Because every thread needs some data set for it (time started to execute current function), it will do its work within a class | 41 | /// Because every thread needs some data set for it (time started to execute current function), it will do its work within a class |
42 | /// </summary> | 42 | /// </summary> |
43 | public class EventQueueThreadClass: iScriptEngineFunctionModule | 43 | public class EventQueueThreadClass : iScriptEngineFunctionModule |
44 | { | 44 | { |
45 | /// <summary> | 45 | /// <summary> |
46 | /// How many ms to sleep if queue is empty | 46 | /// How many ms to sleep if queue is empty |
47 | /// </summary> | 47 | /// </summary> |
48 | private int nothingToDoSleepms;// = 50; | 48 | private static int nothingToDoSleepms;// = 50; |
49 | private ThreadPriority MyThreadPriority; | 49 | private static ThreadPriority MyThreadPriority; |
50 | 50 | ||
51 | public long LastExecutionStarted; | 51 | public long LastExecutionStarted; |
52 | public bool InExecution = false; | 52 | public bool InExecution = false; |
53 | public bool KillCurrentScript = false; | 53 | public bool KillCurrentScript = false; |
54 | 54 | ||
55 | private EventQueueManager eventQueueManager; | 55 | //private EventQueueManager eventQueueManager; |
56 | public Thread EventQueueThread; | 56 | public Thread EventQueueThread; |
57 | private static int ThreadCount = 0; | 57 | private static int ThreadCount = 0; |
58 | 58 | ||
59 | private string ScriptEngineName = "ScriptEngine.Common"; | 59 | private string ScriptEngineName = "ScriptEngine.Common"; |
60 | 60 | ||
61 | public EventQueueThreadClass(EventQueueManager eqm) | 61 | public EventQueueThreadClass()//EventQueueManager eqm |
62 | { | 62 | { |
63 | eventQueueManager = eqm; | 63 | //eventQueueManager = eqm; |
64 | ReadConfig(); | 64 | ReadConfig(); |
65 | Start(); | 65 | Start(); |
66 | } | 66 | } |
@@ -72,32 +72,36 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase | |||
72 | 72 | ||
73 | public void ReadConfig() | 73 | public void ReadConfig() |
74 | { | 74 | { |
75 | ScriptEngineName = eventQueueManager.m_ScriptEngine.ScriptEngineName; | 75 | foreach (ScriptEngine m_ScriptEngine in ScriptEngine.ScriptEngines) |
76 | nothingToDoSleepms = eventQueueManager.m_ScriptEngine.ScriptConfigSource.GetInt("SleepTimeIfNoScriptExecutionMs", 50); | ||
77 | |||
78 | // Later with ScriptServer we might want to ask OS for stuff too, so doing this a bit manually | ||
79 | string pri = eventQueueManager.m_ScriptEngine.ScriptConfigSource.GetString("ScriptThreadPriority", "BelowNormal"); | ||
80 | switch (pri.ToLower()) | ||
81 | { | 76 | { |
82 | case "lowest": | 77 | ScriptEngineName = m_ScriptEngine.ScriptEngineName; |
83 | MyThreadPriority = ThreadPriority.Lowest; | 78 | nothingToDoSleepms = m_ScriptEngine.ScriptConfigSource.GetInt("SleepTimeIfNoScriptExecutionMs", 50); |
84 | break; | 79 | |
85 | case "belownormal": | 80 | // Later with ScriptServer we might want to ask OS for stuff too, so doing this a bit manually |
86 | MyThreadPriority = ThreadPriority.BelowNormal; | 81 | string pri = m_ScriptEngine.ScriptConfigSource.GetString("ScriptThreadPriority", "BelowNormal"); |
87 | break; | 82 | switch (pri.ToLower()) |
88 | case "normal": | 83 | { |
89 | MyThreadPriority = ThreadPriority.Normal; | 84 | case "lowest": |
90 | break; | 85 | MyThreadPriority = ThreadPriority.Lowest; |
91 | case "abovenormal": | 86 | break; |
92 | MyThreadPriority = ThreadPriority.AboveNormal; | 87 | case "belownormal": |
93 | break; | 88 | MyThreadPriority = ThreadPriority.BelowNormal; |
94 | case "highest": | 89 | break; |
95 | MyThreadPriority = ThreadPriority.Highest; | 90 | case "normal": |
96 | break; | 91 | MyThreadPriority = ThreadPriority.Normal; |
97 | default: | 92 | break; |
98 | MyThreadPriority = ThreadPriority.BelowNormal; // Default | 93 | case "abovenormal": |
99 | eventQueueManager.m_ScriptEngine.Log.Error("[ScriptEngineBase]: Unknown priority type \"" + pri + "\" in config file. Defaulting to \"BelowNormal\"."); | 94 | MyThreadPriority = ThreadPriority.AboveNormal; |
100 | break; | 95 | break; |
96 | case "highest": | ||
97 | MyThreadPriority = ThreadPriority.Highest; | ||
98 | break; | ||
99 | default: | ||
100 | MyThreadPriority = ThreadPriority.BelowNormal; // Default | ||
101 | m_ScriptEngine.Log.Error("[ScriptEngineBase]: Unknown priority type \"" + pri + | ||
102 | "\" in config file. Defaulting to \"BelowNormal\"."); | ||
103 | break; | ||
104 | } | ||
101 | } | 105 | } |
102 | 106 | ||
103 | // Now set that priority | 107 | // Now set that priority |
@@ -113,7 +117,7 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase | |||
113 | { | 117 | { |
114 | EventQueueThread = new Thread(EventQueueThreadLoop); | 118 | EventQueueThread = new Thread(EventQueueThreadLoop); |
115 | EventQueueThread.IsBackground = true; | 119 | EventQueueThread.IsBackground = true; |
116 | 120 | ||
117 | EventQueueThread.Priority = MyThreadPriority; | 121 | EventQueueThread.Priority = MyThreadPriority; |
118 | EventQueueThread.Name = "EventQueueManagerThread_" + ThreadCount; | 122 | EventQueueThread.Name = "EventQueueManagerThread_" + ThreadCount; |
119 | EventQueueThread.Start(); | 123 | EventQueueThread.Start(); |
@@ -127,8 +131,8 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase | |||
127 | 131 | ||
128 | public void Stop() | 132 | public void Stop() |
129 | { | 133 | { |
130 | PleaseShutdown = true; // Set shutdown flag | 134 | //PleaseShutdown = true; // Set shutdown flag |
131 | Thread.Sleep(100); // Wait a bit | 135 | //Thread.Sleep(100); // Wait a bit |
132 | if (EventQueueThread != null && EventQueueThread.IsAlive == true) | 136 | if (EventQueueThread != null && EventQueueThread.IsAlive == true) |
133 | { | 137 | { |
134 | try | 138 | try |
@@ -143,6 +147,8 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase | |||
143 | } | 147 | } |
144 | } | 148 | } |
145 | 149 | ||
150 | private EventQueueManager.QueueItemStruct BlankQIS = new EventQueueManager.QueueItemStruct(); | ||
151 | private ScriptEngine lastScriptEngine; | ||
146 | /// <summary> | 152 | /// <summary> |
147 | /// Queue processing thread loop | 153 | /// Queue processing thread loop |
148 | /// </summary> | 154 | /// </summary> |
@@ -151,188 +157,198 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase | |||
151 | //myScriptEngine.Log.Info("[" + ScriptEngineName + "]: EventQueueManager Worker thread spawned"); | 157 | //myScriptEngine.Log.Info("[" + ScriptEngineName + "]: EventQueueManager Worker thread spawned"); |
152 | try | 158 | try |
153 | { | 159 | { |
154 | while (true) | 160 | while (true) |
155 | { | 161 | { |
156 | try | 162 | try |
157 | { | 163 | { |
158 | EventQueueManager.QueueItemStruct BlankQIS = new EventQueueManager.QueueItemStruct(); | ||
159 | while (true) | 164 | while (true) |
160 | { | 165 | { |
161 | // Every now and then check if we should shut down | 166 | DoProcessQueue(); |
162 | if (PleaseShutdown || eventQueueManager.ThreadsToExit > 0) | 167 | } |
163 | { | 168 | } |
164 | // Someone should shut down, lets get exclusive lock | 169 | catch (ThreadAbortException tae) |
165 | lock (eventQueueManager.ThreadsToExitLock) | 170 | { |
166 | { | 171 | if (lastScriptEngine != null) |
167 | // Lets re-check in case someone grabbed it | 172 | lastScriptEngine.Log.Info("[" + ScriptEngineName + "]: ThreadAbortException while executing function."); |
168 | if (eventQueueManager.ThreadsToExit > 0) | 173 | } |
169 | { | 174 | catch (Exception e) |
170 | // Its crowded here so we'll shut down | 175 | { |
171 | eventQueueManager.ThreadsToExit--; | 176 | if (lastScriptEngine != null) |
172 | Stop(); | 177 | lastScriptEngine.Log.Error("[" + ScriptEngineName + "]: Exception in EventQueueThreadLoop: " + e.ToString()); |
173 | return; | 178 | } |
174 | } | 179 | } |
175 | else | 180 | } |
176 | { | 181 | catch (ThreadAbortException) |
177 | // We have been asked to shut down | 182 | { |
178 | Stop(); | 183 | //myScriptEngine.Log.Info("[" + ScriptEngineName + "]: EventQueueManager Worker thread killed: " + tae.Message); |
179 | return; | 184 | } |
180 | } | 185 | } |
181 | } | 186 | |
182 | } | 187 | public void DoProcessQueue() |
188 | { | ||
189 | foreach (ScriptEngine m_ScriptEngine in ScriptEngine.ScriptEngines) | ||
190 | { | ||
191 | lastScriptEngine = m_ScriptEngine; | ||
192 | // Every now and then check if we should shut down | ||
193 | //if (PleaseShutdown || EventQueueManager.ThreadsToExit > 0) | ||
194 | //{ | ||
195 | // // Someone should shut down, lets get exclusive lock | ||
196 | // lock (EventQueueManager.ThreadsToExitLock) | ||
197 | // { | ||
198 | // // Lets re-check in case someone grabbed it | ||
199 | // if (EventQueueManager.ThreadsToExit > 0) | ||
200 | // { | ||
201 | // // Its crowded here so we'll shut down | ||
202 | // EventQueueManager.ThreadsToExit--; | ||
203 | // Stop(); | ||
204 | // return; | ||
205 | // } | ||
206 | // else | ||
207 | // { | ||
208 | // // We have been asked to shut down | ||
209 | // Stop(); | ||
210 | // return; | ||
211 | // } | ||
212 | // } | ||
213 | //} | ||
214 | |||
215 | //try | ||
216 | // { | ||
217 | EventQueueManager.QueueItemStruct QIS = BlankQIS; | ||
218 | bool GotItem = false; | ||
183 | 219 | ||
184 | //try | 220 | //if (PleaseShutdown) |
185 | // { | 221 | // return; |
186 | EventQueueManager.QueueItemStruct QIS = BlankQIS; | ||
187 | bool GotItem = false; | ||
188 | 222 | ||
189 | if (PleaseShutdown) | 223 | if (m_ScriptEngine.m_EventQueueManager.eventQueue.Count == 0) |
190 | return; | 224 | { |
225 | // Nothing to do? Sleep a bit waiting for something to do | ||
226 | Thread.Sleep(nothingToDoSleepms); | ||
227 | } | ||
228 | else | ||
229 | { | ||
230 | // Something in queue, process | ||
231 | //myScriptEngine.Log.Info("[" + ScriptEngineName + "]: Processing event for localID: " + QIS.localID + ", itemID: " + QIS.itemID + ", FunctionName: " + QIS.FunctionName); | ||
191 | 232 | ||
192 | if (eventQueueManager.eventQueue.Count == 0) | 233 | // OBJECT BASED LOCK - TWO THREADS WORKING ON SAME OBJECT IS NOT GOOD |
234 | lock (m_ScriptEngine.m_EventQueueManager.eventQueue) | ||
235 | { | ||
236 | GotItem = false; | ||
237 | for (int qc = 0; qc < m_ScriptEngine.m_EventQueueManager.eventQueue.Count; qc++) | ||
238 | { | ||
239 | // Get queue item | ||
240 | QIS = m_ScriptEngine.m_EventQueueManager.eventQueue.Dequeue(); | ||
241 | |||
242 | // Check if object is being processed by someone else | ||
243 | if (m_ScriptEngine.m_EventQueueManager.TryLock(QIS.localID) == false) | ||
193 | { | 244 | { |
194 | // Nothing to do? Sleep a bit waiting for something to do | 245 | // Object is already being processed, requeue it |
195 | Thread.Sleep(nothingToDoSleepms); | 246 | m_ScriptEngine.m_EventQueueManager.eventQueue.Enqueue(QIS); |
196 | } | 247 | } |
197 | else | 248 | else |
198 | { | 249 | { |
199 | // Something in queue, process | 250 | // We have lock on an object and can process it |
200 | //myScriptEngine.Log.Info("[" + ScriptEngineName + "]: Processing event for localID: " + QIS.localID + ", itemID: " + QIS.itemID + ", FunctionName: " + QIS.FunctionName); | 251 | GotItem = true; |
201 | 252 | break; | |
202 | // OBJECT BASED LOCK - TWO THREADS WORKING ON SAME OBJECT IS NOT GOOD | 253 | } |
203 | lock (eventQueueManager.eventQueue) | 254 | } |
204 | { | 255 | } |
205 | GotItem = false; | ||
206 | for (int qc = 0; qc < eventQueueManager.eventQueue.Count; qc++) | ||
207 | { | ||
208 | // Get queue item | ||
209 | QIS = eventQueueManager.eventQueue.Dequeue(); | ||
210 | |||
211 | // Check if object is being processed by someone else | ||
212 | if (eventQueueManager.TryLock(QIS.localID) == false) | ||
213 | { | ||
214 | // Object is already being processed, requeue it | ||
215 | eventQueueManager.eventQueue.Enqueue(QIS); | ||
216 | } | ||
217 | else | ||
218 | { | ||
219 | // We have lock on an object and can process it | ||
220 | GotItem = true; | ||
221 | break; | ||
222 | } | ||
223 | } | ||
224 | } | ||
225 | 256 | ||
226 | if (GotItem == true) | 257 | if (GotItem == true) |
227 | { | 258 | { |
228 | // Execute function | 259 | // Execute function |
229 | try | 260 | try |
230 | { | 261 | { |
231 | ///cfk 2-7-08 dont need this right now and the default Linux build has DEBUG defined | 262 | ///cfk 2-7-08 dont need this right now and the default Linux build has DEBUG defined |
232 | #if DEBUG | 263 | #if DEBUG |
233 | //eventQueueManager.m_ScriptEngine.Log.Debug("[" + ScriptEngineName + "]: " + | 264 | //eventQueueManager.m_ScriptEngine.Log.Debug("[" + ScriptEngineName + "]: " + |
234 | // "Executing event:\r\n" | 265 | // "Executing event:\r\n" |
235 | // + "QIS.localID: " + QIS.localID | 266 | // + "QIS.localID: " + QIS.localID |
236 | // + ", QIS.itemID: " + QIS.itemID | 267 | // + ", QIS.itemID: " + QIS.itemID |
237 | // + ", QIS.functionName: " + | 268 | // + ", QIS.functionName: " + |
238 | // QIS.functionName); | 269 | // QIS.functionName); |
239 | #endif | 270 | #endif |
240 | LastExecutionStarted = DateTime.Now.Ticks; | 271 | LastExecutionStarted = DateTime.Now.Ticks; |
241 | KillCurrentScript = false; | 272 | KillCurrentScript = false; |
242 | InExecution = true; | 273 | InExecution = true; |
243 | eventQueueManager.m_ScriptEngine.m_ScriptManager.ExecuteEvent(QIS.localID, | 274 | m_ScriptEngine.m_ScriptManager.ExecuteEvent(QIS.localID, |
244 | QIS.itemID, | 275 | QIS.itemID, |
245 | QIS.functionName, | 276 | QIS.functionName, |
246 | QIS.llDetectParams, | 277 | QIS.llDetectParams, |
247 | QIS.param); | 278 | QIS.param); |
248 | InExecution = false; | 279 | InExecution = false; |
249 | } | 280 | } |
250 | catch (Exception e) | 281 | catch (Exception e) |
251 | { | 282 | { |
252 | InExecution = false; | 283 | InExecution = false; |
253 | // DISPLAY ERROR INWORLD | 284 | // DISPLAY ERROR INWORLD |
254 | string text = "Error executing script function \"" + QIS.functionName + | 285 | string text = "Error executing script function \"" + QIS.functionName + |
255 | "\":\r\n"; | 286 | "\":\r\n"; |
256 | if (e.InnerException != null) | 287 | if (e.InnerException != null) |
257 | { | 288 | { |
258 | // Send inner exception | 289 | // Send inner exception |
259 | text += e.InnerException.Message.ToString(); | 290 | text += e.InnerException.Message.ToString(); |
260 | } | 291 | } |
261 | else | 292 | else |
262 | { | 293 | { |
263 | text += "\r\n"; | 294 | text += "\r\n"; |
264 | // Send normal | 295 | // Send normal |
265 | text += e.Message.ToString(); | 296 | text += e.Message.ToString(); |
266 | } | 297 | } |
267 | if (KillCurrentScript) | 298 | if (KillCurrentScript) |
268 | text += "\r\nScript will be deactivated!"; | 299 | text += "\r\nScript will be deactivated!"; |
269 | 300 | ||
270 | try | 301 | try |
271 | { | 302 | { |
272 | if (text.Length > 1500) | 303 | if (text.Length > 1500) |
273 | text = text.Substring(0, 1500); | 304 | text = text.Substring(0, 1500); |
274 | IScriptHost m_host = | 305 | IScriptHost m_host = |
275 | eventQueueManager.m_ScriptEngine.World.GetSceneObjectPart(QIS.localID); | 306 | m_ScriptEngine.World.GetSceneObjectPart(QIS.localID); |
276 | //if (m_host != null) | 307 | //if (m_host != null) |
277 | //{ | 308 | //{ |
278 | eventQueueManager.m_ScriptEngine.World.SimChat(Helpers.StringToField(text), | 309 | m_ScriptEngine.World.SimChat(Helpers.StringToField(text), |
279 | ChatTypeEnum.Say, 0, | 310 | ChatTypeEnum.Say, 0, |
280 | m_host.AbsolutePosition, | 311 | m_host.AbsolutePosition, |
281 | m_host.Name, m_host.UUID); | 312 | m_host.Name, m_host.UUID); |
282 | } | 313 | } |
283 | catch | 314 | catch |
284 | { | 315 | { |
285 | //} | 316 | //} |
286 | //else | 317 | //else |
287 | //{ | 318 | //{ |
288 | // T oconsole | 319 | // T oconsole |
289 | eventQueueManager.m_ScriptEngine.Log.Error("[" + ScriptEngineName + "]: " + | 320 | m_ScriptEngine.m_EventQueueManager.m_ScriptEngine.Log.Error("[" + ScriptEngineName + "]: " + |
290 | "Unable to send text in-world:\r\n" + | 321 | "Unable to send text in-world:\r\n" + |
291 | text); | 322 | text); |
292 | } | 323 | } |
293 | finally | 324 | finally |
294 | { | 325 | { |
295 | // So we are done sending message in-world | 326 | // So we are done sending message in-world |
296 | if (KillCurrentScript) | 327 | if (KillCurrentScript) |
297 | { | 328 | { |
298 | eventQueueManager.m_ScriptEngine.m_ScriptManager.StopScript( | 329 | m_ScriptEngine.m_EventQueueManager.m_ScriptEngine.m_ScriptManager.StopScript( |
299 | QIS.localID, QIS.itemID); | 330 | QIS.localID, QIS.itemID); |
300 | } | ||
301 | } | ||
302 | } | ||
303 | finally | ||
304 | { | ||
305 | InExecution = false; | ||
306 | eventQueueManager.ReleaseLock(QIS.localID); | ||
307 | } | ||
308 | } | 331 | } |
309 | } | 332 | } |
310 | } | 333 | } |
311 | } | 334 | finally |
312 | catch (ThreadAbortException tae) | 335 | { |
313 | { | 336 | InExecution = false; |
314 | eventQueueManager.m_ScriptEngine.Log.Info("[" + ScriptEngineName + "]: ThreadAbortException while executing function."); | 337 | m_ScriptEngine.m_EventQueueManager.ReleaseLock(QIS.localID); |
315 | } | 338 | } |
316 | catch (Exception e) | ||
317 | { | ||
318 | eventQueueManager.m_ScriptEngine.Log.Error("[" + ScriptEngineName + "]: Exception in EventQueueThreadLoop: " + e.ToString()); | ||
319 | } | 339 | } |
320 | } | 340 | } |
321 | } | 341 | } |
322 | catch (ThreadAbortException) | ||
323 | { | ||
324 | //myScriptEngine.Log.Info("[" + ScriptEngineName + "]: EventQueueManager Worker thread killed: " + tae.Message); | ||
325 | } | ||
326 | } | 342 | } |
327 | 343 | ||
328 | /// <summary> | 344 | ///// <summary> |
329 | /// If set to true then threads and stuff should try to make a graceful exit | 345 | ///// If set to true then threads and stuff should try to make a graceful exit |
330 | /// </summary> | 346 | ///// </summary> |
331 | public bool PleaseShutdown | 347 | //public bool PleaseShutdown |
332 | { | 348 | //{ |
333 | get { return _PleaseShutdown; } | 349 | // get { return _PleaseShutdown; } |
334 | set { _PleaseShutdown = value; } | 350 | // set { _PleaseShutdown = value; } |
335 | } | 351 | //} |
336 | private bool _PleaseShutdown = false; | 352 | //private bool _PleaseShutdown = false; |
337 | } | 353 | } |
338 | } | 354 | } |
diff --git a/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/MaintenanceThread.cs b/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/MaintenanceThread.cs index 5c9f76d..0911afb 100644 --- a/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/MaintenanceThread.cs +++ b/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/MaintenanceThread.cs | |||
@@ -156,12 +156,11 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase | |||
156 | m_ScriptEngine.m_EventQueueManager.AdjustNumberOfScriptThreads(); | 156 | m_ScriptEngine.m_EventQueueManager.AdjustNumberOfScriptThreads(); |
157 | 157 | ||
158 | // Check if any script has exceeded its max execution time | 158 | // Check if any script has exceeded its max execution time |
159 | if (m_ScriptEngine.m_EventQueueManager != null && | 159 | if (EventQueueManager.EnforceMaxExecutionTime) |
160 | m_ScriptEngine.m_EventQueueManager.EnforceMaxExecutionTime) | ||
161 | { | 160 | { |
162 | // We are enforcing execution time | 161 | // We are enforcing execution time |
163 | if (DateTime.Now.Ticks - Last_maxFunctionExecutionTimens > | 162 | if (DateTime.Now.Ticks - Last_maxFunctionExecutionTimens > |
164 | m_ScriptEngine.m_EventQueueManager.maxFunctionExecutionTimens) | 163 | EventQueueManager.maxFunctionExecutionTimens) |
165 | { | 164 | { |
166 | // Its time to check again | 165 | // Its time to check again |
167 | m_ScriptEngine.m_EventQueueManager.CheckScriptMaxExecTime(); // Do check | 166 | m_ScriptEngine.m_EventQueueManager.CheckScriptMaxExecTime(); // Do check |