aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ScriptEngine/DotNetEngine
diff options
context:
space:
mode:
authorMelanie2009-10-27 20:28:12 +0000
committerMelanie2009-10-27 20:28:12 +0000
commit0d37883bfdb1c8e15187f63f170765c7909a6650 (patch)
tree25a5d722292d038d1ca314199b29efed54aed426 /OpenSim/Region/ScriptEngine/DotNetEngine
parentMerge branch 'master' into vehicles (diff)
parentRemove the rest of SECS. It was never used, except by an experimental version (diff)
downloadopensim-SC-0d37883bfdb1c8e15187f63f170765c7909a6650.zip
opensim-SC-0d37883bfdb1c8e15187f63f170765c7909a6650.tar.gz
opensim-SC-0d37883bfdb1c8e15187f63f170765c7909a6650.tar.bz2
opensim-SC-0d37883bfdb1c8e15187f63f170765c7909a6650.tar.xz
Merge branch 'master' into vehicles
Diffstat (limited to '')
-rw-r--r--OpenSim/Region/ScriptEngine/DotNetEngine/AppDomainManager.cs234
-rw-r--r--OpenSim/Region/ScriptEngine/DotNetEngine/Common.cs51
-rw-r--r--OpenSim/Region/ScriptEngine/DotNetEngine/EventManager.cs544
-rw-r--r--OpenSim/Region/ScriptEngine/DotNetEngine/EventQueueManager.cs460
-rw-r--r--OpenSim/Region/ScriptEngine/DotNetEngine/EventQueueThreadClass.cs428
-rw-r--r--OpenSim/Region/ScriptEngine/DotNetEngine/MaintenanceThread.cs238
-rw-r--r--OpenSim/Region/ScriptEngine/DotNetEngine/Properties/AssemblyInfo.cs65
-rw-r--r--OpenSim/Region/ScriptEngine/DotNetEngine/Resources/DotNetEngine.addin.xml13
-rw-r--r--OpenSim/Region/ScriptEngine/DotNetEngine/ScriptEngine.cs485
-rw-r--r--OpenSim/Region/ScriptEngine/DotNetEngine/ScriptManager.cs703
10 files changed, 0 insertions, 3221 deletions
diff --git a/OpenSim/Region/ScriptEngine/DotNetEngine/AppDomainManager.cs b/OpenSim/Region/ScriptEngine/DotNetEngine/AppDomainManager.cs
deleted file mode 100644
index 7116512..0000000
--- a/OpenSim/Region/ScriptEngine/DotNetEngine/AppDomainManager.cs
+++ /dev/null
@@ -1,234 +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 OpenSimulator 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
28using System;
29using System.Collections;
30using System.Collections.Generic;
31using System.Reflection;
32using System.Security;
33using System.Security.Policy;
34using System.Security.Permissions;
35using OpenSim.Region.ScriptEngine.Interfaces;
36using OpenSim.Region.ScriptEngine.Shared.ScriptBase;
37using log4net;
38
39namespace OpenSim.Region.ScriptEngine.DotNetEngine
40{
41 public class AppDomainManager
42 {
43 //
44 // This class does AppDomain handling and loading/unloading of
45 // scripts in it. It is instanced in "ScriptEngine" and controlled
46 // from "ScriptManager"
47 //
48 // 1. Create a new AppDomain if old one is full (or doesn't exist)
49 // 2. Load scripts into AppDomain
50 // 3. Unload scripts from AppDomain (stopping them and marking
51 // them as inactive)
52 // 4. Unload AppDomain completely when all scripts in it has stopped
53 //
54
55 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
56
57 private int maxScriptsPerAppDomain = 1;
58
59 // Internal list of all AppDomains
60 private List<AppDomainStructure> appDomains =
61 new List<AppDomainStructure>();
62
63 // Structure to keep track of data around AppDomain
64 private class AppDomainStructure
65 {
66 // The AppDomain itself
67 public AppDomain CurrentAppDomain;
68
69 // Number of scripts loaded into AppDomain
70 public int ScriptsLoaded;
71
72 // Number of dead scripts
73 public int ScriptsWaitingUnload;
74 }
75
76 // Current AppDomain
77 private AppDomainStructure currentAD;
78
79 private object getLock = new object(); // Mutex
80 private object freeLock = new object(); // Mutex
81
82 private ScriptEngine m_scriptEngine;
83 //public AppDomainManager(ScriptEngine scriptEngine)
84 public AppDomainManager(ScriptEngine scriptEngine)
85 {
86 m_scriptEngine = scriptEngine;
87 ReadConfig();
88 }
89
90 public void ReadConfig()
91 {
92 maxScriptsPerAppDomain = m_scriptEngine.ScriptConfigSource.GetInt(
93 "ScriptsPerAppDomain", 1);
94 }
95
96 // Find a free AppDomain, creating one if necessary
97 private AppDomainStructure GetFreeAppDomain()
98 {
99 lock (getLock)
100 {
101 // Current full?
102 if (currentAD != null &&
103 currentAD.ScriptsLoaded >= maxScriptsPerAppDomain)
104 {
105 // Add it to AppDomains list and empty current
106 appDomains.Add(currentAD);
107 currentAD = null;
108 }
109 // No current
110 if (currentAD == null)
111 {
112 // Create a new current AppDomain
113 currentAD = new AppDomainStructure();
114 currentAD.CurrentAppDomain = PrepareNewAppDomain();
115 }
116
117 return currentAD;
118 }
119 }
120
121 private int AppDomainNameCount;
122
123 // Create and prepare a new AppDomain for scripts
124 private AppDomain PrepareNewAppDomain()
125 {
126 // Create and prepare a new AppDomain
127 AppDomainNameCount++;
128
129 // TODO: Currently security match current appdomain
130
131 // Construct and initialize settings for a second AppDomain.
132 AppDomainSetup ads = new AppDomainSetup();
133 ads.ApplicationBase = AppDomain.CurrentDomain.BaseDirectory;
134 ads.DisallowBindingRedirects = true;
135 ads.DisallowCodeDownload = true;
136 ads.LoaderOptimization = LoaderOptimization.MultiDomainHost;
137 ads.ShadowCopyFiles = "false"; // Disable shadowing
138 ads.ConfigurationFile =
139 AppDomain.CurrentDomain.SetupInformation.ConfigurationFile;
140
141 AppDomain AD = AppDomain.CreateDomain("ScriptAppDomain_" +
142 AppDomainNameCount, null, ads);
143
144 m_log.Info("[" + m_scriptEngine.ScriptEngineName +
145 "]: AppDomain Loading: " +
146 AssemblyName.GetAssemblyName(
147 "OpenSim.Region.ScriptEngine.Shared.dll").ToString());
148 AD.Load(AssemblyName.GetAssemblyName(
149 "OpenSim.Region.ScriptEngine.Shared.dll"));
150
151 // Return the new AppDomain
152 return AD;
153 }
154
155 // Unload appdomains that are full and have only dead scripts
156 private void UnloadAppDomains()
157 {
158 lock (freeLock)
159 {
160 // Go through all
161 foreach (AppDomainStructure ads in new ArrayList(appDomains))
162 {
163 // Don't process current AppDomain
164 if (ads.CurrentAppDomain != currentAD.CurrentAppDomain)
165 {
166 // Not current AppDomain
167 // Is number of unloaded bigger or equal to number of loaded?
168 if (ads.ScriptsLoaded <= ads.ScriptsWaitingUnload)
169 {
170 // Remove from internal list
171 appDomains.Remove(ads);
172
173 // Unload
174 AppDomain.Unload(ads.CurrentAppDomain);
175 }
176 }
177 }
178 }
179 }
180
181 public IScript LoadScript(string FileName, out AppDomain ad)
182 {
183 // Find next available AppDomain to put it in
184 AppDomainStructure FreeAppDomain = GetFreeAppDomain();
185
186 IScript mbrt = (IScript)
187 FreeAppDomain.CurrentAppDomain.CreateInstanceFromAndUnwrap(
188 FileName, "SecondLife.Script");
189
190 FreeAppDomain.ScriptsLoaded++;
191 ad = FreeAppDomain.CurrentAppDomain;
192
193 return mbrt;
194 }
195
196
197 // Increase "dead script" counter for an AppDomain
198 public void StopScript(AppDomain ad)
199 {
200 lock (freeLock)
201 {
202 // Check if it is current AppDomain
203 if (currentAD.CurrentAppDomain == ad)
204 {
205 // Yes - increase
206 currentAD.ScriptsWaitingUnload++;
207 return;
208 }
209
210 // Lopp through all AppDomains
211 foreach (AppDomainStructure ads in new ArrayList(appDomains))
212 {
213 if (ads.CurrentAppDomain == ad)
214 {
215 // Found it
216 ads.ScriptsWaitingUnload++;
217 break;
218 }
219 }
220 }
221
222 UnloadAppDomains(); // Outsite lock, has its own GetLock
223 }
224
225 // If set to true then threads and stuff should try
226 // to make a graceful exit
227 public bool PleaseShutdown
228 {
229 get { return _PleaseShutdown; }
230 set { _PleaseShutdown = value; }
231 }
232 private bool _PleaseShutdown = false;
233 }
234}
diff --git a/OpenSim/Region/ScriptEngine/DotNetEngine/Common.cs b/OpenSim/Region/ScriptEngine/DotNetEngine/Common.cs
deleted file mode 100644
index 1cd60e3..0000000
--- a/OpenSim/Region/ScriptEngine/DotNetEngine/Common.cs
+++ /dev/null
@@ -1,51 +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 OpenSimulator 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
28using System.Reflection;
29using log4net;
30
31namespace OpenSim.Region.ScriptEngine.DotNetEngine
32{
33 public static class Common
34 {
35 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
36
37 public static ScriptEngine mySE;
38
39 // This class just contains some static log stuff used for debugging.
40
41 public static void SendToDebug(string message)
42 {
43 m_log.Info("[" + mySE.ScriptEngineName + "]: Debug: " + message);
44 }
45
46 public static void SendToLog(string message)
47 {
48 m_log.Info("[" + mySE.ScriptEngineName + "]: LOG: " + message);
49 }
50 }
51}
diff --git a/OpenSim/Region/ScriptEngine/DotNetEngine/EventManager.cs b/OpenSim/Region/ScriptEngine/DotNetEngine/EventManager.cs
deleted file mode 100644
index 4e13fb3..0000000
--- a/OpenSim/Region/ScriptEngine/DotNetEngine/EventManager.cs
+++ /dev/null
@@ -1,544 +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 OpenSimulator 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
28using System;
29using System.Collections.Generic;
30using System.Reflection;
31using OpenMetaverse;
32using OpenSim.Framework;
33using OpenSim.Region.CoreModules;
34using OpenSim.Region;
35using OpenSim.Region.Framework.Scenes;
36using OpenSim.Region.Framework.Interfaces;
37using OpenSim.Region.ScriptEngine.Shared;
38using log4net;
39
40namespace OpenSim.Region.ScriptEngine.DotNetEngine
41{
42 /// <summary>
43 /// Prepares events so they can be directly executed upon a script by EventQueueManager, then queues it.
44 /// </summary>
45 [Serializable]
46 public class EventManager
47 {
48 //
49 // Class is instanced in "ScriptEngine" and Uses "EventQueueManager"
50 // that is also instanced in "ScriptEngine".
51 // This class needs a bit of explaining:
52 //
53 // This class it the link between an event inside OpenSim and
54 // the corresponding event in a user script being executed.
55 //
56 // For example when an user touches an object then the
57 // "myScriptEngine.World.EventManager.OnObjectGrab" event is fired
58 // inside OpenSim.
59 // We hook up to this event and queue a touch_start in
60 // EventQueueManager with the proper LSL parameters.
61 // It will then be delivered to the script by EventQueueManager.
62 //
63 // You can check debug C# dump of an LSL script if you need to
64 // verify what exact parameters are needed.
65 //
66
67 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
68
69 private ScriptEngine myScriptEngine;
70
71 public EventManager(ScriptEngine _ScriptEngine, bool performHookUp)
72 {
73 myScriptEngine = _ScriptEngine;
74 ReadConfig();
75
76 if (performHookUp)
77 {
78 myScriptEngine.World.EventManager.OnRezScript += OnRezScript;
79 }
80 }
81
82 public void HookUpEvents()
83 {
84 m_log.Info("[" + myScriptEngine.ScriptEngineName +
85 "]: Hooking up to server events");
86
87 myScriptEngine.World.EventManager.OnObjectGrab +=
88 touch_start;
89 myScriptEngine.World.EventManager.OnObjectDeGrab +=
90 touch_end;
91 myScriptEngine.World.EventManager.OnRemoveScript +=
92 OnRemoveScript;
93 myScriptEngine.World.EventManager.OnScriptChangedEvent +=
94 changed;
95 myScriptEngine.World.EventManager.OnScriptAtTargetEvent +=
96 at_target;
97 myScriptEngine.World.EventManager.OnScriptNotAtTargetEvent +=
98 not_at_target;
99 myScriptEngine.World.EventManager.OnScriptControlEvent +=
100 control;
101 myScriptEngine.World.EventManager.OnScriptColliderStart +=
102 collision_start;
103 myScriptEngine.World.EventManager.OnScriptColliding +=
104 collision;
105 myScriptEngine.World.EventManager.OnScriptCollidingEnd +=
106 collision_end;
107
108 IMoneyModule money =
109 myScriptEngine.World.RequestModuleInterface<IMoneyModule>();
110 if (money != null)
111 money.OnObjectPaid+=HandleObjectPaid;
112 }
113
114 public void ReadConfig()
115 {
116 }
117
118 private void HandleObjectPaid(UUID objectID, UUID agentID, int amount)
119 {
120 SceneObjectPart part =
121 myScriptEngine.World.GetSceneObjectPart(objectID);
122
123 if (part != null)
124 {
125 money(part.LocalId, agentID, amount);
126 }
127 }
128
129 public void changed(uint localID, uint change)
130 {
131 // Add to queue for all scripts in localID, Object pass change.
132 myScriptEngine.PostObjectEvent(localID, new EventParams(
133 "changed",new object[] { new LSL_Types.LSLInteger(change) },
134 new DetectParams[0]));
135 }
136
137 public void state_entry(uint localID)
138 {
139 // Add to queue for all scripts in ObjectID object
140 myScriptEngine.PostObjectEvent(localID, new EventParams(
141 "state_entry",new object[] { },
142 new DetectParams[0]));
143 }
144
145 public void touch_start(uint localID, uint originalID,
146 Vector3 offsetPos, IClientAPI remoteClient, SurfaceTouchEventArgs surfaceArgs)
147 {
148 // Add to queue for all scripts in ObjectID object
149 DetectParams[] det = new DetectParams[1];
150 det[0] = new DetectParams();
151 det[0].Key = remoteClient.AgentId;
152 det[0].Populate(myScriptEngine.World);
153
154 if (originalID == 0)
155 {
156 SceneObjectPart part =
157 myScriptEngine.World.GetSceneObjectPart(localID);
158
159 if (part == null)
160 return;
161
162 det[0].LinkNum = part.LinkNum;
163 }
164 else
165 {
166 SceneObjectPart originalPart =
167 myScriptEngine.World.GetSceneObjectPart(originalID);
168 det[0].LinkNum = originalPart.LinkNum;
169 }
170 if (surfaceArgs != null)
171 {
172 det[0].SurfaceTouchArgs = surfaceArgs;
173 }
174
175 myScriptEngine.PostObjectEvent(localID, new EventParams(
176 "touch_start", new Object[] { new LSL_Types.LSLInteger(1) },
177 det));
178 }
179
180 public void touch(uint localID, uint originalID, Vector3 offsetPos,
181 IClientAPI remoteClient)
182 {
183 // Add to queue for all scripts in ObjectID object
184 DetectParams[] det = new DetectParams[1];
185 det[0] = new DetectParams();
186 det[0].Key = remoteClient.AgentId;
187 det[0].Populate(myScriptEngine.World);
188 det[0].OffsetPos = new LSL_Types.Vector3(offsetPos.X,
189 offsetPos.Y,
190 offsetPos.Z);
191
192 if (originalID == 0)
193 {
194 SceneObjectPart part = myScriptEngine.World.GetSceneObjectPart(localID);
195 if (part == null)
196 return;
197
198 det[0].LinkNum = part.LinkNum;
199 }
200 else
201 {
202 SceneObjectPart originalPart = myScriptEngine.World.GetSceneObjectPart(originalID);
203 det[0].LinkNum = originalPart.LinkNum;
204 }
205
206 myScriptEngine.PostObjectEvent(localID, new EventParams(
207 "touch", new Object[] { new LSL_Types.LSLInteger(1) },
208 det));
209 }
210
211 public void touch_end(uint localID, uint originalID, IClientAPI remoteClient,
212 SurfaceTouchEventArgs surfaceArgs)
213 {
214 // Add to queue for all scripts in ObjectID object
215 DetectParams[] det = new DetectParams[1];
216 det[0] = new DetectParams();
217 det[0].Key = remoteClient.AgentId;
218 det[0].Populate(myScriptEngine.World);
219
220 if (originalID == 0)
221 {
222 SceneObjectPart part =
223 myScriptEngine.World.GetSceneObjectPart(localID);
224 if (part == null)
225 return;
226
227 det[0].LinkNum = part.LinkNum;
228 }
229 else
230 {
231 SceneObjectPart originalPart =
232 myScriptEngine.World.GetSceneObjectPart(originalID);
233 det[0].LinkNum = originalPart.LinkNum;
234 }
235
236 if (surfaceArgs != null)
237 {
238 det[0].SurfaceTouchArgs = surfaceArgs;
239 }
240
241 myScriptEngine.PostObjectEvent(localID, new EventParams(
242 "touch_end", new Object[] { new LSL_Types.LSLInteger(1) },
243 det));
244 }
245
246 public void OnRezScript(uint localID, UUID itemID, string script,
247 int startParam, bool postOnRez, string engine, int stateSource)
248 {
249 if (script.StartsWith("//MRM:"))
250 return;
251
252 List<IScriptModule> engines =
253 new List<IScriptModule>(
254 myScriptEngine.World.RequestModuleInterfaces<IScriptModule>());
255
256 List<string> names = new List<string>();
257 foreach (IScriptModule m in engines)
258 names.Add(m.ScriptEngineName);
259
260 int lineEnd = script.IndexOf('\n');
261
262 if (lineEnd > 1)
263 {
264 string firstline = script.Substring(0, lineEnd).Trim();
265
266 int colon = firstline.IndexOf(':');
267 if (firstline.Length > 2 &&
268 firstline.Substring(0, 2) == "//" && colon != -1)
269 {
270 string engineName = firstline.Substring(2, colon-2);
271
272 if (names.Contains(engineName))
273 {
274 engine = engineName;
275 script = "//" + script.Substring(script.IndexOf(':')+1);
276 }
277 else
278 {
279 if (engine == myScriptEngine.ScriptEngineName)
280 {
281 SceneObjectPart part =
282 myScriptEngine.World.GetSceneObjectPart(
283 localID);
284
285 TaskInventoryItem item =
286 part.Inventory.GetInventoryItem(itemID);
287
288 ScenePresence presence =
289 myScriptEngine.World.GetScenePresence(
290 item.OwnerID);
291
292 if (presence != null)
293 {
294 presence.ControllingClient.SendAgentAlertMessage(
295 "Selected engine unavailable. "+
296 "Running script on "+
297 myScriptEngine.ScriptEngineName,
298 false);
299 }
300 }
301 }
302 }
303 }
304
305 if (engine != myScriptEngine.ScriptEngineName)
306 return;
307
308 // m_log.Debug("OnRezScript localID: " + localID +
309 // " LLUID: " + itemID.ToString() + " Size: " +
310 // script.Length);
311
312 myScriptEngine.m_ScriptManager.StartScript(localID, itemID, script,
313 startParam, postOnRez);
314 }
315
316 public void OnRemoveScript(uint localID, UUID itemID)
317 {
318 // m_log.Debug("OnRemoveScript localID: " + localID + " LLUID: " + itemID.ToString());
319 myScriptEngine.m_ScriptManager.StopScript(
320 localID,
321 itemID
322 );
323 }
324
325 public void money(uint localID, UUID agentID, int amount)
326 {
327 myScriptEngine.PostObjectEvent(localID, new EventParams(
328 "money", new object[] {
329 new LSL_Types.LSLString(agentID.ToString()),
330 new LSL_Types.LSLInteger(amount) },
331 new DetectParams[0]));
332 }
333
334 // TODO: Replace placeholders below
335 // NOTE! THE PARAMETERS FOR THESE FUNCTIONS ARE NOT CORRECT!
336 // These needs to be hooked up to OpenSim during init of this class
337 // then queued in EventQueueManager.
338 // When queued in EventQueueManager they need to be LSL compatible (name and params)
339
340 public void state_exit(uint localID)
341 {
342 myScriptEngine.PostObjectEvent(localID, new EventParams(
343 "state_exit", new object[] { },
344 new DetectParams[0]));
345 }
346
347 public void collision_start(uint localID, ColliderArgs col)
348 {
349 // Add to queue for all scripts in ObjectID object
350 List<DetectParams> det = new List<DetectParams>();
351
352 foreach (DetectedObject detobj in col.Colliders)
353 {
354 DetectParams d = new DetectParams();
355 d.Key =detobj.keyUUID;
356 d.Populate(myScriptEngine.World);
357 det.Add(d);
358 }
359
360 if (det.Count > 0)
361 myScriptEngine.PostObjectEvent(localID, new EventParams(
362 "collision_start",
363 new Object[] { new LSL_Types.LSLInteger(det.Count) },
364 det.ToArray()));
365 }
366
367 public void collision(uint localID, ColliderArgs col)
368 {
369 // Add to queue for all scripts in ObjectID object
370 List<DetectParams> det = new List<DetectParams>();
371
372 foreach (DetectedObject detobj in col.Colliders)
373 {
374 DetectParams d = new DetectParams();
375 d.Key =detobj.keyUUID;
376 d.Populate(myScriptEngine.World);
377 det.Add(d);
378 }
379
380 if (det.Count > 0)
381 myScriptEngine.PostObjectEvent(localID, new EventParams(
382 "collision", new Object[] { new LSL_Types.LSLInteger(det.Count) },
383 det.ToArray()));
384 }
385
386 public void collision_end(uint localID, ColliderArgs col)
387 {
388 // Add to queue for all scripts in ObjectID object
389 List<DetectParams> det = new List<DetectParams>();
390
391 foreach (DetectedObject detobj in col.Colliders)
392 {
393 DetectParams d = new DetectParams();
394 d.Key =detobj.keyUUID;
395 d.Populate(myScriptEngine.World);
396 det.Add(d);
397 }
398
399 if (det.Count > 0)
400 myScriptEngine.PostObjectEvent(localID, new EventParams(
401 "collision_end",
402 new Object[] { new LSL_Types.LSLInteger(det.Count) },
403 det.ToArray()));
404 }
405
406 public void land_collision_start(uint localID, UUID itemID)
407 {
408 myScriptEngine.PostObjectEvent(localID, new EventParams(
409 "land_collision_start",
410 new object[0],
411 new DetectParams[0]));
412 }
413
414 public void land_collision(uint localID, UUID itemID)
415 {
416 myScriptEngine.PostObjectEvent(localID, new EventParams(
417 "land_collision",
418 new object[0],
419 new DetectParams[0]));
420 }
421
422 public void land_collision_end(uint localID, UUID itemID)
423 {
424 myScriptEngine.PostObjectEvent(localID, new EventParams(
425 "land_collision_end",
426 new object[0],
427 new DetectParams[0]));
428 }
429
430 // Handled by long commands
431 public void timer(uint localID, UUID itemID)
432 {
433 }
434
435 public void listen(uint localID, UUID itemID)
436 {
437 }
438
439 public void control(uint localID, UUID itemID, UUID agentID, uint held, uint change)
440 {
441 if ((change == 0) && (myScriptEngine.m_EventQueueManager.CheckEeventQueueForEvent(localID,"control"))) return;
442 myScriptEngine.PostObjectEvent(localID, new EventParams(
443 "control",new object[] {
444 new LSL_Types.LSLString(agentID.ToString()),
445 new LSL_Types.LSLInteger(held),
446 new LSL_Types.LSLInteger(change)},
447 new DetectParams[0]));
448 }
449
450 public void email(uint localID, UUID itemID, string timeSent,
451 string address, string subject, string message, int numLeft)
452 {
453 myScriptEngine.PostObjectEvent(localID, new EventParams(
454 "email",new object[] {
455 new LSL_Types.LSLString(timeSent),
456 new LSL_Types.LSLString(address),
457 new LSL_Types.LSLString(subject),
458 new LSL_Types.LSLString(message),
459 new LSL_Types.LSLInteger(numLeft)},
460 new DetectParams[0]));
461 }
462
463 public void at_target(uint localID, uint handle, Vector3 targetpos,
464 Vector3 atpos)
465 {
466 myScriptEngine.PostObjectEvent(localID, new EventParams(
467 "at_target", new object[] {
468 new LSL_Types.LSLInteger(handle),
469 new LSL_Types.Vector3(targetpos.X,targetpos.Y,targetpos.Z),
470 new LSL_Types.Vector3(atpos.X,atpos.Y,atpos.Z) },
471 new DetectParams[0]));
472 }
473
474 public void not_at_target(uint localID)
475 {
476 myScriptEngine.PostObjectEvent(localID, new EventParams(
477 "not_at_target",new object[0],
478 new DetectParams[0]));
479 }
480
481 public void at_rot_target(uint localID, UUID itemID)
482 {
483 myScriptEngine.PostObjectEvent(localID, new EventParams(
484 "at_rot_target",new object[0],
485 new DetectParams[0]));
486 }
487
488 public void not_at_rot_target(uint localID, UUID itemID)
489 {
490 myScriptEngine.PostObjectEvent(localID, new EventParams(
491 "not_at_rot_target",new object[0],
492 new DetectParams[0]));
493 }
494
495 public void attach(uint localID, UUID itemID)
496 {
497 }
498
499 public void dataserver(uint localID, UUID itemID)
500 {
501 }
502
503 public void link_message(uint localID, UUID itemID)
504 {
505 }
506
507 public void moving_start(uint localID, UUID itemID)
508 {
509 myScriptEngine.PostObjectEvent(localID, new EventParams(
510 "moving_start",new object[0],
511 new DetectParams[0]));
512 }
513
514 public void moving_end(uint localID, UUID itemID)
515 {
516 myScriptEngine.PostObjectEvent(localID, new EventParams(
517 "moving_end",new object[0],
518 new DetectParams[0]));
519 }
520
521 public void object_rez(uint localID, UUID itemID)
522 {
523 }
524
525 public void remote_data(uint localID, UUID itemID)
526 {
527 }
528
529 // Handled by long commands
530 public void http_response(uint localID, UUID itemID)
531 {
532 }
533
534 /// <summary>
535 /// If set to true then threads and stuff should try to make a graceful exit
536 /// </summary>
537 public bool PleaseShutdown
538 {
539 get { return _PleaseShutdown; }
540 set { _PleaseShutdown = value; }
541 }
542 private bool _PleaseShutdown = false;
543 }
544}
diff --git a/OpenSim/Region/ScriptEngine/DotNetEngine/EventQueueManager.cs b/OpenSim/Region/ScriptEngine/DotNetEngine/EventQueueManager.cs
deleted file mode 100644
index 5865452..0000000
--- a/OpenSim/Region/ScriptEngine/DotNetEngine/EventQueueManager.cs
+++ /dev/null
@@ -1,460 +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 OpenSimulator 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
28using System;
29using System.Collections;
30using System.Collections.Generic;
31using System.Reflection;
32using OpenMetaverse;
33using OpenSim.Region.ScriptEngine.Shared;
34using log4net;
35
36namespace OpenSim.Region.ScriptEngine.DotNetEngine
37{
38 /// <summary>
39 /// EventQueueManager handles event queues
40 /// Events are queued and executed in separate thread
41 /// </summary>
42 [Serializable]
43 public class EventQueueManager
44 {
45 //
46 // Class is instanced in "ScriptEngine" and used by "EventManager" which is also instanced in "ScriptEngine".
47 //
48 // Class purpose is to queue and execute functions that are received by "EventManager":
49 // - allowing "EventManager" to release its event thread immediately, thus not interrupting server execution.
50 // - allowing us to prioritize and control execution of script functions.
51 // Class can use multiple threads for simultaneous execution. Mutexes are used for thread safety.
52 //
53 // 1. Hold an execution queue for scripts
54 // 2. Use threads to process queue, each thread executes one script function on each pass.
55 // 3. Catch any script error and process it
56 //
57 //
58 // Notes:
59 // * Current execution load balancing is optimized for 1 thread, and can cause unfair execute balancing between scripts.
60 // Not noticeable unless server is under high load.
61 //
62
63 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
64
65 public ScriptEngine m_ScriptEngine;
66
67 /// <summary>
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.
70 /// </summary>
71 internal static List<EventQueueThreadClass> eventQueueThreads = new List<EventQueueThreadClass>(); // Thread pool that we work on
72 /// <summary>
73 /// Locking access to eventQueueThreads AND staticGlobalEventQueueThreads.
74 /// </summary>
75// private object eventQueueThreadsLock = new object();
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
78// internal static object staticEventQueueThreadsLock; // Statick lock object reference for same reason
79
80 /// <summary>
81 /// Global static list of all threads (classes) processing event queue -- used by max enforcment thread
82 /// </summary>
83 //private List<EventQueueThreadClass> staticGlobalEventQueueThreads = new List<EventQueueThreadClass>();
84
85 /// <summary>
86 /// Used internally to specify how many threads should exit gracefully
87 /// </summary>
88 public static int ThreadsToExit;
89 public static object ThreadsToExitLock = new object();
90
91
92 //public object queueLock = new object(); // Mutex lock object
93
94 /// <summary>
95 /// How many threads to process queue with
96 /// </summary>
97 internal static int numberOfThreads;
98
99 internal static int EventExecutionMaxQueueSize;
100
101 /// <summary>
102 /// Maximum time one function can use for execution before we perform a thread kill.
103 /// </summary>
104 private static int maxFunctionExecutionTimems
105 {
106 get { return (int)(maxFunctionExecutionTimens / 10000); }
107 set { maxFunctionExecutionTimens = value * 10000; }
108 }
109
110 /// <summary>
111 /// Contains nanoseconds version of maxFunctionExecutionTimems so that it matches time calculations better (performance reasons).
112 /// WARNING! ONLY UPDATE maxFunctionExecutionTimems, NEVER THIS DIRECTLY.
113 /// </summary>
114 public static long maxFunctionExecutionTimens;
115
116 /// <summary>
117 /// Enforce max execution time
118 /// </summary>
119 public static bool EnforceMaxExecutionTime;
120
121 /// <summary>
122 /// Kill script (unload) when it exceeds execution time
123 /// </summary>
124 private static bool KillScriptOnMaxFunctionExecutionTime;
125
126 /// <summary>
127 /// List of localID locks for mutex processing of script events
128 /// </summary>
129 private List<uint> objectLocks = new List<uint>();
130 private object tryLockLock = new object(); // Mutex lock object
131
132 /// <summary>
133 /// Queue containing events waiting to be executed
134 /// </summary>
135 public Queue<QueueItemStruct> eventQueue = new Queue<QueueItemStruct>();
136
137 #region " Queue structures "
138 /// <summary>
139 /// Queue item structure
140 /// </summary>
141 public struct QueueItemStruct
142 {
143 public uint localID;
144 public UUID itemID;
145 public string functionName;
146 public DetectParams[] llDetectParams;
147 public object[] param;
148 public Dictionary<KeyValuePair<int,int>,KeyValuePair<int,int>>
149 LineMap;
150 }
151
152 #endregion
153
154 #region " Initialization / Startup "
155 public EventQueueManager(ScriptEngine _ScriptEngine)
156 {
157 m_ScriptEngine = _ScriptEngine;
158
159 ReadConfig();
160 AdjustNumberOfScriptThreads();
161 }
162
163 public void ReadConfig()
164 {
165 // Refresh config
166 numberOfThreads = m_ScriptEngine.ScriptConfigSource.GetInt("NumberOfScriptThreads", 2);
167 maxFunctionExecutionTimems = m_ScriptEngine.ScriptConfigSource.GetInt("MaxEventExecutionTimeMs", 5000);
168 EnforceMaxExecutionTime = m_ScriptEngine.ScriptConfigSource.GetBoolean("EnforceMaxEventExecutionTime", true);
169 KillScriptOnMaxFunctionExecutionTime = m_ScriptEngine.ScriptConfigSource.GetBoolean("DeactivateScriptOnTimeout", false);
170 EventExecutionMaxQueueSize = m_ScriptEngine.ScriptConfigSource.GetInt("EventExecutionMaxQueueSize", 300);
171
172 // Now refresh config in all threads
173 lock (eventQueueThreads)
174 {
175 foreach (EventQueueThreadClass EventQueueThread in eventQueueThreads)
176 {
177 EventQueueThread.ReadConfig();
178 }
179 }
180 }
181
182 #endregion
183
184 #region " Shutdown all threads "
185 ~EventQueueManager()
186 {
187 Stop();
188 }
189
190 private void Stop()
191 {
192 if (eventQueueThreads != null)
193 {
194 // Kill worker threads
195 lock (eventQueueThreads)
196 {
197 foreach (EventQueueThreadClass EventQueueThread in new ArrayList(eventQueueThreads))
198 {
199 AbortThreadClass(EventQueueThread);
200 }
201 //eventQueueThreads.Clear();
202 //staticGlobalEventQueueThreads.Clear();
203 }
204 }
205
206 // Remove all entries from our event queue
207 lock (eventQueue)
208 {
209 eventQueue.Clear();
210 }
211 }
212
213 #endregion
214
215 #region " Start / stop script execution threads (ThreadClasses) "
216 private void StartNewThreadClass()
217 {
218 EventQueueThreadClass eqtc = new EventQueueThreadClass();
219 eventQueueThreads.Add(eqtc);
220 //m_log.Debug("[" + m_ScriptEngine.ScriptEngineName + "]: Started new script execution thread. Current thread count: " + eventQueueThreads.Count);
221 }
222
223 private void AbortThreadClass(EventQueueThreadClass threadClass)
224 {
225 if (eventQueueThreads.Contains(threadClass))
226 eventQueueThreads.Remove(threadClass);
227
228 try
229 {
230 threadClass.Stop();
231 }
232 catch (Exception)
233 {
234 //m_log.Error("[" + m_ScriptEngine.ScriptEngineName + ":EventQueueManager]: If you see this, could you please report it to Tedd:");
235 //m_log.Error("[" + m_ScriptEngine.ScriptEngineName + ":EventQueueManager]: Script thread execution timeout kill ended in exception: " + ex.ToString());
236 }
237 //m_log.Debug("[" + m_ScriptEngine.ScriptEngineName + "]: Killed script execution thread. Remaining thread count: " + eventQueueThreads.Count);
238 }
239 #endregion
240
241 #region " Mutex locks for queue access "
242 /// <summary>
243 /// Try to get a mutex lock on localID
244 /// </summary>
245 /// <param name="localID"></param>
246 /// <returns></returns>
247 public bool TryLock(uint localID)
248 {
249 lock (tryLockLock)
250 {
251 if (objectLocks.Contains(localID) == true)
252 {
253 return false;
254 }
255 else
256 {
257 objectLocks.Add(localID);
258 return true;
259 }
260 }
261 }
262
263 /// <summary>
264 /// Release mutex lock on localID
265 /// </summary>
266 /// <param name="localID"></param>
267 public void ReleaseLock(uint localID)
268 {
269 lock (tryLockLock)
270 {
271 if (objectLocks.Contains(localID) == true)
272 {
273 objectLocks.Remove(localID);
274 }
275 }
276 }
277 #endregion
278
279 #region " Check execution queue for a specified Event"
280 /// <summary>
281 /// checks to see if a specified event type is already in the queue
282 /// </summary>
283 /// <param name="localID">Region object ID</param>
284 /// <param name="FunctionName">Name of the function, will be state + "_event_" + FunctionName</param>
285 /// <returns>true if event is found , false if not found</returns>
286 ///
287 public bool CheckEeventQueueForEvent(uint localID, string FunctionName)
288 {
289 if (eventQueue.Count > 0)
290 {
291 lock (eventQueue)
292 {
293 foreach (EventQueueManager.QueueItemStruct QIS in eventQueue)
294 {
295 if ((QIS.functionName == FunctionName) && (QIS.localID == localID))
296 return true;
297 }
298 }
299 }
300 return false;
301 }
302 #endregion
303
304 #region " Add events to execution queue "
305 /// <summary>
306 /// Add event to event execution queue
307 /// </summary>
308 /// <param name="localID">Region object ID</param>
309 /// <param name="FunctionName">Name of the function, will be state + "_event_" + FunctionName</param>
310 /// <param name="param">Array of parameters to match event mask</param>
311 public bool AddToObjectQueue(uint localID, string FunctionName, DetectParams[] qParams, params object[] param)
312 {
313 // Determine all scripts in Object and add to their queue
314 //myScriptEngine.log.Info("[" + ScriptEngineName + "]: EventQueueManager Adding localID: " + localID + ", FunctionName: " + FunctionName);
315
316 // Do we have any scripts in this object at all? If not, return
317 if (m_ScriptEngine.m_ScriptManager.Scripts.ContainsKey(localID) == false)
318 {
319 //m_log.Debug("Event \String.Empty + FunctionName + "\" for localID: " + localID + ". No scripts found on this localID.");
320 return false;
321 }
322
323 List<UUID> scriptKeys =
324 m_ScriptEngine.m_ScriptManager.GetScriptKeys(localID);
325
326 foreach (UUID itemID in scriptKeys)
327 {
328 // Add to each script in that object
329 // TODO: Some scripts may not subscribe to this event. Should we NOT add it? Does it matter?
330 AddToScriptQueue(localID, itemID, FunctionName, qParams, param);
331 }
332 return true;
333 }
334
335 /// <summary>
336 /// Add event to event execution queue
337 /// </summary>
338 /// <param name="localID">Region object ID</param>
339 /// <param name="itemID">Region script ID</param>
340 /// <param name="FunctionName">Name of the function, will be state + "_event_" + FunctionName</param>
341 /// <param name="param">Array of parameters to match event mask</param>
342 public bool AddToScriptQueue(uint localID, UUID itemID, string FunctionName, DetectParams[] qParams, params object[] param)
343 {
344 List<UUID> keylist = m_ScriptEngine.m_ScriptManager.GetScriptKeys(localID);
345
346 if (!keylist.Contains(itemID)) // We don't manage that script
347 {
348 return false;
349 }
350
351 lock (eventQueue)
352 {
353 if (eventQueue.Count >= EventExecutionMaxQueueSize)
354 {
355 m_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.");
356 m_log.Error("[" + m_ScriptEngine.ScriptEngineName + "]: Event ignored: localID: " + localID + ", itemID: " + itemID + ", FunctionName: " + FunctionName);
357 return false;
358 }
359
360 InstanceData id = m_ScriptEngine.m_ScriptManager.GetScript(
361 localID, itemID);
362
363 // Create a structure and add data
364 QueueItemStruct QIS = new QueueItemStruct();
365 QIS.localID = localID;
366 QIS.itemID = itemID;
367 QIS.functionName = FunctionName;
368 QIS.llDetectParams = qParams;
369 QIS.param = param;
370 if (id != null)
371 QIS.LineMap = id.LineMap;
372
373 // Add it to queue
374 eventQueue.Enqueue(QIS);
375 }
376 return true;
377 }
378 #endregion
379
380 #region " Maintenance thread "
381
382 /// <summary>
383 /// Adjust number of script thread classes. It can start new, but if it needs to stop it will just set number of threads in "ThreadsToExit" and threads will have to exit themselves.
384 /// Called from MaintenanceThread
385 /// </summary>
386 public void AdjustNumberOfScriptThreads()
387 {
388 // Is there anything here for us to do?
389 if (eventQueueThreads.Count == numberOfThreads)
390 return;
391
392 lock (eventQueueThreads)
393 {
394 int diff = numberOfThreads - eventQueueThreads.Count;
395 // Positive number: Start
396 // Negative number: too many are running
397 if (diff > 0)
398 {
399 // We need to add more threads
400 for (int ThreadCount = eventQueueThreads.Count; ThreadCount < numberOfThreads; ThreadCount++)
401 {
402 StartNewThreadClass();
403 }
404 }
405 if (diff < 0)
406 {
407 // We need to kill some threads
408 lock (ThreadsToExitLock)
409 {
410 ThreadsToExit = Math.Abs(diff);
411 }
412 }
413 }
414 }
415
416 /// <summary>
417 /// Check if any thread class has been executing an event too long
418 /// </summary>
419 public void CheckScriptMaxExecTime()
420 {
421 // Iterate through all ScriptThreadClasses and check how long their current function has been executing
422 lock (eventQueueThreads)
423 {
424 foreach (EventQueueThreadClass EventQueueThread in eventQueueThreads)
425 {
426 // Is thread currently executing anything?
427 if (EventQueueThread.InExecution)
428 {
429 // Has execution time expired?
430 if (DateTime.Now.Ticks - EventQueueThread.LastExecutionStarted >
431 maxFunctionExecutionTimens)
432 {
433 // Yes! We need to kill this thread!
434
435 // Set flag if script should be removed or not
436 EventQueueThread.KillCurrentScript = KillScriptOnMaxFunctionExecutionTime;
437
438 // Abort this thread
439 AbortThreadClass(EventQueueThread);
440
441 // We do not need to start another, MaintenenceThread will do that for us
442 //StartNewThreadClass();
443 }
444 }
445 }
446 }
447 }
448 #endregion
449
450 ///// <summary>
451 ///// If set to true then threads and stuff should try to make a graceful exit
452 ///// </summary>
453 //public bool PleaseShutdown
454 //{
455 // get { return _PleaseShutdown; }
456 // set { _PleaseShutdown = value; }
457 //}
458 //private bool _PleaseShutdown = false;
459 }
460}
diff --git a/OpenSim/Region/ScriptEngine/DotNetEngine/EventQueueThreadClass.cs b/OpenSim/Region/ScriptEngine/DotNetEngine/EventQueueThreadClass.cs
deleted file mode 100644
index 51fd41a..0000000
--- a/OpenSim/Region/ScriptEngine/DotNetEngine/EventQueueThreadClass.cs
+++ /dev/null
@@ -1,428 +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 OpenSimulator 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
28using System;
29using System.Collections;
30using System.Collections.Generic;
31using System.Reflection;
32using System.Text.RegularExpressions;
33using System.Threading;
34using System.Globalization;
35using OpenMetaverse;
36using log4net;
37using OpenSim.Framework;
38using OpenSim.Region.Framework.Scenes;
39using OpenSim.Region.Framework.Scenes.Scripting;
40using OpenSim.Region.ScriptEngine.Shared;
41using OpenSim.Region.ScriptEngine.Shared.CodeTools;
42
43namespace OpenSim.Region.ScriptEngine.DotNetEngine
44{
45 // Because every thread needs some data set for it
46 // (time started to execute current function), it will do its work
47 // within a class
48 public class EventQueueThreadClass
49 {
50 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
51
52 // How many ms to sleep if queue is empty
53 private static int nothingToDoSleepms;// = 50;
54 private static ThreadPriority MyThreadPriority;
55
56 public long LastExecutionStarted;
57 public bool InExecution = false;
58 public bool KillCurrentScript = false;
59
60 //private EventQueueManager eventQueueManager;
61 public Thread EventQueueThread;
62 private static int ThreadCount = 0;
63
64 private string ScriptEngineName = "ScriptEngine.Common";
65
66 public EventQueueThreadClass()//EventQueueManager eqm
67 {
68 CultureInfo USCulture = new CultureInfo("en-US");
69 Thread.CurrentThread.CurrentCulture = USCulture;
70
71 //eventQueueManager = eqm;
72 ReadConfig();
73 Start();
74 }
75
76 ~EventQueueThreadClass()
77 {
78 Stop();
79 }
80
81 public void ReadConfig()
82 {
83 lock (ScriptEngine.ScriptEngines)
84 {
85 foreach (ScriptEngine m_ScriptEngine in
86 ScriptEngine.ScriptEngines)
87 {
88 ScriptEngineName = m_ScriptEngine.ScriptEngineName;
89 nothingToDoSleepms =
90 m_ScriptEngine.ScriptConfigSource.GetInt(
91 "SleepTimeIfNoScriptExecutionMs", 50);
92
93 string pri = m_ScriptEngine.ScriptConfigSource.GetString(
94 "ScriptThreadPriority", "BelowNormal");
95
96 switch (pri.ToLower())
97 {
98 case "lowest":
99 MyThreadPriority = ThreadPriority.Lowest;
100 break;
101 case "belownormal":
102 MyThreadPriority = ThreadPriority.BelowNormal;
103 break;
104 case "normal":
105 MyThreadPriority = ThreadPriority.Normal;
106 break;
107 case "abovenormal":
108 MyThreadPriority = ThreadPriority.AboveNormal;
109 break;
110 case "highest":
111 MyThreadPriority = ThreadPriority.Highest;
112 break;
113 default:
114 MyThreadPriority = ThreadPriority.BelowNormal;
115 m_log.Error(
116 "[ScriptEngine.DotNetEngine]: Unknown "+
117 "priority type \"" + pri +
118 "\" in config file. Defaulting to "+
119 "\"BelowNormal\".");
120 break;
121 }
122 }
123 }
124 // Now set that priority
125 if (EventQueueThread != null)
126 if (EventQueueThread.IsAlive)
127 EventQueueThread.Priority = MyThreadPriority;
128 }
129
130 /// <summary>
131 /// Start thread
132 /// </summary>
133 private void Start()
134 {
135 EventQueueThread = Watchdog.StartThread(EventQueueThreadLoop, "EventQueueManagerThread_" + ThreadCount, MyThreadPriority, true);
136
137 // Look at this... Don't you wish everyone did that solid
138 // coding everywhere? :P
139
140 if (ThreadCount == int.MaxValue)
141 ThreadCount = 0;
142
143 ThreadCount++;
144 }
145
146 public void Stop()
147 {
148 if (EventQueueThread != null && EventQueueThread.IsAlive == true)
149 {
150 try
151 {
152 EventQueueThread.Abort(); // Send abort
153 }
154 catch (Exception)
155 {
156 }
157 }
158 }
159
160 private EventQueueManager.QueueItemStruct BlankQIS =
161 new EventQueueManager.QueueItemStruct();
162
163 private ScriptEngine lastScriptEngine;
164 private uint lastLocalID;
165 private UUID lastItemID;
166
167 // Queue processing thread loop
168 private void EventQueueThreadLoop()
169 {
170 CultureInfo USCulture = new CultureInfo("en-US");
171 Thread.CurrentThread.CurrentCulture = USCulture;
172
173 try
174 {
175 while (true)
176 {
177 try
178 {
179 while (true)
180 {
181 DoProcessQueue();
182 Watchdog.UpdateThread();
183 }
184 }
185 catch (ThreadAbortException)
186 {
187 m_log.Info("[" + ScriptEngineName +
188 "]: ThreadAbortException while executing "+
189 "function.");
190 }
191 catch (SelfDeleteException) // Must delete SOG
192 {
193 SceneObjectPart part =
194 lastScriptEngine.World.GetSceneObjectPart(
195 lastLocalID);
196 if (part != null && part.ParentGroup != null)
197 lastScriptEngine.World.DeleteSceneObject(
198 part.ParentGroup, false);
199 }
200 catch (ScriptDeleteException) // Must delete item
201 {
202 SceneObjectPart part =
203 lastScriptEngine.World.GetSceneObjectPart(
204 lastLocalID);
205 if (part != null && part.ParentGroup != null)
206 part.Inventory.RemoveInventoryItem(lastItemID);
207 }
208 catch (Exception e)
209 {
210 m_log.ErrorFormat("[{0}]: Exception {1} thrown", ScriptEngineName, e.GetType().ToString());
211 throw e;
212 }
213
214 Watchdog.UpdateThread();
215 }
216 }
217 catch (ThreadAbortException)
218 {
219 }
220 catch (Exception e)
221 {
222 // TODO: Let users in the sim and those entering it and possibly an external watchdog know what has happened
223 m_log.ErrorFormat(
224 "[{0}]: Event queue thread terminating with exception. PLEASE REBOOT YOUR SIM - SCRIPT EVENTS WILL NOT WORK UNTIL YOU DO. Exception is {1}",
225 ScriptEngineName, e);
226 }
227
228 Watchdog.RemoveThread();
229 }
230
231 public void DoProcessQueue()
232 {
233 foreach (ScriptEngine m_ScriptEngine in
234 new ArrayList(ScriptEngine.ScriptEngines))
235 {
236 lastScriptEngine = m_ScriptEngine;
237
238 EventQueueManager.QueueItemStruct QIS = BlankQIS;
239 bool GotItem = false;
240
241 //if (PleaseShutdown)
242 // return;
243
244 if (m_ScriptEngine.m_EventQueueManager == null ||
245 m_ScriptEngine.m_EventQueueManager.eventQueue == null)
246 continue;
247
248 if (m_ScriptEngine.m_EventQueueManager.eventQueue.Count == 0)
249 {
250 // Nothing to do? Sleep a bit waiting for something to do
251 Thread.Sleep(nothingToDoSleepms);
252 }
253 else
254 {
255 // Something in queue, process
256
257 // OBJECT BASED LOCK - TWO THREADS WORKING ON SAME
258 // OBJECT IS NOT GOOD
259 lock (m_ScriptEngine.m_EventQueueManager.eventQueue)
260 {
261 GotItem = false;
262 for (int qc = 0; qc < m_ScriptEngine.m_EventQueueManager.eventQueue.Count; qc++)
263 {
264 // Get queue item
265 QIS = m_ScriptEngine.m_EventQueueManager.eventQueue.Dequeue();
266
267 // Check if object is being processed by
268 // someone else
269 if (m_ScriptEngine.m_EventQueueManager.TryLock(
270 QIS.localID) == false)
271 {
272 // Object is already being processed, requeue it
273 m_ScriptEngine.m_EventQueueManager.
274 eventQueue.Enqueue(QIS);
275 }
276 else
277 {
278 // We have lock on an object and can process it
279 GotItem = true;
280 break;
281 }
282 }
283 }
284
285 if (GotItem == true)
286 {
287 // Execute function
288 try
289 {
290 // Only pipe event if land supports it.
291 if (m_ScriptEngine.World.PipeEventsForScript(
292 QIS.localID))
293 {
294 lastLocalID = QIS.localID;
295 lastItemID = QIS.itemID;
296 LastExecutionStarted = DateTime.Now.Ticks;
297 KillCurrentScript = false;
298 InExecution = true;
299 m_ScriptEngine.m_ScriptManager.ExecuteEvent(
300 QIS.localID,
301 QIS.itemID,
302 QIS.functionName,
303 QIS.llDetectParams,
304 QIS.param);
305
306 InExecution = false;
307 }
308 }
309 catch (TargetInvocationException tie)
310 {
311 Exception e = tie.InnerException;
312
313 if (e is SelfDeleteException) // Forward it
314 throw e;
315
316 InExecution = false;
317 string text = FormatException(tie, QIS.LineMap);
318
319 // DISPLAY ERROR INWORLD
320
321// if (e.InnerException != null)
322// {
323// // Send inner exception
324// string line = " (unknown line)";
325// Regex rx = new Regex(@"SecondLife\.Script\..+[\s:](?<line>\d+)\.?\r?$", RegexOptions.Compiled);
326// if (rx.Match(e.InnerException.ToString()).Success)
327// line = " (line " + rx.Match(e.InnerException.ToString()).Result("${line}") + ")";
328// text += e.InnerException.Message.ToString() + line;
329// }
330// else
331// {
332// text += "\r\n";
333// // Send normal
334// text += e.Message.ToString();
335// }
336// if (KillCurrentScript)
337// text += "\r\nScript will be deactivated!";
338
339 try
340 {
341 if (text.Length >= 1100)
342 text = text.Substring(0, 1099);
343 IScriptHost m_host =
344 m_ScriptEngine.World.GetSceneObjectPart(QIS.localID);
345 m_ScriptEngine.World.SimChat(
346 Utils.StringToBytes(text),
347 ChatTypeEnum.DebugChannel, 2147483647,
348 m_host.AbsolutePosition,
349 m_host.Name, m_host.UUID, false);
350 }
351 catch (Exception)
352 {
353 m_log.Error("[" +
354 ScriptEngineName + "]: " +
355 "Unable to send text in-world:\r\n" +
356 text);
357 }
358 finally
359 {
360 // So we are done sending message in-world
361 if (KillCurrentScript)
362 {
363 m_ScriptEngine.m_EventQueueManager.
364 m_ScriptEngine.m_ScriptManager.
365 StopScript(
366 QIS.localID, QIS.itemID);
367 }
368 }
369 }
370 catch (Exception)
371 {
372 throw;
373 }
374 finally
375 {
376 InExecution = false;
377 m_ScriptEngine.m_EventQueueManager.ReleaseLock(
378 QIS.localID);
379 }
380 }
381 }
382 }
383 }
384
385 string FormatException(Exception e, Dictionary<KeyValuePair<int,int>,
386 KeyValuePair<int,int>> LineMap)
387 {
388 if (e.InnerException == null)
389 return e.ToString();
390
391 string message = "Runtime error:\n" + e.InnerException.StackTrace;
392 string[] lines = message.Split(new char[] {'\n'});
393
394 foreach (string line in lines)
395 {
396 if (line.Contains("SecondLife.Script"))
397 {
398 int idx = line.IndexOf(':');
399 if (idx != -1)
400 {
401 string val = line.Substring(idx+1);
402 int lineNum = 0;
403 if (int.TryParse(val, out lineNum))
404 {
405 KeyValuePair<int, int> pos =
406 Compiler.FindErrorPosition(
407 lineNum, 0, LineMap);
408
409 int scriptLine = pos.Key;
410 int col = pos.Value;
411 if (scriptLine == 0)
412 scriptLine++;
413 if (col == 0)
414 col++;
415 message = string.Format("Runtime error:\n" +
416 "Line ({0}): {1}", scriptLine - 1,
417 e.InnerException.Message);
418
419 return message;
420 }
421 }
422 }
423 }
424
425 return message;
426 }
427 }
428}
diff --git a/OpenSim/Region/ScriptEngine/DotNetEngine/MaintenanceThread.cs b/OpenSim/Region/ScriptEngine/DotNetEngine/MaintenanceThread.cs
deleted file mode 100644
index 87fdf1f..0000000
--- a/OpenSim/Region/ScriptEngine/DotNetEngine/MaintenanceThread.cs
+++ /dev/null
@@ -1,238 +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 OpenSimulator 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
28using System;
29using System.Collections;
30using System.Reflection;
31using System.Threading;
32using log4net;
33using OpenSim.Framework;
34
35namespace OpenSim.Region.ScriptEngine.DotNetEngine
36{
37 /// <summary>
38 /// This class does maintenance on script engine.
39 /// </summary>
40 public class MaintenanceThread
41 {
42 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
43
44 //public ScriptEngine m_ScriptEngine;
45 private int MaintenanceLoopms;
46 private int MaintenanceLoopTicks_ScriptLoadUnload;
47 private int MaintenanceLoopTicks_Other;
48
49
50 public MaintenanceThread()
51 {
52 //m_ScriptEngine = _ScriptEngine;
53
54 ReadConfig();
55
56 // Start maintenance thread
57 StartMaintenanceThread();
58 }
59
60 ~MaintenanceThread()
61 {
62 StopMaintenanceThread();
63 }
64
65 public void ReadConfig()
66 {
67 // Bad hack, but we need a m_ScriptEngine :)
68 lock (ScriptEngine.ScriptEngines)
69 {
70 foreach (ScriptEngine m_ScriptEngine in ScriptEngine.ScriptEngines)
71 {
72 MaintenanceLoopms = m_ScriptEngine.ScriptConfigSource.GetInt("MaintenanceLoopms", 50);
73 MaintenanceLoopTicks_ScriptLoadUnload =
74 m_ScriptEngine.ScriptConfigSource.GetInt("MaintenanceLoopTicks_ScriptLoadUnload", 1);
75 MaintenanceLoopTicks_Other =
76 m_ScriptEngine.ScriptConfigSource.GetInt("MaintenanceLoopTicks_Other", 10);
77
78 return;
79 }
80 }
81 }
82
83 #region " Maintenance thread "
84 /// <summary>
85 /// Maintenance thread. Enforcing max execution time for example.
86 /// </summary>
87 public Thread MaintenanceThreadThread;
88
89 /// <summary>
90 /// Starts maintenance thread
91 /// </summary>
92 private void StartMaintenanceThread()
93 {
94 if (MaintenanceThreadThread == null)
95 {
96 MaintenanceThreadThread = Watchdog.StartThread(MaintenanceLoop, "ScriptMaintenanceThread", ThreadPriority.Normal, true);
97 }
98 }
99
100 /// <summary>
101 /// Stops maintenance thread
102 /// </summary>
103 private void StopMaintenanceThread()
104 {
105#if DEBUG
106 //m_log.Debug("[" + m_ScriptEngine.ScriptEngineName + "]: StopMaintenanceThread() called");
107#endif
108 //PleaseShutdown = true;
109 Thread.Sleep(100);
110 try
111 {
112 if (MaintenanceThreadThread != null && MaintenanceThreadThread.IsAlive)
113 {
114 MaintenanceThreadThread.Abort();
115 }
116 }
117 catch (Exception)
118 {
119 //m_log.Error("[" + m_ScriptEngine.ScriptEngineName + "]: Exception stopping maintenence thread: " + ex.ToString());
120 }
121 }
122
123 // private ScriptEngine lastScriptEngine; // Keep track of what ScriptEngine instance we are at so we can give exception
124 /// <summary>
125 /// A thread should run in this loop and check all running scripts
126 /// </summary>
127 public void MaintenanceLoop()
128 {
129 //if (m_ScriptEngine.m_EventQueueManager.maxFunctionExecutionTimens < MaintenanceLoopms)
130 // m_log.Warn("[" + m_ScriptEngine.ScriptEngineName + "]: " +
131 // "Configuration error: MaxEventExecutionTimeMs is less than MaintenanceLoopms. The Maintenance Loop will only check scripts once per run.");
132
133 long Last_maxFunctionExecutionTimens = 0; // DateTime.Now.Ticks;
134 long Last_ReReadConfigFilens = DateTime.Now.Ticks;
135 int MaintenanceLoopTicks_ScriptLoadUnload_Count = 0;
136 int MaintenanceLoopTicks_Other_Count = 0;
137 bool MaintenanceLoopTicks_ScriptLoadUnload_ResetCount = false;
138 bool MaintenanceLoopTicks_Other_ResetCount = false;
139
140 while (true)
141 {
142 try
143 {
144 while (true)
145 {
146 Thread.Sleep(MaintenanceLoopms); // Sleep before next pass
147
148 // Reset counters?
149 if (MaintenanceLoopTicks_ScriptLoadUnload_ResetCount)
150 {
151 MaintenanceLoopTicks_ScriptLoadUnload_ResetCount = false;
152 MaintenanceLoopTicks_ScriptLoadUnload_Count = 0;
153 }
154 if (MaintenanceLoopTicks_Other_ResetCount)
155 {
156 MaintenanceLoopTicks_Other_ResetCount = false;
157 MaintenanceLoopTicks_Other_Count = 0;
158 }
159
160 // Increase our counters
161 MaintenanceLoopTicks_ScriptLoadUnload_Count++;
162 MaintenanceLoopTicks_Other_Count++;
163
164 foreach (ScriptEngine m_ScriptEngine in new ArrayList(ScriptEngine.ScriptEngines))
165 {
166 // lastScriptEngine = m_ScriptEngine;
167 // Re-reading config every x seconds
168 if (MaintenanceLoopTicks_Other_Count >= MaintenanceLoopTicks_Other)
169 {
170 MaintenanceLoopTicks_Other_ResetCount = true;
171 if (m_ScriptEngine.RefreshConfigFilens > 0)
172 {
173 // Check if its time to re-read config
174 if (DateTime.Now.Ticks - Last_ReReadConfigFilens >
175 m_ScriptEngine.RefreshConfigFilens)
176 {
177 //m_log.Debug("Time passed: " + (DateTime.Now.Ticks - Last_ReReadConfigFilens) + ">" + m_ScriptEngine.RefreshConfigFilens);
178 // Its time to re-read config file
179 m_ScriptEngine.ReadConfig();
180 Last_ReReadConfigFilens = DateTime.Now.Ticks; // Reset time
181 }
182
183
184 // Adjust number of running script threads if not correct
185 if (m_ScriptEngine.m_EventQueueManager != null)
186 m_ScriptEngine.m_EventQueueManager.AdjustNumberOfScriptThreads();
187
188 // Check if any script has exceeded its max execution time
189 if (EventQueueManager.EnforceMaxExecutionTime)
190 {
191 // We are enforcing execution time
192 if (DateTime.Now.Ticks - Last_maxFunctionExecutionTimens >
193 EventQueueManager.maxFunctionExecutionTimens)
194 {
195 // Its time to check again
196 m_ScriptEngine.m_EventQueueManager.CheckScriptMaxExecTime(); // Do check
197 Last_maxFunctionExecutionTimens = DateTime.Now.Ticks; // Reset time
198 }
199 }
200 }
201 }
202 if (MaintenanceLoopTicks_ScriptLoadUnload_Count >= MaintenanceLoopTicks_ScriptLoadUnload)
203 {
204 MaintenanceLoopTicks_ScriptLoadUnload_ResetCount = true;
205 // LOAD / UNLOAD SCRIPTS
206 if (m_ScriptEngine.m_ScriptManager != null)
207 m_ScriptEngine.m_ScriptManager.DoScriptLoadUnload();
208 }
209 }
210
211 Watchdog.UpdateThread();
212 }
213 }
214 catch(ThreadAbortException)
215 {
216 m_log.Error("Thread aborted in MaintenanceLoopThread. If this is during shutdown, please ignore");
217 }
218 catch (Exception ex)
219 {
220 m_log.ErrorFormat("Exception in MaintenanceLoopThread. Thread will recover after 5 sec throttle. Exception: {0}", ex.ToString());
221 }
222 }
223
224 Watchdog.RemoveThread();
225 }
226 #endregion
227
228 ///// <summary>
229 ///// If set to true then threads and stuff should try to make a graceful exit
230 ///// </summary>
231 //public bool PleaseShutdown
232 //{
233 // get { return _PleaseShutdown; }
234 // set { _PleaseShutdown = value; }
235 //}
236 //private bool _PleaseShutdown = false;
237 }
238}
diff --git a/OpenSim/Region/ScriptEngine/DotNetEngine/Properties/AssemblyInfo.cs b/OpenSim/Region/ScriptEngine/DotNetEngine/Properties/AssemblyInfo.cs
deleted file mode 100644
index 4c4c5e7..0000000
--- a/OpenSim/Region/ScriptEngine/DotNetEngine/Properties/AssemblyInfo.cs
+++ /dev/null
@@ -1,65 +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 OpenSimulator 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
28using System.Reflection;
29using System.Runtime.InteropServices;
30
31// General information about an assembly is controlled through the following
32// set of attributes. Change these attribute values to modify the information
33// associated with an assembly.
34
35[assembly : AssemblyTitle("OpenSim.Region.ScriptEngine.DotNetEngine")]
36[assembly : AssemblyDescription("")]
37[assembly : AssemblyConfiguration("")]
38[assembly : AssemblyCompany("http://opensimulator.org")]
39[assembly : AssemblyProduct("OpenSim.Region.ScriptEngine.DotNetEngine")]
40[assembly : AssemblyCopyright("Copyright (c) OpenSimulator.org Developers 2007-2009")]
41[assembly : AssemblyTrademark("")]
42[assembly : AssemblyCulture("")]
43
44// Setting ComVisible to false makes the types in this assembly not visible
45// to COM components. If you need to access a type in this assembly from
46// COM, set the ComVisible attribute to true on that type.
47
48[assembly : ComVisible(false)]
49
50// The following GUID is for the ID of the typelib if this project is exposed to COM
51
52[assembly : Guid("2842257e-6fde-4460-9368-4cde57fa9cc4")]
53
54// Version information for an assembly consists of the following four values:
55//
56// Major Version
57// Minor Version
58// Build Number
59// Revision
60//
61// You can specify all the values or you can default the Revision and Build Numbers
62// by using the '*' as shown below:
63
64[assembly : AssemblyVersion("0.6.5.*")]
65[assembly : AssemblyFileVersion("0.6.5.0")]
diff --git a/OpenSim/Region/ScriptEngine/DotNetEngine/Resources/DotNetEngine.addin.xml b/OpenSim/Region/ScriptEngine/DotNetEngine/Resources/DotNetEngine.addin.xml
deleted file mode 100644
index 78a8dca..0000000
--- a/OpenSim/Region/ScriptEngine/DotNetEngine/Resources/DotNetEngine.addin.xml
+++ /dev/null
@@ -1,13 +0,0 @@
1<Addin id="OpenSim.Region.ScriptEngine.DotNetEngine" version="0.2">
2 <Runtime>
3 <Import assembly="OpenSim.Region.ScriptEngine.DotNetEngine.dll"/>
4 </Runtime>
5
6 <Dependencies>
7 <Addin id="OpenSim" version="0.5" />
8 </Dependencies>
9
10 <Extension path = "/OpenSim/RegionModules">
11 <RegionModule id="DotNetEngine" type="OpenSim.Region.ScriptEngine.DotNetEngine.ScriptEngine" />
12 </Extension>
13</Addin>
diff --git a/OpenSim/Region/ScriptEngine/DotNetEngine/ScriptEngine.cs b/OpenSim/Region/ScriptEngine/DotNetEngine/ScriptEngine.cs
deleted file mode 100644
index 9806218..0000000
--- a/OpenSim/Region/ScriptEngine/DotNetEngine/ScriptEngine.cs
+++ /dev/null
@@ -1,485 +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 OpenSimulator 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
28using System;
29using System.Collections.Generic;
30using System.Reflection;
31using log4net;
32using Nini.Config;
33using OpenSim.Framework;
34using OpenSim.Region.CoreModules.Framework.EventQueue;
35using OpenSim.Region.Framework.Interfaces;
36using OpenSim.Region.Framework.Scenes;
37using OpenSim.Region.ScriptEngine.Interfaces;
38using OpenMetaverse;
39using OpenMetaverse.StructuredData;
40using OpenSim.Region.ScriptEngine.Shared;
41using OpenSim.Region.ScriptEngine.Shared.ScriptBase;
42
43namespace OpenSim.Region.ScriptEngine.DotNetEngine
44{
45 [Serializable]
46 public class ScriptEngine : INonSharedRegionModule, IScriptEngine, IScriptModule
47 {
48 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
49
50 public static List<ScriptEngine> ScriptEngines =
51 new List<ScriptEngine>();
52
53 private Scene m_Scene;
54 public Scene World
55 {
56 get { return m_Scene; }
57 }
58
59 // Handles and queues incoming events from OpenSim
60 public EventManager m_EventManager;
61
62 // Executes events, handles script threads
63 public EventQueueManager m_EventQueueManager;
64
65 // Load, unload and execute scripts
66 public ScriptManager m_ScriptManager;
67
68 // Handles loading/unloading of scripts into AppDomains
69 public AppDomainManager m_AppDomainManager;
70
71 // Thread that does different kinds of maintenance,
72 // for example refreshing config and killing scripts
73 // that has been running too long
74 public static MaintenanceThread m_MaintenanceThread;
75
76 private IConfigSource m_ConfigSource;
77 public IConfig ScriptConfigSource;
78 private bool m_enabled = false;
79
80 public IConfig Config
81 {
82 get { return ScriptConfigSource; }
83 }
84
85 public IConfigSource ConfigSource
86 {
87 get { return m_ConfigSource; }
88 }
89
90 // How many seconds between re-reading config-file.
91 // 0 = never. ScriptEngine will try to adjust to new config changes.
92 public int RefreshConfigFileSeconds {
93 get { return (int)(RefreshConfigFilens / 10000000); }
94 set { RefreshConfigFilens = value * 10000000; }
95 }
96
97 public long RefreshConfigFilens;
98
99 public string ScriptEngineName
100 {
101 get { return "ScriptEngine.DotNetEngine"; }
102 }
103
104 public IScriptModule ScriptModule
105 {
106 get { return this; }
107 }
108
109 public event ScriptRemoved OnScriptRemoved;
110 public event ObjectRemoved OnObjectRemoved;
111
112 public ScriptEngine()
113 {
114 // For logging, just need any instance, doesn't matter
115 Common.mySE = this;
116
117 lock (ScriptEngines)
118 {
119 // Keep a list of ScriptEngines for shared threads
120 // to process all instances
121 ScriptEngines.Add(this);
122 }
123 }
124
125 public void Initialise(IConfigSource config)
126 {
127 m_ConfigSource = config;
128 }
129
130 public void AddRegion(Scene Sceneworld)
131 {
132 // Make sure we have config
133 if (ConfigSource.Configs[ScriptEngineName] == null)
134 ConfigSource.AddConfig(ScriptEngineName);
135
136 ScriptConfigSource = ConfigSource.Configs[ScriptEngineName];
137
138 m_enabled = ScriptConfigSource.GetBoolean("Enabled", true);
139 if (!m_enabled)
140 return;
141
142 m_log.Info("[" + ScriptEngineName + "]: ScriptEngine initializing");
143
144 m_Scene = Sceneworld;
145
146 // Create all objects we'll be using
147 m_EventQueueManager = new EventQueueManager(this);
148 m_EventManager = new EventManager(this, true);
149
150 // We need to start it
151 m_ScriptManager = new ScriptManager(this);
152 m_ScriptManager.Setup();
153 m_AppDomainManager = new AppDomainManager(this);
154 if (m_MaintenanceThread == null)
155 m_MaintenanceThread = new MaintenanceThread();
156
157 m_log.Info("[" + ScriptEngineName + "]: Reading configuration "+
158 "from config section \"" + ScriptEngineName + "\"");
159
160 ReadConfig();
161
162 m_Scene.StackModuleInterface<IScriptModule>(this);
163 }
164
165 public void RemoveRegion(Scene scene)
166 {
167 }
168
169 public void RegionLoaded(Scene scene)
170 {
171 if (!m_enabled)
172 return;
173
174 m_EventManager.HookUpEvents();
175
176 m_Scene.EventManager.OnScriptReset += OnScriptReset;
177 m_Scene.EventManager.OnGetScriptRunning += OnGetScriptRunning;
178 m_Scene.EventManager.OnStartScript += OnStartScript;
179 m_Scene.EventManager.OnStopScript += OnStopScript;
180
181 m_ScriptManager.Start();
182 }
183
184 public void Shutdown()
185 {
186 // We are shutting down
187 lock (ScriptEngines)
188 {
189 ScriptEngines.Remove(this);
190 }
191 }
192
193 public void ReadConfig()
194 {
195 RefreshConfigFileSeconds = ScriptConfigSource.GetInt("RefreshConfig", 0);
196
197 if (m_EventQueueManager != null) m_EventQueueManager.ReadConfig();
198 if (m_EventManager != null) m_EventManager.ReadConfig();
199 if (m_ScriptManager != null) m_ScriptManager.ReadConfig();
200 if (m_AppDomainManager != null) m_AppDomainManager.ReadConfig();
201 if (m_MaintenanceThread != null) m_MaintenanceThread.ReadConfig();
202 }
203
204 #region IRegionModule
205
206 public void Close()
207 {
208 }
209
210 public Type ReplaceableInterface
211 {
212 get { return null; }
213 }
214
215 public string Name
216 {
217 get { return "Common." + ScriptEngineName; }
218 }
219
220 public bool IsSharedModule
221 {
222 get { return false; }
223 }
224
225 public bool PostObjectEvent(uint localID, EventParams p)
226 {
227 return m_EventQueueManager.AddToObjectQueue(localID, p.EventName,
228 p.DetectParams, p.Params);
229 }
230
231 public bool PostScriptEvent(UUID itemID, EventParams p)
232 {
233 uint localID = m_ScriptManager.GetLocalID(itemID);
234 return m_EventQueueManager.AddToScriptQueue(localID, itemID,
235 p.EventName, p.DetectParams, p.Params);
236 }
237
238 public bool PostScriptEvent(UUID itemID, string name, Object[] p)
239 {
240 Object[] lsl_p = new Object[p.Length];
241 for (int i = 0; i < p.Length ; i++)
242 {
243 if (p[i] is int)
244 lsl_p[i] = new LSL_Types.LSLInteger((int)p[i]);
245 else if (p[i] is string)
246 lsl_p[i] = new LSL_Types.LSLString((string)p[i]);
247 else if (p[i] is Vector3)
248 lsl_p[i] = new LSL_Types.Vector3(((Vector3)p[i]).X, ((Vector3)p[i]).Y, ((Vector3)p[i]).Z);
249 else if (p[i] is Quaternion)
250 lsl_p[i] = new LSL_Types.Quaternion(((Quaternion)p[i]).X, ((Quaternion)p[i]).Y, ((Quaternion)p[i]).Z, ((Quaternion)p[i]).W);
251 else if (p[i] is float)
252 lsl_p[i] = new LSL_Types.LSLFloat((float)p[i]);
253 else
254 lsl_p[i] = p[i];
255 }
256
257 return PostScriptEvent(itemID, new EventParams(name, lsl_p, new DetectParams[0]));
258 }
259
260 public bool PostObjectEvent(UUID itemID, string name, Object[] p)
261 {
262 SceneObjectPart part = m_Scene.GetSceneObjectPart(itemID);
263 if (part == null)
264 return false;
265
266 Object[] lsl_p = new Object[p.Length];
267 for (int i = 0; i < p.Length ; i++)
268 {
269 if (p[i] is int)
270 lsl_p[i] = new LSL_Types.LSLInteger((int)p[i]);
271 else if (p[i] is string)
272 lsl_p[i] = new LSL_Types.LSLString((string)p[i]);
273 else if (p[i] is Vector3)
274 lsl_p[i] = new LSL_Types.Vector3(((Vector3)p[i]).X, ((Vector3)p[i]).Y, ((Vector3)p[i]).Z);
275 else if (p[i] is Quaternion)
276 lsl_p[i] = new LSL_Types.Quaternion(((Quaternion)p[i]).X, ((Quaternion)p[i]).Y, ((Quaternion)p[i]).Z, ((Quaternion)p[i]).W);
277 else if (p[i] is float)
278 lsl_p[i] = new LSL_Types.LSLFloat((float)p[i]);
279 else
280 lsl_p[i] = p[i];
281 }
282
283 return PostObjectEvent(part.LocalId, new EventParams(name, lsl_p, new DetectParams[0]));
284 }
285
286 public DetectParams GetDetectParams(UUID itemID, int number)
287 {
288 uint localID = m_ScriptManager.GetLocalID(itemID);
289 if (localID == 0)
290 return null;
291
292 InstanceData id = m_ScriptManager.GetScript(localID, itemID);
293
294 if (id == null)
295 return null;
296
297 DetectParams[] det = m_ScriptManager.GetDetectParams(id);
298
299 if (number < 0 || number >= det.Length)
300 return null;
301
302 return det[number];
303 }
304
305 public int GetStartParameter(UUID itemID)
306 {
307 return m_ScriptManager.GetStartParameter(itemID);
308 }
309
310 public void SetMinEventDelay(UUID itemID, double delay)
311 {
312 // TODO in DotNet, done in XEngine
313 throw new NotImplementedException();
314 }
315
316 #endregion
317
318 public void SetState(UUID itemID, string state)
319 {
320 uint localID = m_ScriptManager.GetLocalID(itemID);
321 if (localID == 0)
322 return;
323
324 InstanceData id = m_ScriptManager.GetScript(localID, itemID);
325
326 if (id == null)
327 return;
328
329 string currentState = id.State;
330
331 if (currentState != state)
332 {
333 try
334 {
335 m_EventManager.state_exit(localID);
336
337 }
338 catch (AppDomainUnloadedException)
339 {
340 m_log.Error("[SCRIPT]: state change called when "+
341 "script was unloaded. Nothing to worry about, "+
342 "but noting the occurance");
343 }
344
345 id.State = state;
346
347 try
348 {
349 int eventFlags = m_ScriptManager.GetStateEventFlags(localID,
350 itemID);
351
352 SceneObjectPart part = m_Scene.GetSceneObjectPart(localID);
353 if (part != null)
354 part.SetScriptEvents(itemID, eventFlags);
355
356 m_EventManager.state_entry(localID);
357 }
358 catch (AppDomainUnloadedException)
359 {
360 m_log.Error("[SCRIPT]: state change called when "+
361 "script was unloaded. Nothing to worry about, but "+
362 "noting the occurance");
363 }
364 }
365 }
366
367 public bool GetScriptState(UUID itemID)
368 {
369 uint localID = m_ScriptManager.GetLocalID(itemID);
370 if (localID == 0)
371 return false;
372
373 InstanceData id = m_ScriptManager.GetScript(localID, itemID);
374 if (id == null)
375 return false;
376
377 return id.Running;
378 }
379
380 public void SetScriptState(UUID itemID, bool state)
381 {
382 uint localID = m_ScriptManager.GetLocalID(itemID);
383 if (localID == 0)
384 return;
385
386 InstanceData id = m_ScriptManager.GetScript(localID, itemID);
387 if (id == null)
388 return;
389
390 if (!id.Disabled)
391 id.Running = state;
392 }
393
394 public void ApiResetScript(UUID itemID)
395 {
396 uint localID = m_ScriptManager.GetLocalID(itemID);
397 if (localID == 0)
398 return;
399
400 m_ScriptManager.ResetScript(localID, itemID);
401 }
402
403 public void ResetScript(UUID itemID)
404 {
405 uint localID = m_ScriptManager.GetLocalID(itemID);
406 if (localID == 0)
407 return;
408
409 m_ScriptManager.ResetScript(localID, itemID);
410 }
411
412 public void OnScriptReset(uint localID, UUID itemID)
413 {
414 ResetScript(itemID);
415 }
416
417 public void OnStartScript(uint localID, UUID itemID)
418 {
419 InstanceData id = m_ScriptManager.GetScript(localID, itemID);
420 if (id == null)
421 return;
422
423 if (!id.Disabled)
424 id.Running = true;
425 }
426
427 public void OnStopScript(uint localID, UUID itemID)
428 {
429 InstanceData id = m_ScriptManager.GetScript(localID, itemID);
430 if (id == null)
431 return;
432
433 id.Running = false;
434 }
435
436 public void OnGetScriptRunning(IClientAPI controllingClient,
437 UUID objectID, UUID itemID)
438 {
439 uint localID = m_ScriptManager.GetLocalID(itemID);
440 if (localID == 0)
441 return;
442
443 InstanceData id = m_ScriptManager.GetScript(localID, itemID);
444 if (id == null)
445 return;
446
447 IEventQueue eq = World.RequestModuleInterface<IEventQueue>();
448 if (eq == null)
449 {
450 controllingClient.SendScriptRunningReply(objectID, itemID,
451 id.Running);
452 }
453 else
454 {
455 eq.Enqueue(EventQueueHelper.ScriptRunningReplyEvent(objectID, itemID, id.Running, true),
456 controllingClient.AgentId);
457 }
458 }
459
460 public IScriptApi GetApi(UUID itemID, string name)
461 {
462 return m_ScriptManager.GetApi(itemID, name);
463 }
464
465 public IScriptWorkItem QueueEventHandler(Object o)
466 {
467 return null;
468 }
469
470 public string GetAssemblyName(UUID itemID)
471 {
472 return "";
473 }
474
475 public string GetXMLState(UUID itemID)
476 {
477 return "";
478 }
479
480 public bool CanBeDeleted(UUID itemID)
481 {
482 return true;
483 }
484 }
485}
diff --git a/OpenSim/Region/ScriptEngine/DotNetEngine/ScriptManager.cs b/OpenSim/Region/ScriptEngine/DotNetEngine/ScriptManager.cs
deleted file mode 100644
index 6ac209e..0000000
--- a/OpenSim/Region/ScriptEngine/DotNetEngine/ScriptManager.cs
+++ /dev/null
@@ -1,703 +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 OpenSimulator 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
28using System;
29using System.Reflection;
30using System.Globalization;
31using System.Runtime.Remoting;
32using System.Runtime.Remoting.Lifetime;
33using log4net;
34using OpenMetaverse;
35using OpenSim.Framework;
36using OpenSim.Region.Framework.Scenes;
37using OpenSim.Region.ScriptEngine.Interfaces;
38using OpenSim.Region.ScriptEngine.Shared;
39using OpenSim.Region.ScriptEngine.Shared.Api;
40using System.Collections.Generic;
41using System.IO;
42using System.Runtime.Serialization.Formatters.Binary;
43using System.Threading;
44using OpenSim.Region.ScriptEngine.Shared.Api.Runtime;
45using OpenSim.Region.ScriptEngine.Shared.ScriptBase;
46using OpenSim.Region.ScriptEngine.Shared.CodeTools;
47
48namespace OpenSim.Region.ScriptEngine.DotNetEngine
49{
50 public class InstanceData
51 {
52 public IScript Script;
53 public string State;
54 public bool Running;
55 public bool Disabled;
56 public string Source;
57 public int StartParam;
58 public AppDomain AppDomain;
59 public Dictionary<string, IScriptApi> Apis;
60 public Dictionary<KeyValuePair<int,int>, KeyValuePair<int,int>>
61 LineMap;
62// public ISponsor ScriptSponsor;
63 }
64
65 public class ScriptManager
66 {
67 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
68
69 #region Declares
70
71 private Thread scriptLoadUnloadThread;
72 private static Thread staticScriptLoadUnloadThread = null;
73 private Queue<LUStruct> LUQueue = new Queue<LUStruct>();
74 private static bool PrivateThread;
75 private int LoadUnloadMaxQueueSize;
76 private Object scriptLock = new Object();
77 private bool m_started = false;
78 private Dictionary<InstanceData, DetectParams[]> detparms =
79 new Dictionary<InstanceData, DetectParams[]>();
80
81 // Load/Unload structure
82 private struct LUStruct
83 {
84 public uint localID;
85 public UUID itemID;
86 public string script;
87 public LUType Action;
88 public int startParam;
89 public bool postOnRez;
90 }
91
92 private enum LUType
93 {
94 Unknown = 0,
95 Load = 1,
96 Unload = 2
97 }
98
99 public Dictionary<uint, Dictionary<UUID, InstanceData>> Scripts =
100 new Dictionary<uint, Dictionary<UUID, InstanceData>>();
101
102 private Compiler LSLCompiler;
103
104 public Scene World
105 {
106 get { return m_scriptEngine.World; }
107 }
108
109 #endregion
110
111 public void Initialize()
112 {
113 // Create our compiler
114 LSLCompiler = new Compiler(m_scriptEngine);
115 }
116
117 public void _StartScript(uint localID, UUID itemID, string Script,
118 int startParam, bool postOnRez)
119 {
120 m_log.DebugFormat(
121 "[{0}]: ScriptManager StartScript: localID: {1}, itemID: {2}",
122 m_scriptEngine.ScriptEngineName, localID, itemID);
123
124 // We will initialize and start the script.
125 // It will be up to the script itself to hook up the correct events.
126 string CompiledScriptFile = String.Empty;
127
128 SceneObjectPart m_host = World.GetSceneObjectPart(localID);
129
130 if (null == m_host)
131 {
132 m_log.ErrorFormat(
133 "[{0}]: Could not find scene object part corresponding "+
134 "to localID {1} to start script",
135 m_scriptEngine.ScriptEngineName, localID);
136
137 return;
138 }
139
140 UUID assetID = UUID.Zero;
141 TaskInventoryItem taskInventoryItem = new TaskInventoryItem();
142 if (m_host.TaskInventory.TryGetValue(itemID, out taskInventoryItem))
143 assetID = taskInventoryItem.AssetID;
144
145 ScenePresence presence =
146 World.GetScenePresence(taskInventoryItem.OwnerID);
147
148 CultureInfo USCulture = new CultureInfo("en-US");
149 Thread.CurrentThread.CurrentCulture = USCulture;
150
151 try
152 {
153 // Compile (We assume LSL)
154 CompiledScriptFile =
155 (string)LSLCompiler.PerformScriptCompile(Script,
156 assetID.ToString(), taskInventoryItem.OwnerID);
157
158 if (presence != null && (!postOnRez))
159 presence.ControllingClient.SendAgentAlertMessage(
160 "Compile successful", false);
161
162 m_log.InfoFormat("[SCRIPT]: Compiled assetID {0}: {1}",
163 assetID, CompiledScriptFile);
164
165 InstanceData id = new InstanceData();
166
167 IScript CompiledScript;
168 CompiledScript =
169 m_scriptEngine.m_AppDomainManager.LoadScript(
170 CompiledScriptFile, out id.AppDomain);
171 //Register the sponsor
172// ISponsor scriptSponsor = new ScriptSponsor();
173// ILease lease = (ILease)RemotingServices.GetLifetimeService(CompiledScript as MarshalByRefObject);
174// lease.Register(scriptSponsor);
175// id.ScriptSponsor = scriptSponsor;
176
177 id.LineMap = LSLCompiler.LineMap();
178 id.Script = CompiledScript;
179 id.Source = Script;
180 id.StartParam = startParam;
181 id.State = "default";
182 id.Running = true;
183 id.Disabled = false;
184
185 // Add it to our script memstruct
186 m_scriptEngine.m_ScriptManager.SetScript(localID, itemID, id);
187
188 id.Apis = new Dictionary<string, IScriptApi>();
189
190 ApiManager am = new ApiManager();
191
192 foreach (string api in am.GetApis())
193 {
194 id.Apis[api] = am.CreateApi(api);
195 id.Apis[api].Initialize(m_scriptEngine, m_host,
196 localID, itemID);
197 }
198
199 foreach (KeyValuePair<string,IScriptApi> kv in id.Apis)
200 {
201 CompiledScript.InitApi(kv.Key, kv.Value);
202 }
203
204 // Fire the first start-event
205 int eventFlags =
206 m_scriptEngine.m_ScriptManager.GetStateEventFlags(
207 localID, itemID);
208
209 m_host.SetScriptEvents(itemID, eventFlags);
210
211 m_scriptEngine.m_EventQueueManager.AddToScriptQueue(
212 localID, itemID, "state_entry", new DetectParams[0],
213 new object[] { });
214
215 if (postOnRez)
216 {
217 m_scriptEngine.m_EventQueueManager.AddToScriptQueue(
218 localID, itemID, "on_rez", new DetectParams[0],
219 new object[] { new LSL_Types.LSLInteger(startParam) });
220 }
221
222 string[] warnings = LSLCompiler.GetWarnings();
223
224 if (warnings != null && warnings.Length != 0)
225 {
226 if (presence != null && (!postOnRez))
227 presence.ControllingClient.SendAgentAlertMessage(
228 "Script saved with warnings, check debug window!",
229 false);
230
231 foreach (string warning in warnings)
232 {
233 try
234 {
235 // DISPLAY WARNING INWORLD
236 string text = "Warning:\n" + warning;
237 if (text.Length > 1100)
238 text = text.Substring(0, 1099);
239
240 World.SimChat(Utils.StringToBytes(text),
241 ChatTypeEnum.DebugChannel, 2147483647,
242 m_host.AbsolutePosition, m_host.Name, m_host.UUID,
243 false);
244 }
245 catch (Exception e2) // LEGIT: User Scripting
246 {
247 m_log.Error("[" +
248 m_scriptEngine.ScriptEngineName +
249 "]: Error displaying warning in-world: " +
250 e2.ToString());
251 m_log.Error("[" +
252 m_scriptEngine.ScriptEngineName + "]: " +
253 "Warning:\r\n" +
254 warning);
255 }
256 }
257 }
258 }
259 catch (Exception e) // LEGIT: User Scripting
260 {
261 if (presence != null && (!postOnRez))
262 presence.ControllingClient.SendAgentAlertMessage(
263 "Script saved with errors, check debug window!",
264 false);
265 try
266 {
267 // DISPLAY ERROR INWORLD
268 string text = "Error compiling script:\n" +
269 e.Message.ToString();
270 if (text.Length > 1100)
271 text = text.Substring(0, 1099);
272
273 World.SimChat(Utils.StringToBytes(text),
274 ChatTypeEnum.DebugChannel, 2147483647,
275 m_host.AbsolutePosition, m_host.Name, m_host.UUID,
276 false);
277 }
278 catch (Exception e2) // LEGIT: User Scripting
279 {
280 m_log.Error("[" +
281 m_scriptEngine.ScriptEngineName +
282 "]: Error displaying error in-world: " +
283 e2.ToString());
284 m_log.Error("[" +
285 m_scriptEngine.ScriptEngineName + "]: " +
286 "Errormessage: Error compiling script:\r\n" +
287 e2.Message.ToString());
288 }
289 }
290 }
291
292 public void _StopScript(uint localID, UUID itemID)
293 {
294 InstanceData id = GetScript(localID, itemID);
295 if (id == null)
296 return;
297
298 m_log.DebugFormat("[{0}]: Unloading script",
299 m_scriptEngine.ScriptEngineName);
300
301 // Stop long command on script
302 AsyncCommandManager.RemoveScript(m_scriptEngine, localID, itemID);
303
304 try
305 {
306 // Get AppDomain
307 // Tell script not to accept new requests
308 id.Running = false;
309 id.Disabled = true;
310 AppDomain ad = id.AppDomain;
311
312 // Remove from internal structure
313 RemoveScript(localID, itemID);
314
315 // Tell AppDomain that we have stopped script
316 m_scriptEngine.m_AppDomainManager.StopScript(ad);
317 }
318 catch (Exception e) // LEGIT: User Scripting
319 {
320 m_log.Error("[" +
321 m_scriptEngine.ScriptEngineName +
322 "]: Exception stopping script localID: " +
323 localID + " LLUID: " + itemID.ToString() +
324 ": " + e.ToString());
325 }
326 }
327
328 public void ReadConfig()
329 {
330 // TODO: Requires sharing of all ScriptManagers to single thread
331 PrivateThread = true;
332 LoadUnloadMaxQueueSize = m_scriptEngine.ScriptConfigSource.GetInt(
333 "LoadUnloadMaxQueueSize", 100);
334 }
335
336 #region Object init/shutdown
337
338 public ScriptEngine m_scriptEngine;
339
340 public ScriptManager(ScriptEngine scriptEngine)
341 {
342 m_scriptEngine = scriptEngine;
343 }
344
345 public void Setup()
346 {
347 ReadConfig();
348 Initialize();
349 }
350
351 public void Start()
352 {
353 m_started = true;
354
355
356 AppDomain.CurrentDomain.AssemblyResolve +=
357 new ResolveEventHandler(CurrentDomain_AssemblyResolve);
358
359 //
360 // CREATE THREAD
361 // Private or shared
362 //
363 if (PrivateThread)
364 {
365 // Assign one thread per region
366 //scriptLoadUnloadThread = StartScriptLoadUnloadThread();
367 }
368 else
369 {
370 // Shared thread - make sure one exist, then assign it to the private
371 if (staticScriptLoadUnloadThread == null)
372 {
373 //staticScriptLoadUnloadThread =
374 // StartScriptLoadUnloadThread();
375 }
376 scriptLoadUnloadThread = staticScriptLoadUnloadThread;
377 }
378 }
379
380 ~ScriptManager()
381 {
382 // Abort load/unload thread
383 try
384 {
385 if (scriptLoadUnloadThread != null &&
386 scriptLoadUnloadThread.IsAlive == true)
387 {
388 scriptLoadUnloadThread.Abort();
389 //scriptLoadUnloadThread.Join();
390 }
391 }
392 catch
393 {
394 }
395 }
396
397 #endregion
398
399 #region Load / Unload scripts (Thread loop)
400
401 public void DoScriptLoadUnload()
402 {
403 if (!m_started)
404 return;
405
406 lock (LUQueue)
407 {
408 if (LUQueue.Count > 0)
409 {
410 LUStruct item = LUQueue.Dequeue();
411
412 if (item.Action == LUType.Unload)
413 {
414 _StopScript(item.localID, item.itemID);
415 RemoveScript(item.localID, item.itemID);
416 }
417 else if (item.Action == LUType.Load)
418 {
419 m_log.DebugFormat("[{0}]: Loading script",
420 m_scriptEngine.ScriptEngineName);
421 _StartScript(item.localID, item.itemID, item.script,
422 item.startParam, item.postOnRez);
423 }
424 }
425 }
426 }
427
428 #endregion
429
430 #region Helper functions
431
432 private static Assembly CurrentDomain_AssemblyResolve(
433 object sender, ResolveEventArgs args)
434 {
435 return Assembly.GetExecutingAssembly().FullName == args.Name ?
436 Assembly.GetExecutingAssembly() : null;
437 }
438
439 #endregion
440
441 #region Start/Stop/Reset script
442
443 /// <summary>
444 /// Fetches, loads and hooks up a script to an objects events
445 /// </summary>
446 /// <param name="itemID"></param>
447 /// <param name="localID"></param>
448 public void StartScript(uint localID, UUID itemID, string Script, int startParam, bool postOnRez)
449 {
450 lock (LUQueue)
451 {
452 if ((LUQueue.Count >= LoadUnloadMaxQueueSize) && m_started)
453 {
454 m_log.Error("[" +
455 m_scriptEngine.ScriptEngineName +
456 "]: ERROR: Load/unload queue item count is at " +
457 LUQueue.Count +
458 ". Config variable \"LoadUnloadMaxQueueSize\" "+
459 "is set to " + LoadUnloadMaxQueueSize +
460 ", so ignoring new script.");
461
462 return;
463 }
464
465 LUStruct ls = new LUStruct();
466 ls.localID = localID;
467 ls.itemID = itemID;
468 ls.script = Script;
469 ls.Action = LUType.Load;
470 ls.startParam = startParam;
471 ls.postOnRez = postOnRez;
472 LUQueue.Enqueue(ls);
473 }
474 }
475
476 /// <summary>
477 /// Disables and unloads a script
478 /// </summary>
479 /// <param name="localID"></param>
480 /// <param name="itemID"></param>
481 public void StopScript(uint localID, UUID itemID)
482 {
483 LUStruct ls = new LUStruct();
484 ls.localID = localID;
485 ls.itemID = itemID;
486 ls.Action = LUType.Unload;
487 ls.startParam = 0;
488 ls.postOnRez = false;
489 lock (LUQueue)
490 {
491 LUQueue.Enqueue(ls);
492 }
493 }
494
495 #endregion
496
497 #region Perform event execution in script
498
499 // Execute a LL-event-function in Script
500 internal void ExecuteEvent(uint localID, UUID itemID,
501 string FunctionName, DetectParams[] qParams, object[] args)
502 {
503 int ExeStage=0; // ;^) Ewe Loon, for debuging
504 InstanceData id=null;
505 try // ;^) Ewe Loon,fix
506 { // ;^) Ewe Loon,fix
507 ExeStage = 1; // ;^) Ewe Loon, for debuging
508 id = GetScript(localID, itemID);
509 if (id == null)
510 return;
511 ExeStage = 2; // ;^) Ewe Loon, for debuging
512 if (qParams.Length>0) // ;^) Ewe Loon,fix
513 detparms[id] = qParams;
514 ExeStage = 3; // ;^) Ewe Loon, for debuging
515 if (id.Running)
516 id.Script.ExecuteEvent(id.State, FunctionName, args);
517 ExeStage = 4; // ;^) Ewe Loon, for debuging
518 if (qParams.Length>0) // ;^) Ewe Loon,fix
519 detparms.Remove(id);
520 ExeStage = 5; // ;^) Ewe Loon, for debuging
521 }
522 catch (Exception e) // ;^) Ewe Loon, From here down tis fix
523 {
524 if ((ExeStage == 3)&&(qParams.Length>0))
525 detparms.Remove(id);
526 SceneObjectPart ob = m_scriptEngine.World.GetSceneObjectPart(localID);
527 m_log.InfoFormat("[Script Error] ,{0},{1},@{2},{3},{4},{5}", ob.Name , FunctionName, ExeStage, e.Message, qParams.Length, detparms.Count);
528 if (ExeStage != 2) throw e;
529 }
530 }
531
532 public uint GetLocalID(UUID itemID)
533 {
534 foreach (KeyValuePair<uint, Dictionary<UUID, InstanceData> > k
535 in Scripts)
536 {
537 if (k.Value.ContainsKey(itemID))
538 return k.Key;
539 }
540 return 0;
541 }
542
543 public int GetStateEventFlags(uint localID, UUID itemID)
544 {
545 try
546 {
547 InstanceData id = GetScript(localID, itemID);
548 if (id == null)
549 {
550 return 0;
551 }
552 int evflags = id.Script.GetStateEventFlags(id.State);
553
554 return (int)evflags;
555 }
556 catch (Exception)
557 {
558 }
559
560 return 0;
561 }
562
563 #endregion
564
565 #region Internal functions to keep track of script
566
567 public List<UUID> GetScriptKeys(uint localID)
568 {
569 if (Scripts.ContainsKey(localID) == false)
570 return new List<UUID>();
571
572 Dictionary<UUID, InstanceData> Obj;
573 Scripts.TryGetValue(localID, out Obj);
574
575 return new List<UUID>(Obj.Keys);
576 }
577
578 public InstanceData GetScript(uint localID, UUID itemID)
579 {
580 lock (scriptLock)
581 {
582 InstanceData id = null;
583
584 if (Scripts.ContainsKey(localID) == false)
585 return null;
586
587 Dictionary<UUID, InstanceData> Obj;
588 Scripts.TryGetValue(localID, out Obj);
589 if (Obj==null) return null;
590 if (Obj.ContainsKey(itemID) == false)
591 return null;
592
593 // Get script
594 Obj.TryGetValue(itemID, out id);
595 return id;
596 }
597 }
598
599 public void SetScript(uint localID, UUID itemID, InstanceData id)
600 {
601 lock (scriptLock)
602 {
603 // Create object if it doesn't exist
604 if (Scripts.ContainsKey(localID) == false)
605 {
606 Scripts.Add(localID, new Dictionary<UUID, InstanceData>());
607 }
608
609 // Delete script if it exists
610 Dictionary<UUID, InstanceData> Obj;
611 Scripts.TryGetValue(localID, out Obj);
612 if (Obj.ContainsKey(itemID) == true)
613 Obj.Remove(itemID);
614
615 // Add to object
616 Obj.Add(itemID, id);
617 }
618 }
619
620 public void RemoveScript(uint localID, UUID itemID)
621 {
622 if (localID == 0)
623 localID = GetLocalID(itemID);
624
625 // Don't have that object?
626 if (Scripts.ContainsKey(localID) == false)
627 return;
628
629 // Delete script if it exists
630 Dictionary<UUID, InstanceData> Obj;
631 Scripts.TryGetValue(localID, out Obj);
632 if (Obj.ContainsKey(itemID) == true)
633 Obj.Remove(itemID);
634 }
635
636 #endregion
637
638 public void ResetScript(uint localID, UUID itemID)
639 {
640 InstanceData id = GetScript(localID, itemID);
641 string script = id.Source;
642 StopScript(localID, itemID);
643 SceneObjectPart part = World.GetSceneObjectPart(localID);
644 part.Inventory.GetInventoryItem(itemID).PermsMask = 0;
645 part.Inventory.GetInventoryItem(itemID).PermsGranter = UUID.Zero;
646 StartScript(localID, itemID, script, id.StartParam, false);
647 }
648
649 #region Script serialization/deserialization
650
651 public void GetSerializedScript(uint localID, UUID itemID)
652 {
653 // Serialize the script and return it
654 // Should not be a problem
655 FileStream fs = File.Create("SERIALIZED_SCRIPT_" + itemID);
656 BinaryFormatter b = new BinaryFormatter();
657 b.Serialize(fs, GetScript(localID, itemID));
658 fs.Close();
659 }
660
661 public void PutSerializedScript(uint localID, UUID itemID)
662 {
663 // Deserialize the script and inject it into an AppDomain
664
665 // How to inject into an AppDomain?
666 }
667
668 #endregion
669
670 public DetectParams[] GetDetectParams(InstanceData id)
671 {
672 if (detparms.ContainsKey(id))
673 return detparms[id];
674
675 return null;
676 }
677
678 public int GetStartParameter(UUID itemID)
679 {
680 uint localID = GetLocalID(itemID);
681 InstanceData id = GetScript(localID, itemID);
682
683 if (id == null)
684 return 0;
685
686 return id.StartParam;
687 }
688
689 public IScriptApi GetApi(UUID itemID, string name)
690 {
691 uint localID = GetLocalID(itemID);
692
693 InstanceData id = GetScript(localID, itemID);
694 if (id == null)
695 return null;
696
697 if (id.Apis.ContainsKey(name))
698 return id.Apis[name];
699
700 return null;
701 }
702 }
703}