diff options
6 files changed, 98 insertions, 21 deletions
diff --git a/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/EventQueueManager.cs b/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/EventQueueManager.cs index fb20f40..7da2769 100644 --- a/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/EventQueueManager.cs +++ b/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/EventQueueManager.cs | |||
@@ -99,6 +99,8 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase | |||
99 | /// </summary> | 99 | /// </summary> |
100 | internal int numberOfThreads; | 100 | internal int numberOfThreads; |
101 | 101 | ||
102 | internal static int EventExecutionMaxQueueSize; | ||
103 | |||
102 | /// <summary> | 104 | /// <summary> |
103 | /// Maximum time one function can use for execution before we perform a thread kill. | 105 | /// Maximum time one function can use for execution before we perform a thread kill. |
104 | /// </summary> | 106 | /// </summary> |
@@ -208,6 +210,7 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase | |||
208 | maxFunctionExecutionTimems = m_ScriptEngine.ScriptConfigSource.GetInt("MaxEventExecutionTimeMs", 5000); | 210 | maxFunctionExecutionTimems = m_ScriptEngine.ScriptConfigSource.GetInt("MaxEventExecutionTimeMs", 5000); |
209 | EnforceMaxExecutionTime = m_ScriptEngine.ScriptConfigSource.GetBoolean("EnforceMaxEventExecutionTime", false); | 211 | EnforceMaxExecutionTime = m_ScriptEngine.ScriptConfigSource.GetBoolean("EnforceMaxEventExecutionTime", false); |
210 | KillScriptOnMaxFunctionExecutionTime = m_ScriptEngine.ScriptConfigSource.GetBoolean("DeactivateScriptOnTimeout", false); | 212 | KillScriptOnMaxFunctionExecutionTime = m_ScriptEngine.ScriptConfigSource.GetBoolean("DeactivateScriptOnTimeout", false); |
213 | EventExecutionMaxQueueSize = m_ScriptEngine.ScriptConfigSource.GetInt("EventExecutionMaxQueueSize", 300); | ||
211 | 214 | ||
212 | // Now refresh config in all threads | 215 | // Now refresh config in all threads |
213 | lock (eventQueueThreadsLock) | 216 | lock (eventQueueThreadsLock) |
@@ -362,6 +365,13 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase | |||
362 | { | 365 | { |
363 | lock (queueLock) | 366 | lock (queueLock) |
364 | { | 367 | { |
368 | if (eventQueue.Count >= EventExecutionMaxQueueSize) | ||
369 | { | ||
370 | m_ScriptEngine.Log.Error(m_ScriptEngine.ScriptEngineName, "ERROR: Event execution queue item count is at " + eventQueue.Count + ". Config variable \"EventExecutionMaxQueueSize\" is set to " + EventExecutionMaxQueueSize + ", so ignoring new event."); | ||
371 | m_ScriptEngine.Log.Error(m_ScriptEngine.ScriptEngineName, "Event ignored: localID: " + localID + ", itemID: " + itemID + ", FunctionName: " + FunctionName); | ||
372 | return; | ||
373 | } | ||
374 | |||
365 | // Create a structure and add data | 375 | // Create a structure and add data |
366 | QueueItemStruct QIS = new QueueItemStruct(); | 376 | QueueItemStruct QIS = new QueueItemStruct(); |
367 | QIS.localID = localID; | 377 | QIS.localID = localID; |
diff --git a/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/MaintenanceThread.cs b/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/MaintenanceThread.cs index dc98637..fc2fda9 100644 --- a/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/MaintenanceThread.cs +++ b/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/MaintenanceThread.cs | |||
@@ -38,19 +38,20 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase | |||
38 | /// <summary> | 38 | /// <summary> |
39 | /// Maintenance thread. Enforcing max execution time for example. | 39 | /// Maintenance thread. Enforcing max execution time for example. |
40 | /// </summary> | 40 | /// </summary> |
41 | public static Thread MaintenanceThreadThread; | 41 | public Thread MaintenanceThreadThread; |
42 | 42 | ||
43 | /// <summary> | 43 | /// <summary> |
44 | /// Starts maintenance thread | 44 | /// Starts maintenance thread |
45 | /// </summary> | 45 | /// </summary> |
46 | private void StartMaintenanceThread() | 46 | private void StartMaintenanceThread() |
47 | { | 47 | { |
48 | StopMaintenanceThread(); | 48 | if (MaintenanceThreadThread == null) |
49 | 49 | { | |
50 | MaintenanceThreadThread = new Thread(MaintenanceLoop); | 50 | MaintenanceThreadThread = new Thread(MaintenanceLoop); |
51 | MaintenanceThreadThread.Name = "ScriptMaintenanceThread"; | 51 | MaintenanceThreadThread.Name = "ScriptMaintenanceThread"; |
52 | MaintenanceThreadThread.IsBackground = true; | 52 | MaintenanceThreadThread.IsBackground = true; |
53 | MaintenanceThreadThread.Start(); | 53 | MaintenanceThreadThread.Start(); |
54 | } | ||
54 | } | 55 | } |
55 | 56 | ||
56 | /// <summary> | 57 | /// <summary> |
diff --git a/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/ScriptEngine.cs b/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/ScriptEngine.cs index ea8ae1f..0b58da0 100644 --- a/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/ScriptEngine.cs +++ b/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/ScriptEngine.cs | |||
@@ -92,23 +92,26 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase | |||
92 | m_log = logger; | 92 | m_log = logger; |
93 | ConfigSource = config; | 93 | ConfigSource = config; |
94 | Log.Verbose(ScriptEngineName, "ScriptEngine initializing"); | 94 | Log.Verbose(ScriptEngineName, "ScriptEngine initializing"); |
95 | Log.Verbose(ScriptEngineName, "Reading configuration from config section \"" + ScriptEngineName + "\""); | ||
96 | 95 | ||
97 | // Make sure we have config | 96 | // Make sure we have config |
98 | if (ConfigSource.Configs[ScriptEngineName] == null) | 97 | if (ConfigSource.Configs[ScriptEngineName] == null) |
99 | ConfigSource.AddConfig(ScriptEngineName); | 98 | ConfigSource.AddConfig(ScriptEngineName); |
100 | ScriptConfigSource = ConfigSource.Configs[ScriptEngineName]; | 99 | ScriptConfigSource = ConfigSource.Configs[ScriptEngineName]; |
101 | 100 | ||
101 | |||
102 | //m_logger.Status(ScriptEngineName, "InitializeEngine"); | 102 | //m_logger.Status(ScriptEngineName, "InitializeEngine"); |
103 | 103 | ||
104 | // Create all objects we'll be using | 104 | // Create all objects we'll be using |
105 | m_EventQueueManager = new EventQueueManager(this); | 105 | m_EventQueueManager = new EventQueueManager(this); |
106 | m_EventManager = new EventManager(this, HookUpToServer); | 106 | m_EventManager = new EventManager(this, HookUpToServer); |
107 | // We need to start it | ||
108 | newScriptManager.Start(); | ||
107 | m_ScriptManager = newScriptManager; | 109 | m_ScriptManager = newScriptManager; |
108 | m_AppDomainManager = new AppDomainManager(this); | 110 | m_AppDomainManager = new AppDomainManager(this); |
109 | m_ASYNCLSLCommandManager = new AsyncLSLCommandManager(this); | 111 | m_ASYNCLSLCommandManager = new AsyncLSLCommandManager(this); |
110 | m_MaintenanceThread = new MaintenanceThread(this); | 112 | m_MaintenanceThread = new MaintenanceThread(this); |
111 | 113 | ||
114 | Log.Verbose(ScriptEngineName, "Reading configuration from config section \"" + ScriptEngineName + "\""); | ||
112 | ReadConfig(); | 115 | ReadConfig(); |
113 | 116 | ||
114 | 117 | ||
diff --git a/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/ScriptManager.cs b/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/ScriptManager.cs index 22cffff..53ef217 100644 --- a/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/ScriptManager.cs +++ b/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/ScriptManager.cs | |||
@@ -62,9 +62,11 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase | |||
62 | #region Declares | 62 | #region Declares |
63 | 63 | ||
64 | private Thread scriptLoadUnloadThread; | 64 | private Thread scriptLoadUnloadThread; |
65 | private static Thread staticScriptLoadUnloadThread; | ||
65 | private int scriptLoadUnloadThread_IdleSleepms; | 66 | private int scriptLoadUnloadThread_IdleSleepms; |
66 | private Queue<LUStruct> LUQueue = new Queue<LUStruct>(); | 67 | private Queue<LUStruct> LUQueue = new Queue<LUStruct>(); |
67 | 68 | private static bool PrivateThread; | |
69 | private int LoadUnloadMaxQueueSize; | ||
68 | 70 | ||
69 | // Load/Unload structure | 71 | // Load/Unload structure |
70 | private struct LUStruct | 72 | private struct LUStruct |
@@ -98,6 +100,8 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase | |||
98 | public void ReadConfig() | 100 | public void ReadConfig() |
99 | { | 101 | { |
100 | scriptLoadUnloadThread_IdleSleepms = m_scriptEngine.ScriptConfigSource.GetInt("ScriptLoadUnloadLoopms", 30); | 102 | scriptLoadUnloadThread_IdleSleepms = m_scriptEngine.ScriptConfigSource.GetInt("ScriptLoadUnloadLoopms", 30); |
103 | PrivateThread = m_scriptEngine.ScriptConfigSource.GetBoolean("PrivateScriptLoadUnloadThread", false); | ||
104 | LoadUnloadMaxQueueSize = m_scriptEngine.ScriptConfigSource.GetInt("LoadUnloadMaxQueueSize", 100); | ||
101 | } | 105 | } |
102 | 106 | ||
103 | #region Object init/shutdown | 107 | #region Object init/shutdown |
@@ -107,14 +111,52 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase | |||
107 | public ScriptManager(ScriptEngineBase.ScriptEngine scriptEngine) | 111 | public ScriptManager(ScriptEngineBase.ScriptEngine scriptEngine) |
108 | { | 112 | { |
109 | m_scriptEngine = scriptEngine; | 113 | m_scriptEngine = scriptEngine; |
110 | // We should not read config during startup as ScriptEngine may not have config object yet | 114 | } |
115 | public void Start() | ||
116 | { | ||
117 | ReadConfig(); | ||
111 | 118 | ||
112 | AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve); | 119 | AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve); |
113 | scriptLoadUnloadThread = new Thread(ScriptLoadUnloadThreadLoop); | 120 | |
114 | scriptLoadUnloadThread.Name = "ScriptLoadUnloadThread"; | 121 | // |
115 | scriptLoadUnloadThread.IsBackground = true; | 122 | // CREATE THREAD |
116 | scriptLoadUnloadThread.Priority = ThreadPriority.BelowNormal; | 123 | // Private or shared |
117 | scriptLoadUnloadThread.Start(); | 124 | // |
125 | if (PrivateThread) | ||
126 | { | ||
127 | // Assign one thread per region | ||
128 | scriptLoadUnloadThread = StartScriptLoadUnloadThread(); | ||
129 | } | ||
130 | else | ||
131 | { | ||
132 | // Shared thread - make sure one exist, then assign it to the private | ||
133 | if (staticScriptLoadUnloadThread == null) | ||
134 | { | ||
135 | staticScriptLoadUnloadThread = StartScriptLoadUnloadThread(); | ||
136 | } | ||
137 | scriptLoadUnloadThread = staticScriptLoadUnloadThread; | ||
138 | } | ||
139 | } | ||
140 | |||
141 | private static int privateThreadCount = 0; | ||
142 | private Thread StartScriptLoadUnloadThread() | ||
143 | { | ||
144 | Thread t = new Thread(ScriptLoadUnloadThreadLoop); | ||
145 | string name = "ScriptLoadUnloadThread:"; | ||
146 | if (PrivateThread) | ||
147 | { | ||
148 | name += "Private:" + privateThreadCount; | ||
149 | privateThreadCount++; | ||
150 | } | ||
151 | else | ||
152 | { | ||
153 | name += "Shared"; | ||
154 | } | ||
155 | t.Name = name; | ||
156 | t.IsBackground = true; | ||
157 | t.Priority = ThreadPriority.Normal; | ||
158 | t.Start(); | ||
159 | return t; | ||
118 | } | 160 | } |
119 | 161 | ||
120 | ~ScriptManager() | 162 | ~ScriptManager() |
@@ -122,6 +164,8 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase | |||
122 | // Abort load/unload thread | 164 | // Abort load/unload thread |
123 | try | 165 | try |
124 | { | 166 | { |
167 | PleaseShutdown = true; | ||
168 | Thread.Sleep(100); | ||
125 | if (scriptLoadUnloadThread != null) | 169 | if (scriptLoadUnloadThread != null) |
126 | { | 170 | { |
127 | if (scriptLoadUnloadThread.IsAlive == true) | 171 | if (scriptLoadUnloadThread.IsAlive == true) |
@@ -148,6 +192,8 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase | |||
148 | { | 192 | { |
149 | if (LUQueue.Count == 0) | 193 | if (LUQueue.Count == 0) |
150 | Thread.Sleep(scriptLoadUnloadThread_IdleSleepms); | 194 | Thread.Sleep(scriptLoadUnloadThread_IdleSleepms); |
195 | if (PleaseShutdown) | ||
196 | return; | ||
151 | if (LUQueue.Count > 0) | 197 | if (LUQueue.Count > 0) |
152 | { | 198 | { |
153 | LUStruct item = LUQueue.Dequeue(); | 199 | LUStruct item = LUQueue.Dequeue(); |
@@ -185,7 +231,7 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase | |||
185 | 231 | ||
186 | #endregion | 232 | #endregion |
187 | 233 | ||
188 | 234 | ||
189 | 235 | ||
190 | #region Start/Stop/Reset script | 236 | #region Start/Stop/Reset script |
191 | 237 | ||
@@ -198,6 +244,12 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase | |||
198 | /// <param name="localID"></param> | 244 | /// <param name="localID"></param> |
199 | public void StartScript(uint localID, LLUUID itemID, string Script) | 245 | public void StartScript(uint localID, LLUUID itemID, string Script) |
200 | { | 246 | { |
247 | if (LUQueue.Count >= LoadUnloadMaxQueueSize) | ||
248 | { | ||
249 | m_scriptEngine.Log.Error(m_scriptEngine.ScriptEngineName, "ERROR: Load/unload queue item count is at " + LUQueue.Count + ". Config variable \"LoadUnloadMaxQueueSize\" is set to " + LoadUnloadMaxQueueSize + ", so ignoring new script."); | ||
250 | return; | ||
251 | } | ||
252 | |||
201 | LUStruct ls = new LUStruct(); | 253 | LUStruct ls = new LUStruct(); |
202 | ls.localID = localID; | 254 | ls.localID = localID; |
203 | ls.itemID = itemID; | 255 | ls.itemID = itemID; |
@@ -224,9 +276,8 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase | |||
224 | //private Compiler.LSL.Compiler LSLCompiler = new Compiler.LSL.Compiler(); | 276 | //private Compiler.LSL.Compiler LSLCompiler = new Compiler.LSL.Compiler(); |
225 | 277 | ||
226 | public abstract void _StartScript(uint localID, LLUUID itemID, string Script); | 278 | public abstract void _StartScript(uint localID, LLUUID itemID, string Script); |
227 | |||
228 | public abstract void _StopScript(uint localID, LLUUID itemID); | 279 | public abstract void _StopScript(uint localID, LLUUID itemID); |
229 | 280 | ||
230 | 281 | ||
231 | #endregion | 282 | #endregion |
232 | 283 | ||
diff --git a/OpenSim/Region/ScriptEngine/DotNetEngine/ScriptManager.cs b/OpenSim/Region/ScriptEngine/DotNetEngine/ScriptManager.cs index f6c9e30..821b2d4 100644 --- a/OpenSim/Region/ScriptEngine/DotNetEngine/ScriptManager.cs +++ b/OpenSim/Region/ScriptEngine/DotNetEngine/ScriptManager.cs | |||
@@ -86,7 +86,7 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine | |||
86 | 86 | ||
87 | CompiledScript.Source = Script; | 87 | CompiledScript.Source = Script; |
88 | // Add it to our script memstruct | 88 | // Add it to our script memstruct |
89 | SetScript(localID, itemID, CompiledScript); | 89 | m_scriptEngine.m_ScriptManager.SetScript(localID, itemID, CompiledScript); |
90 | 90 | ||
91 | // We need to give (untrusted) assembly a private instance of BuiltIns | 91 | // We need to give (untrusted) assembly a private instance of BuiltIns |
92 | // this private copy will contain Read-Only FullitemID so that it can bring that on to the server whenever needed. | 92 | // this private copy will contain Read-Only FullitemID so that it can bring that on to the server whenever needed. |
@@ -144,9 +144,9 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine | |||
144 | // Get AppDomain | 144 | // Get AppDomain |
145 | AppDomain ad = LSLBC.Exec.GetAppDomain(); | 145 | AppDomain ad = LSLBC.Exec.GetAppDomain(); |
146 | // Tell script not to accept new requests | 146 | // Tell script not to accept new requests |
147 | GetScript(localID, itemID).Exec.StopScript(); | 147 | m_scriptEngine.m_ScriptManager.GetScript(localID, itemID).Exec.StopScript(); |
148 | // Remove from internal structure | 148 | // Remove from internal structure |
149 | RemoveScript(localID, itemID); | 149 | m_scriptEngine.m_ScriptManager.RemoveScript(localID, itemID); |
150 | // Tell AppDomain that we have stopped script | 150 | // Tell AppDomain that we have stopped script |
151 | m_scriptEngine.m_AppDomainManager.StopScript(ad); | 151 | m_scriptEngine.m_AppDomainManager.StopScript(ad); |
152 | } | 152 | } |
diff --git a/bin/OpenSim.ini.example b/bin/OpenSim.ini.example index 9b9a139..495f4ce 100644 --- a/bin/OpenSim.ini.example +++ b/bin/OpenSim.ini.example | |||
@@ -195,6 +195,18 @@ ScriptsPerAppDomain=1 | |||
195 | ; But once active it will process all in queue before sleeping again | 195 | ; But once active it will process all in queue before sleeping again |
196 | ScriptLoadUnloadLoopms=30 | 196 | ScriptLoadUnloadLoopms=30 |
197 | 197 | ||
198 | ; Loading and unloading of scripts is queued and processed by a separate thread. | ||
199 | ; This thread can either be shared among all regions, or private (one thread per region) | ||
200 | PrivateScriptLoadUnloadThread=false | ||
201 | |||
202 | ; Maximum number of items in load/unload queue before we start rejecting loads | ||
203 | ; Note that we will only be rejecting load. Unloads will still be able to queue. | ||
204 | LoadUnloadMaxQueueSize=100 | ||
205 | |||
206 | ; Maximum number of (LSL) events that can be queued before new events are ignored. | ||
207 | EventExecutionMaxQueueSize=300 | ||
208 | |||
209 | |||
198 | ; Async LL command sleep | 210 | ; Async LL command sleep |
199 | ; If no async LL commands are waiting, how long should thread sleep before checking again | 211 | ; If no async LL commands are waiting, how long should thread sleep before checking again |
200 | ; Async LL commands are LSL-commands that causes an event to be fired back with result | 212 | ; Async LL commands are LSL-commands that causes an event to be fired back with result |