aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ScriptEngine/Common
diff options
context:
space:
mode:
authorMelanie Thielker2008-09-26 13:16:11 +0000
committerMelanie Thielker2008-09-26 13:16:11 +0000
commit824283ca3c2ab54868ed61fdb0a329221d69e5fa (patch)
tree9013892fa2afa579bffe8bdcd6a46e2242ed085c /OpenSim/Region/ScriptEngine/Common
parent* Wind updates. Still random.. but in 4 directions instead of two! (diff)
downloadopensim-SC-824283ca3c2ab54868ed61fdb0a329221d69e5fa.zip
opensim-SC-824283ca3c2ab54868ed61fdb0a329221d69e5fa.tar.gz
opensim-SC-824283ca3c2ab54868ed61fdb0a329221d69e5fa.tar.bz2
opensim-SC-824283ca3c2ab54868ed61fdb0a329221d69e5fa.tar.xz
Remove all the subclassing complexity and script server interfaces from
DNE and move all of DNE into the DotNetEngine directory. Remove references that would cause the script runtime to load the entire engine + scene into each script appdomain. This might help DNE memory consumption.
Diffstat (limited to 'OpenSim/Region/ScriptEngine/Common')
-rw-r--r--OpenSim/Region/ScriptEngine/Common/IScript.cs1
-rw-r--r--OpenSim/Region/ScriptEngine/Common/ScriptBaseClass.cs1
-rw-r--r--OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/AppDomainManager.cs253
-rw-r--r--OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/Common.cs56
-rw-r--r--OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/EventManager.cs479
-rw-r--r--OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/EventQueueManager.cs447
-rw-r--r--OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/EventQueueThreadClass.cs381
-rw-r--r--OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/MaintenanceThread.cs243
-rw-r--r--OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/ScriptEngine.cs317
-rw-r--r--OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/ScriptManager.cs510
-rw-r--r--OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/iScriptEngineFunctionModule.cs35
11 files changed, 0 insertions, 2723 deletions
diff --git a/OpenSim/Region/ScriptEngine/Common/IScript.cs b/OpenSim/Region/ScriptEngine/Common/IScript.cs
index 8d91071..d38dc7b 100644
--- a/OpenSim/Region/ScriptEngine/Common/IScript.cs
+++ b/OpenSim/Region/ScriptEngine/Common/IScript.cs
@@ -25,7 +25,6 @@
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */ 26 */
27 27
28using OpenSim.Region.ScriptEngine.Common.ScriptEngineBase;
29using OpenSim.Region.ScriptEngine.Shared; 28using OpenSim.Region.ScriptEngine.Shared;
30using OpenSim.Region.ScriptEngine.Interfaces; 29using OpenSim.Region.ScriptEngine.Interfaces;
31 30
diff --git a/OpenSim/Region/ScriptEngine/Common/ScriptBaseClass.cs b/OpenSim/Region/ScriptEngine/Common/ScriptBaseClass.cs
index 927ab2c..dc3ae05 100644
--- a/OpenSim/Region/ScriptEngine/Common/ScriptBaseClass.cs
+++ b/OpenSim/Region/ScriptEngine/Common/ScriptBaseClass.cs
@@ -29,7 +29,6 @@ using System;
29using System.Runtime.Remoting.Lifetime; 29using System.Runtime.Remoting.Lifetime;
30using System.Threading; 30using System.Threading;
31using OpenSim.Region.Environment.Interfaces; 31using OpenSim.Region.Environment.Interfaces;
32using OpenSim.Region.ScriptEngine.Common.ScriptEngineBase;
33using OpenSim.Region.ScriptEngine.Shared; 32using OpenSim.Region.ScriptEngine.Shared;
34using OpenSim.Region.ScriptEngine.Shared.Api.Interfaces; 33using OpenSim.Region.ScriptEngine.Shared.Api.Interfaces;
35using OpenSim.Region.ScriptEngine.Interfaces; 34using OpenSim.Region.ScriptEngine.Interfaces;
diff --git a/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/AppDomainManager.cs b/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/AppDomainManager.cs
deleted file mode 100644
index 262d75f..0000000
--- a/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/AppDomainManager.cs
+++ /dev/null
@@ -1,253 +0,0 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections;
30using System.Collections.Generic;
31using System.Reflection;
32
33namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
34{
35 public class AppDomainManager : iScriptEngineFunctionModule
36 {
37 //
38 // This class does AppDomain handling and loading/unloading of scripts in it.
39 // It is instanced in "ScriptEngine" and controlled from "ScriptManager"
40 //
41 // 1. Create a new AppDomain if old one is full (or doesn't exist)
42 // 2. Load scripts into AppDomain
43 // 3. Unload scripts from AppDomain (stopping them and marking them as inactive)
44 // 4. Unload AppDomain completely when all scripts in it has stopped
45 //
46
47 private int maxScriptsPerAppDomain = 1;
48
49 /// <summary>
50 /// Internal list of all AppDomains
51 /// </summary>
52 private List<AppDomainStructure> appDomains = new List<AppDomainStructure>();
53
54 /// <summary>
55 /// Structure to keep track of data around AppDomain
56 /// </summary>
57 private class AppDomainStructure
58 {
59 /// <summary>
60 /// The AppDomain itself
61 /// </summary>
62 public AppDomain CurrentAppDomain;
63
64 /// <summary>
65 /// Number of scripts loaded into AppDomain
66 /// </summary>
67 public int ScriptsLoaded;
68
69 /// <summary>
70 /// Number of dead scripts
71 /// </summary>
72 public int ScriptsWaitingUnload;
73 }
74
75 /// <summary>
76 /// Current AppDomain
77 /// </summary>
78 private AppDomainStructure currentAD;
79
80 private object getLock = new object(); // Mutex
81 private object freeLock = new object(); // Mutex
82
83 private ScriptEngine m_scriptEngine;
84 //public AppDomainManager(ScriptEngine scriptEngine)
85 public AppDomainManager(ScriptEngine scriptEngine)
86 {
87 m_scriptEngine = scriptEngine;
88 ReadConfig();
89 }
90
91 public void ReadConfig()
92 {
93 maxScriptsPerAppDomain = m_scriptEngine.ScriptConfigSource.GetInt("ScriptsPerAppDomain", 1);
94 }
95
96 /// <summary>
97 /// Find a free AppDomain, creating one if necessary
98 /// </summary>
99 /// <returns>Free AppDomain</returns>
100 private AppDomainStructure GetFreeAppDomain()
101 {
102 // Console.WriteLine("Finding free AppDomain");
103 lock (getLock)
104 {
105 // Current full?
106 if (currentAD != null && currentAD.ScriptsLoaded >= maxScriptsPerAppDomain)
107 {
108 // Add it to AppDomains list and empty current
109 appDomains.Add(currentAD);
110 currentAD = null;
111 }
112 // No current
113 if (currentAD == null)
114 {
115 // Create a new current AppDomain
116 currentAD = new AppDomainStructure();
117 currentAD.CurrentAppDomain = PrepareNewAppDomain();
118 }
119
120 // Console.WriteLine("Scripts loaded in this Appdomain: " + currentAD.ScriptsLoaded);
121 return currentAD;
122 }
123 }
124
125 private int AppDomainNameCount;
126
127 /// <summary>
128 /// Create and prepare a new AppDomain for scripts
129 /// </summary>
130 /// <returns>The new AppDomain</returns>
131 private AppDomain PrepareNewAppDomain()
132 {
133 // Create and prepare a new AppDomain
134 AppDomainNameCount++;
135 // TODO: Currently security match current appdomain
136
137 // Construct and initialize settings for a second AppDomain.
138 AppDomainSetup ads = new AppDomainSetup();
139 ads.ApplicationBase = AppDomain.CurrentDomain.BaseDirectory;
140 ads.DisallowBindingRedirects = true;
141 ads.DisallowCodeDownload = true;
142 ads.LoaderOptimization = LoaderOptimization.MultiDomainHost;
143 ads.ShadowCopyFiles = "false"; // Disable shadowing
144 ads.ConfigurationFile = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile;
145
146
147 AppDomain AD = AppDomain.CreateDomain("ScriptAppDomain_" + AppDomainNameCount, null, ads);
148 m_scriptEngine.Log.Info("[" + m_scriptEngine.ScriptEngineName + "]: AppDomain Loading: " +
149 AssemblyName.GetAssemblyName("OpenSim.Region.ScriptEngine.Common.dll").ToString());
150 AD.Load(AssemblyName.GetAssemblyName("OpenSim.Region.ScriptEngine.Common.dll"));
151
152 // Return the new AppDomain
153 return AD;
154 }
155
156 /// <summary>
157 /// Unload appdomains that are full and have only dead scripts
158 /// </summary>
159 private void UnloadAppDomains()
160 {
161 lock (freeLock)
162 {
163 // Go through all
164 foreach (AppDomainStructure ads in new ArrayList(appDomains))
165 {
166 // Don't process current AppDomain
167 if (ads.CurrentAppDomain != currentAD.CurrentAppDomain)
168 {
169 // Not current AppDomain
170 // Is number of unloaded bigger or equal to number of loaded?
171 if (ads.ScriptsLoaded <= ads.ScriptsWaitingUnload)
172 {
173 // Remove from internal list
174 appDomains.Remove(ads);
175//#if DEBUG
176 //Console.WriteLine("Found empty AppDomain, unloading");
177 //long m = GC.GetTotalMemory(true); // This force a garbage collect that freezes some windows plateforms
178//#endif
179 // Unload
180 AppDomain.Unload(ads.CurrentAppDomain);
181//#if DEBUG
182 //m_scriptEngine.Log.Info("[" + m_scriptEngine.ScriptEngineName + "]: AppDomain unload freed " + (m - GC.GetTotalMemory(true)) + " bytes of memory");
183//#endif
184 }
185 }
186 }
187 }
188 }
189
190 public IScript LoadScript(string FileName)
191 {
192 // Find next available AppDomain to put it in
193 AppDomainStructure FreeAppDomain = GetFreeAppDomain();
194
195#if DEBUG
196 m_scriptEngine.Log.Info("[" + m_scriptEngine.ScriptEngineName + "]: Loading into AppDomain: " + FileName);
197#endif
198 IScript mbrt =
199 (IScript)
200 FreeAppDomain.CurrentAppDomain.CreateInstanceFromAndUnwrap(FileName, "SecondLife.Script");
201 //Console.WriteLine("ScriptEngine AppDomainManager: is proxy={0}", RemotingServices.IsTransparentProxy(mbrt));
202 FreeAppDomain.ScriptsLoaded++;
203
204 return mbrt;
205 }
206
207
208 /// <summary>
209 /// Increase "dead script" counter for an AppDomain
210 /// </summary>
211 /// <param name="ad"></param>
212 //[Obsolete("Needs fixing, needs a real purpose in life!!!")]
213 public void StopScript(AppDomain ad)
214 {
215 lock (freeLock)
216 {
217#if DEBUG
218 m_scriptEngine.Log.Info("[" + m_scriptEngine.ScriptEngineName + "]: Stopping script in AppDomain");
219#endif
220 // Check if it is current AppDomain
221 if (currentAD.CurrentAppDomain == ad)
222 {
223 // Yes - increase
224 currentAD.ScriptsWaitingUnload++;
225 return;
226 }
227
228 // Lopp through all AppDomains
229 foreach (AppDomainStructure ads in new ArrayList(appDomains))
230 {
231 if (ads.CurrentAppDomain == ad)
232 {
233 // Found it
234 ads.ScriptsWaitingUnload++;
235 break;
236 }
237 }
238 }
239
240 UnloadAppDomains(); // Outsite lock, has its own GetLock
241 }
242
243 /// <summary>
244 /// If set to true then threads and stuff should try to make a graceful exit
245 /// </summary>
246 public bool PleaseShutdown
247 {
248 get { return _PleaseShutdown; }
249 set { _PleaseShutdown = value; }
250 }
251 private bool _PleaseShutdown = false;
252 }
253}
diff --git a/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/Common.cs b/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/Common.cs
deleted file mode 100644
index d5ec9b4..0000000
--- a/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/Common.cs
+++ /dev/null
@@ -1,56 +0,0 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
29{
30 public static class Common
31 {
32 public static bool debug = true;
33 public static ScriptEngine mySE;
34
35 // This class just contains some static log stuff used for debugging.
36
37 //public delegate void SendToDebugEventDelegate(string message);
38 //public delegate void SendToLogEventDelegate(string message);
39 //static public event SendToDebugEventDelegate SendToDebugEvent;
40 //static public event SendToLogEventDelegate SendToLogEvent;
41
42 public static void SendToDebug(string message)
43 {
44 //if (Debug == true)
45 mySE.Log.Info("[" + mySE.ScriptEngineName + "]: Debug: " + message);
46 //SendToDebugEvent("\r\n" + DateTime.Now.ToString("[HH:mm:ss] ") + message);
47 }
48
49 public static void SendToLog(string message)
50 {
51 //if (Debug == true)
52 mySE.Log.Info("[" + mySE.ScriptEngineName + "]: LOG: " + message);
53 //SendToLogEvent("\r\n" + DateTime.Now.ToString("[HH:mm:ss] ") + message);
54 }
55 }
56}
diff --git a/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/EventManager.cs b/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/EventManager.cs
deleted file mode 100644
index 8293fae..0000000
--- a/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/EventManager.cs
+++ /dev/null
@@ -1,479 +0,0 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using OpenMetaverse;
31using OpenSim.Framework;
32using OpenSim.Region.Environment.Modules.Avatar.Currency.SampleMoney;
33using OpenSim.Region.Environment;
34using OpenSim.Region.Interfaces;
35using OpenSim.Region;
36using OpenSim.Region.Environment.Scenes;
37using OpenSim.Region.Environment.Interfaces;
38using OpenSim.Region.ScriptEngine.Shared;
39
40namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
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 : iScriptEngineFunctionModule
47 {
48 //
49 // Class is instanced in "ScriptEngine" and Uses "EventQueueManager" that is also instanced in "ScriptEngine".
50 // This class needs a bit of explaining:
51 //
52 // This class it the link between an event inside OpenSim and the corresponding event in a user script being executed.
53 //
54 // For example when an user touches an object then the "myScriptEngine.World.EventManager.OnObjectGrab" event is fired inside OpenSim.
55 // We hook up to this event and queue a touch_start in EventQueueManager with the proper LSL parameters.
56 // It will then be delivered to the script by EventQueueManager.
57 //
58 // You can check debug C# dump of an LSL script if you need to verify what exact parameters are needed.
59 //
60
61
62 private ScriptEngine myScriptEngine;
63 //public IScriptHost TEMP_OBJECT_ID;
64 public EventManager(ScriptEngine _ScriptEngine, bool performHookUp)
65 {
66 myScriptEngine = _ScriptEngine;
67 ReadConfig();
68
69 if (performHookUp)
70 {
71 myScriptEngine.World.EventManager.OnRezScript += OnRezScript;
72 }
73 }
74
75 public void HookUpEvents()
76 {
77 // Hook up to events from OpenSim
78 // We may not want to do it because someone is controlling us and will deliver events to us
79
80 myScriptEngine.Log.Info("[" + myScriptEngine.ScriptEngineName + "]: Hooking up to server events");
81 myScriptEngine.World.EventManager.OnObjectGrab += touch_start;
82 myScriptEngine.World.EventManager.OnObjectDeGrab += touch_end;
83 myScriptEngine.World.EventManager.OnRemoveScript += OnRemoveScript;
84 myScriptEngine.World.EventManager.OnScriptChangedEvent += changed;
85 myScriptEngine.World.EventManager.OnScriptAtTargetEvent += at_target;
86 myScriptEngine.World.EventManager.OnScriptNotAtTargetEvent += not_at_target;
87 myScriptEngine.World.EventManager.OnScriptControlEvent += control;
88 myScriptEngine.World.EventManager.OnScriptColliderStart += collision_start;
89 myScriptEngine.World.EventManager.OnScriptColliding += collision;
90 myScriptEngine.World.EventManager.OnScriptCollidingEnd += collision_end;
91
92 // TODO: HOOK ALL EVENTS UP TO SERVER!
93 IMoneyModule money=myScriptEngine.World.RequestModuleInterface<IMoneyModule>();
94 if (money != null)
95 {
96 money.OnObjectPaid+=HandleObjectPaid;
97 }
98
99 }
100
101 public void ReadConfig()
102 {
103 }
104
105 private void HandleObjectPaid(UUID objectID, UUID agentID, int amount)
106 {
107 SceneObjectPart part=myScriptEngine.World.GetSceneObjectPart(objectID);
108 if (part != null)
109 {
110 money(part.LocalId, agentID, amount);
111 }
112 }
113
114 public void changed(uint localID, uint change)
115 {
116 // Add to queue for all scripts in localID, Object pass change.
117 myScriptEngine.PostObjectEvent(localID, new EventParams(
118 "changed",new object[] { new LSL_Types.LSLInteger(change) },
119 new DetectParams[0]));
120 }
121
122 public void state_entry(uint localID)
123 {
124 // Add to queue for all scripts in ObjectID object
125 myScriptEngine.PostObjectEvent(localID, new EventParams(
126 "state_entry",new object[] { },
127 new DetectParams[0]));
128 }
129
130 public void touch_start(uint localID, uint originalID, Vector3 offsetPos,
131 IClientAPI remoteClient)
132 {
133 // Add to queue for all scripts in ObjectID object
134 DetectParams[] det = new DetectParams[1];
135 det[0] = new DetectParams();
136 det[0].Key = remoteClient.AgentId;
137 det[0].Populate(myScriptEngine.World);
138
139 if (originalID == 0)
140 {
141 SceneObjectPart part = myScriptEngine.World.GetSceneObjectPart(localID);
142 if (part == null)
143 return;
144
145 det[0].LinkNum = part.LinkNum;
146 }
147 else
148 {
149 SceneObjectPart originalPart = myScriptEngine.World.GetSceneObjectPart(originalID);
150 det[0].LinkNum = originalPart.LinkNum;
151 }
152
153 myScriptEngine.PostObjectEvent(localID, new EventParams(
154 "touch_start", new Object[] { new LSL_Types.LSLInteger(1) },
155 det));
156 }
157
158 public void touch(uint localID, uint originalID, Vector3 offsetPos,
159 IClientAPI remoteClient)
160 {
161 // Add to queue for all scripts in ObjectID object
162 DetectParams[] det = new DetectParams[1];
163 det[0] = new DetectParams();
164 det[0].Key = remoteClient.AgentId;
165 det[0].Populate(myScriptEngine.World);
166 det[0].OffsetPos = new LSL_Types.Vector3(offsetPos.X,
167 offsetPos.Y,
168 offsetPos.Z);
169
170 if (originalID == 0)
171 {
172 SceneObjectPart part = myScriptEngine.World.GetSceneObjectPart(localID);
173 if (part == null)
174 return;
175
176 det[0].LinkNum = part.LinkNum;
177 }
178 else
179 {
180 SceneObjectPart originalPart = myScriptEngine.World.GetSceneObjectPart(originalID);
181 det[0].LinkNum = originalPart.LinkNum;
182 }
183
184 myScriptEngine.PostObjectEvent(localID, new EventParams(
185 "touch", new Object[] { new LSL_Types.LSLInteger(1) },
186 det));
187 }
188
189 public void touch_end(uint localID, uint originalID, IClientAPI remoteClient)
190 {
191 // Add to queue for all scripts in ObjectID object
192 DetectParams[] det = new DetectParams[1];
193 det[0] = new DetectParams();
194 det[0].Key = remoteClient.AgentId;
195 det[0].Populate(myScriptEngine.World);
196
197 if (originalID == 0)
198 {
199 SceneObjectPart part = myScriptEngine.World.GetSceneObjectPart(localID);
200 if (part == null)
201 return;
202
203 det[0].LinkNum = part.LinkNum;
204 }
205 else
206 {
207 SceneObjectPart originalPart = myScriptEngine.World.GetSceneObjectPart(originalID);
208 det[0].LinkNum = originalPart.LinkNum;
209 }
210
211 myScriptEngine.PostObjectEvent(localID, new EventParams(
212 "touch_end", new Object[] { new LSL_Types.LSLInteger(1) },
213 det));
214 }
215
216 public void OnRezScript(uint localID, UUID itemID, string script, int startParam, bool postOnRez, string engine)
217 {
218 List<IScriptModule> engines = new List<IScriptModule>(myScriptEngine.World.RequestModuleInterfaces<IScriptModule>());
219
220 List<string> names = new List<string>();
221 foreach (IScriptModule m in engines)
222 names.Add(m.ScriptEngineName);
223
224 int lineEnd = script.IndexOf('\n');
225
226 if (lineEnd != 1)
227 {
228 string firstline = script.Substring(0, lineEnd).Trim();
229
230 int colon = firstline.IndexOf(':');
231 if (firstline.Length > 2 && firstline.Substring(0, 2) == "//" && colon != -1)
232 {
233 string engineName = firstline.Substring(2, colon-2);
234
235 if (names.Contains(engineName))
236 {
237 engine = engineName;
238 script = "//" + script.Substring(script.IndexOf(':')+1);
239 }
240 }
241 }
242
243 if (engine != myScriptEngine.ScriptEngineName)
244 return;
245
246 myScriptEngine.Log.Debug("OnRezScript localID: " + localID + " LLUID: " + itemID.ToString() + " Size: " +
247 script.Length);
248 myScriptEngine.m_ScriptManager.StartScript(localID, itemID, script, startParam, postOnRez);
249 }
250
251 public void OnRemoveScript(uint localID, UUID itemID)
252 {
253 myScriptEngine.Log.Debug("OnRemoveScript localID: " + localID + " LLUID: " + itemID.ToString());
254 myScriptEngine.m_ScriptManager.StopScript(
255 localID,
256 itemID
257 );
258 }
259
260 public void money(uint localID, UUID agentID, int amount)
261 {
262 myScriptEngine.PostObjectEvent(localID, new EventParams(
263 "money", new object[] {
264 new LSL_Types.LSLString(agentID.ToString()),
265 new LSL_Types.LSLInteger(amount) },
266 new DetectParams[0]));
267 }
268
269 // TODO: Replace placeholders below
270 // NOTE! THE PARAMETERS FOR THESE FUNCTIONS ARE NOT CORRECT!
271 // These needs to be hooked up to OpenSim during init of this class
272 // then queued in EventQueueManager.
273 // When queued in EventQueueManager they need to be LSL compatible (name and params)
274
275 public void state_exit(uint localID)
276 {
277 myScriptEngine.PostObjectEvent(localID, new EventParams(
278 "state_exit", new object[] { },
279 new DetectParams[0]));
280 }
281
282 public void collision_start(uint localID, ColliderArgs col)
283 {
284 // Add to queue for all scripts in ObjectID object
285 List<DetectParams> det = new List<DetectParams>();
286
287 foreach (DetectedObject detobj in col.Colliders)
288 {
289 DetectParams d = new DetectParams();
290 d.Key =detobj.keyUUID;
291 d.Populate(myScriptEngine.World);
292 det.Add(d);
293 }
294
295 if (det.Count > 0)
296 myScriptEngine.PostObjectEvent(localID, new EventParams(
297 "collision_start",
298 new Object[] { new LSL_Types.LSLInteger(det.Count) },
299 det.ToArray()));
300 }
301
302 public void collision(uint localID, ColliderArgs col)
303 {
304 // Add to queue for all scripts in ObjectID object
305 List<DetectParams> det = new List<DetectParams>();
306
307 foreach (DetectedObject detobj in col.Colliders)
308 {
309 DetectParams d = new DetectParams();
310 d.Key =detobj.keyUUID;
311 d.Populate(myScriptEngine.World);
312 det.Add(d);
313 }
314
315 if (det.Count > 0)
316 myScriptEngine.PostObjectEvent(localID, new EventParams(
317 "collision", new Object[] { new LSL_Types.LSLInteger(det.Count) },
318 det.ToArray()));
319 }
320
321 public void collision_end(uint localID, ColliderArgs col)
322 {
323 // Add to queue for all scripts in ObjectID object
324 List<DetectParams> det = new List<DetectParams>();
325
326 foreach (DetectedObject detobj in col.Colliders)
327 {
328 DetectParams d = new DetectParams();
329 d.Key =detobj.keyUUID;
330 d.Populate(myScriptEngine.World);
331 det.Add(d);
332 }
333
334 if (det.Count > 0)
335 myScriptEngine.PostObjectEvent(localID, new EventParams(
336 "collision_end",
337 new Object[] { new LSL_Types.LSLInteger(det.Count) },
338 det.ToArray()));
339 }
340
341 public void land_collision_start(uint localID, UUID itemID)
342 {
343 myScriptEngine.PostObjectEvent(localID, new EventParams(
344 "land_collision_start",
345 new object[0],
346 new DetectParams[0]));
347 }
348
349 public void land_collision(uint localID, UUID itemID)
350 {
351 myScriptEngine.PostObjectEvent(localID, new EventParams(
352 "land_collision",
353 new object[0],
354 new DetectParams[0]));
355 }
356
357 public void land_collision_end(uint localID, UUID itemID)
358 {
359 myScriptEngine.PostObjectEvent(localID, new EventParams(
360 "land_collision_end",
361 new object[0],
362 new DetectParams[0]));
363 }
364
365 // Handled by long commands
366 public void timer(uint localID, UUID itemID)
367 {
368 }
369
370 public void listen(uint localID, UUID itemID)
371 {
372 }
373
374 public void control(uint localID, UUID itemID, UUID agentID, uint held, uint change)
375 {
376 if ((change == 0) && (myScriptEngine.m_EventQueueManager.CheckEeventQueueForEvent(localID,"control"))) return;
377 myScriptEngine.PostObjectEvent(localID, new EventParams(
378 "control",new object[] {
379 new LSL_Types.LSLString(agentID.ToString()),
380 new LSL_Types.LSLInteger(held),
381 new LSL_Types.LSLInteger(change)},
382 new DetectParams[0]));
383 }
384
385 public void email(uint localID, UUID itemID, string timeSent,
386 string address, string subject, string message, int numLeft)
387 {
388 myScriptEngine.PostObjectEvent(localID, new EventParams(
389 "email",new object[] {
390 new LSL_Types.LSLString(timeSent),
391 new LSL_Types.LSLString(address),
392 new LSL_Types.LSLString(subject),
393 new LSL_Types.LSLString(message),
394 new LSL_Types.LSLInteger(numLeft)},
395 new DetectParams[0]));
396 }
397
398 public void at_target(uint localID, uint handle, Vector3 targetpos,
399 Vector3 atpos)
400 {
401 myScriptEngine.PostObjectEvent(localID, new EventParams(
402 "at_target", new object[] {
403 new LSL_Types.LSLInteger(handle),
404 new LSL_Types.Vector3(targetpos.X,targetpos.Y,targetpos.Z),
405 new LSL_Types.Vector3(atpos.X,atpos.Y,atpos.Z) },
406 new DetectParams[0]));
407 }
408
409 public void not_at_target(uint localID)
410 {
411 myScriptEngine.PostObjectEvent(localID, new EventParams(
412 "not_at_target",new object[0],
413 new DetectParams[0]));
414 }
415
416 public void at_rot_target(uint localID, UUID itemID)
417 {
418 myScriptEngine.PostObjectEvent(localID, new EventParams(
419 "at_rot_target",new object[0],
420 new DetectParams[0]));
421 }
422
423 public void not_at_rot_target(uint localID, UUID itemID)
424 {
425 myScriptEngine.PostObjectEvent(localID, new EventParams(
426 "not_at_rot_target",new object[0],
427 new DetectParams[0]));
428 }
429
430 public void attach(uint localID, UUID itemID)
431 {
432 }
433
434 public void dataserver(uint localID, UUID itemID)
435 {
436 }
437
438 public void link_message(uint localID, UUID itemID)
439 {
440 }
441
442 public void moving_start(uint localID, UUID itemID)
443 {
444 myScriptEngine.PostObjectEvent(localID, new EventParams(
445 "moving_start",new object[0],
446 new DetectParams[0]));
447 }
448
449 public void moving_end(uint localID, UUID itemID)
450 {
451 myScriptEngine.PostObjectEvent(localID, new EventParams(
452 "moving_end",new object[0],
453 new DetectParams[0]));
454 }
455
456 public void object_rez(uint localID, UUID itemID)
457 {
458 }
459
460 public void remote_data(uint localID, UUID itemID)
461 {
462 }
463
464 // Handled by long commands
465 public void http_response(uint localID, UUID itemID)
466 {
467 }
468
469 /// <summary>
470 /// If set to true then threads and stuff should try to make a graceful exit
471 /// </summary>
472 public bool PleaseShutdown
473 {
474 get { return _PleaseShutdown; }
475 set { _PleaseShutdown = value; }
476 }
477 private bool _PleaseShutdown = false;
478 }
479}
diff --git a/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/EventQueueManager.cs b/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/EventQueueManager.cs
deleted file mode 100644
index b13ab21..0000000
--- a/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/EventQueueManager.cs
+++ /dev/null
@@ -1,447 +0,0 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections;
30using System.Collections.Generic;
31using OpenMetaverse;
32using OpenSim.Region.ScriptEngine.Shared;
33
34namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
35{
36 /// <summary>
37 /// EventQueueManager handles event queues
38 /// Events are queued and executed in separate thread
39 /// </summary>
40 [Serializable]
41 public class EventQueueManager : iScriptEngineFunctionModule
42 {
43 //
44 // Class is instanced in "ScriptEngine" and used by "EventManager" which is also instanced in "ScriptEngine".
45 //
46 // Class purpose is to queue and execute functions that are received by "EventManager":
47 // - allowing "EventManager" to release its event thread immediately, thus not interrupting server execution.
48 // - allowing us to prioritize and control execution of script functions.
49 // Class can use multiple threads for simultaneous execution. Mutexes are used for thread safety.
50 //
51 // 1. Hold an execution queue for scripts
52 // 2. Use threads to process queue, each thread executes one script function on each pass.
53 // 3. Catch any script error and process it
54 //
55 //
56 // Notes:
57 // * Current execution load balancing is optimized for 1 thread, and can cause unfair execute balancing between scripts.
58 // Not noticeable unless server is under high load.
59 //
60
61 public ScriptEngine m_ScriptEngine;
62
63 /// <summary>
64 /// List of threads (classes) processing event queue
65 /// Note that this may or may not be a reference to a static object depending on PrivateRegionThreads config setting.
66 /// </summary>
67 internal static List<EventQueueThreadClass> eventQueueThreads = new List<EventQueueThreadClass>(); // Thread pool that we work on
68 /// <summary>
69 /// Locking access to eventQueueThreads AND staticGlobalEventQueueThreads.
70 /// </summary>
71// private object eventQueueThreadsLock = new object();
72 // Static objects for referencing the objects above if we don't have private threads:
73 //internal static List<EventQueueThreadClass> staticEventQueueThreads; // A static reference used if we don't use private threads
74// internal static object staticEventQueueThreadsLock; // Statick lock object reference for same reason
75
76 /// <summary>
77 /// Global static list of all threads (classes) processing event queue -- used by max enforcment thread
78 /// </summary>
79 //private List<EventQueueThreadClass> staticGlobalEventQueueThreads = new List<EventQueueThreadClass>();
80
81 /// <summary>
82 /// Used internally to specify how many threads should exit gracefully
83 /// </summary>
84 public static int ThreadsToExit;
85 public static object ThreadsToExitLock = new object();
86
87
88 //public object queueLock = new object(); // Mutex lock object
89
90 /// <summary>
91 /// How many threads to process queue with
92 /// </summary>
93 internal static int numberOfThreads;
94
95 internal static int EventExecutionMaxQueueSize;
96
97 /// <summary>
98 /// Maximum time one function can use for execution before we perform a thread kill.
99 /// </summary>
100 private static int maxFunctionExecutionTimems
101 {
102 get { return (int)(maxFunctionExecutionTimens / 10000); }
103 set { maxFunctionExecutionTimens = value * 10000; }
104 }
105
106 /// <summary>
107 /// Contains nanoseconds version of maxFunctionExecutionTimems so that it matches time calculations better (performance reasons).
108 /// WARNING! ONLY UPDATE maxFunctionExecutionTimems, NEVER THIS DIRECTLY.
109 /// </summary>
110 public static long maxFunctionExecutionTimens;
111 /// <summary>
112 /// Enforce max execution time
113 /// </summary>
114 public static bool EnforceMaxExecutionTime;
115 /// <summary>
116 /// Kill script (unload) when it exceeds execution time
117 /// </summary>
118 private static bool KillScriptOnMaxFunctionExecutionTime;
119
120 /// <summary>
121 /// List of localID locks for mutex processing of script events
122 /// </summary>
123 private List<uint> objectLocks = new List<uint>();
124 private object tryLockLock = new object(); // Mutex lock object
125
126 /// <summary>
127 /// Queue containing events waiting to be executed
128 /// </summary>
129 public Queue<QueueItemStruct> eventQueue = new Queue<QueueItemStruct>();
130
131 #region " Queue structures "
132 /// <summary>
133 /// Queue item structure
134 /// </summary>
135 public struct QueueItemStruct
136 {
137 public uint localID;
138 public UUID itemID;
139 public string functionName;
140 public DetectParams[] llDetectParams;
141 public object[] param;
142 }
143
144 #endregion
145
146 #region " Initialization / Startup "
147 public EventQueueManager(ScriptEngine _ScriptEngine)
148 {
149 m_ScriptEngine = _ScriptEngine;
150
151 ReadConfig();
152 AdjustNumberOfScriptThreads();
153 }
154
155 public void ReadConfig()
156 {
157 // Refresh config
158 numberOfThreads = m_ScriptEngine.ScriptConfigSource.GetInt("NumberOfScriptThreads", 2);
159 maxFunctionExecutionTimems = m_ScriptEngine.ScriptConfigSource.GetInt("MaxEventExecutionTimeMs", 5000);
160 EnforceMaxExecutionTime = m_ScriptEngine.ScriptConfigSource.GetBoolean("EnforceMaxEventExecutionTime", false);
161 KillScriptOnMaxFunctionExecutionTime = m_ScriptEngine.ScriptConfigSource.GetBoolean("DeactivateScriptOnTimeout", false);
162 EventExecutionMaxQueueSize = m_ScriptEngine.ScriptConfigSource.GetInt("EventExecutionMaxQueueSize", 300);
163
164 // Now refresh config in all threads
165 lock (eventQueueThreads)
166 {
167 foreach (EventQueueThreadClass EventQueueThread in eventQueueThreads)
168 {
169 EventQueueThread.ReadConfig();
170 }
171 }
172 }
173
174 #endregion
175
176 #region " Shutdown all threads "
177 ~EventQueueManager()
178 {
179 Stop();
180 }
181
182 private void Stop()
183 {
184 if (eventQueueThreads != null)
185 {
186 // Kill worker threads
187 lock (eventQueueThreads)
188 {
189 foreach (EventQueueThreadClass EventQueueThread in new ArrayList(eventQueueThreads))
190 {
191 AbortThreadClass(EventQueueThread);
192 }
193 //eventQueueThreads.Clear();
194 //staticGlobalEventQueueThreads.Clear();
195 }
196 }
197
198 // Remove all entries from our event queue
199 lock (eventQueue)
200 {
201 eventQueue.Clear();
202 }
203 }
204
205 #endregion
206
207 #region " Start / stop script execution threads (ThreadClasses) "
208 private void StartNewThreadClass()
209 {
210 EventQueueThreadClass eqtc = new EventQueueThreadClass();
211 eventQueueThreads.Add(eqtc);
212 //m_ScriptEngine.Log.Debug("[" + m_ScriptEngine.ScriptEngineName + "]: Started new script execution thread. Current thread count: " + eventQueueThreads.Count);
213 }
214
215 private void AbortThreadClass(EventQueueThreadClass threadClass)
216 {
217 if (eventQueueThreads.Contains(threadClass))
218 eventQueueThreads.Remove(threadClass);
219
220 try
221 {
222 threadClass.Stop();
223 }
224 catch (Exception)
225 {
226 //m_ScriptEngine.Log.Error("[" + m_ScriptEngine.ScriptEngineName + ":EventQueueManager]: If you see this, could you please report it to Tedd:");
227 //m_ScriptEngine.Log.Error("[" + m_ScriptEngine.ScriptEngineName + ":EventQueueManager]: Script thread execution timeout kill ended in exception: " + ex.ToString());
228 }
229 //m_ScriptEngine.Log.Debug("[" + m_ScriptEngine.ScriptEngineName + "]: Killed script execution thread. Remaining thread count: " + eventQueueThreads.Count);
230 }
231 #endregion
232
233 #region " Mutex locks for queue access "
234 /// <summary>
235 /// Try to get a mutex lock on localID
236 /// </summary>
237 /// <param name="localID"></param>
238 /// <returns></returns>
239 public bool TryLock(uint localID)
240 {
241 lock (tryLockLock)
242 {
243 if (objectLocks.Contains(localID) == true)
244 {
245 return false;
246 }
247 else
248 {
249 objectLocks.Add(localID);
250 return true;
251 }
252 }
253 }
254
255 /// <summary>
256 /// Release mutex lock on localID
257 /// </summary>
258 /// <param name="localID"></param>
259 public void ReleaseLock(uint localID)
260 {
261 lock (tryLockLock)
262 {
263 if (objectLocks.Contains(localID) == true)
264 {
265 objectLocks.Remove(localID);
266 }
267 }
268 }
269 #endregion
270
271 #region " Check execution queue for a specified Event"
272 /// <summary>
273 /// checks to see if a specified event type is already in the queue
274 /// </summary>
275 /// <param name="localID">Region object ID</param>
276 /// <param name="FunctionName">Name of the function, will be state + "_event_" + FunctionName</param>
277 /// <returns>true if event is found , false if not found</returns>
278 ///
279 public bool CheckEeventQueueForEvent(uint localID, string FunctionName)
280 {
281 if (eventQueue.Count > 0)
282 {
283 lock (eventQueue)
284 {
285 foreach (EventQueueManager.QueueItemStruct QIS in eventQueue)
286 {
287 if ((QIS.functionName == FunctionName) && (QIS.localID == localID))
288 return true;
289 }
290 }
291 }
292 return false;
293 }
294 #endregion
295
296 #region " Add events to execution queue "
297 /// <summary>
298 /// Add event to event execution queue
299 /// </summary>
300 /// <param name="localID">Region object ID</param>
301 /// <param name="FunctionName">Name of the function, will be state + "_event_" + FunctionName</param>
302 /// <param name="param">Array of parameters to match event mask</param>
303 public bool AddToObjectQueue(uint localID, string FunctionName, DetectParams[] qParams, params object[] param)
304 {
305 // Determine all scripts in Object and add to their queue
306 //myScriptEngine.log.Info("[" + ScriptEngineName + "]: EventQueueManager Adding localID: " + localID + ", FunctionName: " + FunctionName);
307
308 // Do we have any scripts in this object at all? If not, return
309 if (m_ScriptEngine.m_ScriptManager.Scripts.ContainsKey(localID) == false)
310 {
311 //Console.WriteLine("Event \String.Empty + FunctionName + "\" for localID: " + localID + ". No scripts found on this localID.");
312 return false;
313 }
314
315 List<UUID> scriptKeys =
316 m_ScriptEngine.m_ScriptManager.GetScriptKeys(localID);
317
318 foreach (UUID itemID in scriptKeys)
319 {
320 // Add to each script in that object
321 // TODO: Some scripts may not subscribe to this event. Should we NOT add it? Does it matter?
322 AddToScriptQueue(localID, itemID, FunctionName, qParams, param);
323 }
324 return true;
325 }
326
327 /// <summary>
328 /// Add event to event execution queue
329 /// </summary>
330 /// <param name="localID">Region object ID</param>
331 /// <param name="itemID">Region script ID</param>
332 /// <param name="FunctionName">Name of the function, will be state + "_event_" + FunctionName</param>
333 /// <param name="param">Array of parameters to match event mask</param>
334 public bool AddToScriptQueue(uint localID, UUID itemID, string FunctionName, DetectParams[] qParams, params object[] param)
335 {
336 List<UUID> keylist = m_ScriptEngine.m_ScriptManager.GetScriptKeys(localID);
337
338 if (!keylist.Contains(itemID)) // We don't manage that script
339 {
340 return false;
341 }
342
343 lock (eventQueue)
344 {
345 if (eventQueue.Count >= EventExecutionMaxQueueSize)
346 {
347 m_ScriptEngine.Log.Error("[" + m_ScriptEngine.ScriptEngineName + "]: ERROR: Event execution queue item count is at " + eventQueue.Count + ". Config variable \"EventExecutionMaxQueueSize\" is set to " + EventExecutionMaxQueueSize + ", so ignoring new event.");
348 m_ScriptEngine.Log.Error("[" + m_ScriptEngine.ScriptEngineName + "]: Event ignored: localID: " + localID + ", itemID: " + itemID + ", FunctionName: " + FunctionName);
349 return false;
350 }
351
352 // Create a structure and add data
353 QueueItemStruct QIS = new QueueItemStruct();
354 QIS.localID = localID;
355 QIS.itemID = itemID;
356 QIS.functionName = FunctionName;
357 QIS.llDetectParams = qParams;
358 QIS.param = param;
359
360 // Add it to queue
361 eventQueue.Enqueue(QIS);
362 }
363 return true;
364 }
365 #endregion
366
367 #region " Maintenance thread "
368
369 /// <summary>
370 /// 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.
371 /// Called from MaintenanceThread
372 /// </summary>
373 public void AdjustNumberOfScriptThreads()
374 {
375 // Is there anything here for us to do?
376 if (eventQueueThreads.Count == numberOfThreads)
377 return;
378
379 lock (eventQueueThreads)
380 {
381 int diff = numberOfThreads - eventQueueThreads.Count;
382 // Positive number: Start
383 // Negative number: too many are running
384 if (diff > 0)
385 {
386 // We need to add more threads
387 for (int ThreadCount = eventQueueThreads.Count; ThreadCount < numberOfThreads; ThreadCount++)
388 {
389 StartNewThreadClass();
390 }
391 }
392 if (diff < 0)
393 {
394 // We need to kill some threads
395 lock (ThreadsToExitLock)
396 {
397 ThreadsToExit = Math.Abs(diff);
398 }
399 }
400 }
401 }
402
403 /// <summary>
404 /// Check if any thread class has been executing an event too long
405 /// </summary>
406 public void CheckScriptMaxExecTime()
407 {
408 // Iterate through all ScriptThreadClasses and check how long their current function has been executing
409 lock (eventQueueThreads)
410 {
411 foreach (EventQueueThreadClass EventQueueThread in eventQueueThreads)
412 {
413 // Is thread currently executing anything?
414 if (EventQueueThread.InExecution)
415 {
416 // Has execution time expired?
417 if (DateTime.Now.Ticks - EventQueueThread.LastExecutionStarted >
418 maxFunctionExecutionTimens)
419 {
420 // Yes! We need to kill this thread!
421
422 // Set flag if script should be removed or not
423 EventQueueThread.KillCurrentScript = KillScriptOnMaxFunctionExecutionTime;
424
425 // Abort this thread
426 AbortThreadClass(EventQueueThread);
427
428 // We do not need to start another, MaintenenceThread will do that for us
429 //StartNewThreadClass();
430 }
431 }
432 }
433 }
434 }
435 #endregion
436
437 ///// <summary>
438 ///// If set to true then threads and stuff should try to make a graceful exit
439 ///// </summary>
440 //public bool PleaseShutdown
441 //{
442 // get { return _PleaseShutdown; }
443 // set { _PleaseShutdown = value; }
444 //}
445 //private bool _PleaseShutdown = false;
446 }
447}
diff --git a/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/EventQueueThreadClass.cs b/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/EventQueueThreadClass.cs
deleted file mode 100644
index 7f52793..0000000
--- a/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/EventQueueThreadClass.cs
+++ /dev/null
@@ -1,381 +0,0 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections;
30using System.Reflection;
31using System.Text.RegularExpressions;
32using System.Threading;
33using System.Globalization;
34using OpenMetaverse;
35using log4net;
36using OpenSim.Framework;
37using OpenSim.Region.Environment.Scenes.Scripting;
38
39namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
40{
41 /// <summary>
42 /// Because every thread needs some data set for it (time started to execute current function), it will do its work within a class
43 /// </summary>
44 public class EventQueueThreadClass : iScriptEngineFunctionModule
45 {
46 // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
47
48 /// <summary>
49 /// How many ms to sleep if queue is empty
50 /// </summary>
51 private static int nothingToDoSleepms;// = 50;
52 private static ThreadPriority MyThreadPriority;
53
54 public long LastExecutionStarted;
55 public bool InExecution = false;
56 public bool KillCurrentScript = false;
57
58 //private EventQueueManager eventQueueManager;
59 public Thread EventQueueThread;
60 private static int ThreadCount = 0;
61
62 private string ScriptEngineName = "ScriptEngine.Common";
63
64 public EventQueueThreadClass()//EventQueueManager eqm
65 {
66 //eventQueueManager = eqm;
67 ReadConfig();
68 Start();
69 }
70
71 ~EventQueueThreadClass()
72 {
73 Stop();
74 }
75
76 public void ReadConfig()
77 {
78 lock (ScriptEngine.ScriptEngines)
79 {
80 foreach (ScriptEngine m_ScriptEngine in ScriptEngine.ScriptEngines)
81 {
82 ScriptEngineName = m_ScriptEngine.ScriptEngineName;
83 nothingToDoSleepms = m_ScriptEngine.ScriptConfigSource.GetInt("SleepTimeIfNoScriptExecutionMs", 50);
84
85 // Later with ScriptServer we might want to ask OS for stuff too, so doing this a bit manually
86 string pri = m_ScriptEngine.ScriptConfigSource.GetString("ScriptThreadPriority", "BelowNormal");
87 switch (pri.ToLower())
88 {
89 case "lowest":
90 MyThreadPriority = ThreadPriority.Lowest;
91 break;
92 case "belownormal":
93 MyThreadPriority = ThreadPriority.BelowNormal;
94 break;
95 case "normal":
96 MyThreadPriority = ThreadPriority.Normal;
97 break;
98 case "abovenormal":
99 MyThreadPriority = ThreadPriority.AboveNormal;
100 break;
101 case "highest":
102 MyThreadPriority = ThreadPriority.Highest;
103 break;
104 default:
105 MyThreadPriority = ThreadPriority.BelowNormal; // Default
106 m_ScriptEngine.Log.Error("[ScriptEngineBase]: Unknown priority type \"" + pri +
107 "\" in config file. Defaulting to \"BelowNormal\".");
108 break;
109 }
110 }
111 }
112 // Now set that priority
113 if (EventQueueThread != null)
114 if (EventQueueThread.IsAlive)
115 EventQueueThread.Priority = MyThreadPriority;
116 }
117
118 /// <summary>
119 /// Start thread
120 /// </summary>
121 private void Start()
122 {
123 EventQueueThread = new Thread(EventQueueThreadLoop);
124 EventQueueThread.IsBackground = true;
125
126 EventQueueThread.Priority = MyThreadPriority;
127 EventQueueThread.Name = "EventQueueManagerThread_" + ThreadCount;
128 EventQueueThread.Start();
129 ThreadTracker.Add(EventQueueThread);
130
131 // Look at this... Don't you wish everyone did that solid coding everywhere? :P
132 if (ThreadCount == int.MaxValue)
133 ThreadCount = 0;
134 ThreadCount++;
135 }
136
137 public void Stop()
138 {
139 //PleaseShutdown = true; // Set shutdown flag
140 //Thread.Sleep(100); // Wait a bit
141 if (EventQueueThread != null && EventQueueThread.IsAlive == true)
142 {
143 try
144 {
145 EventQueueThread.Abort(); // Send abort
146 //EventQueueThread.Join(); // Wait for it
147 }
148 catch (Exception)
149 {
150 //myScriptEngine.Log.Info("[" + ScriptEngineName + "]: EventQueueManager Exception killing worker thread: " + e.ToString());
151 }
152 }
153 }
154
155 private EventQueueManager.QueueItemStruct BlankQIS = new EventQueueManager.QueueItemStruct();
156 private ScriptEngine lastScriptEngine;
157 /// <summary>
158 /// Queue processing thread loop
159 /// </summary>
160 private void EventQueueThreadLoop()
161 {
162 CultureInfo USCulture = new CultureInfo("en-US");
163 Thread.CurrentThread.CurrentCulture = USCulture;
164
165 //myScriptEngine.Log.Info("[" + ScriptEngineName + "]: EventQueueManager Worker thread spawned");
166 try
167 {
168 while (true)
169 {
170 try
171 {
172 while (true)
173 {
174 DoProcessQueue();
175 }
176 }
177 catch (ThreadAbortException)
178 {
179 if (lastScriptEngine != null)
180 lastScriptEngine.Log.Info("[" + ScriptEngineName + "]: ThreadAbortException while executing function.");
181 }
182 catch (Exception e)
183 {
184 if (lastScriptEngine != null)
185 lastScriptEngine.Log.Error("[" + ScriptEngineName + "]: Exception in EventQueueThreadLoop: " + e.ToString());
186 }
187 }
188 }
189 catch (ThreadAbortException)
190 {
191 //myScriptEngine.Log.Info("[" + ScriptEngineName + "]: EventQueueManager Worker thread killed: " + tae.Message);
192 }
193 }
194
195 public void DoProcessQueue()
196 {
197 //lock (ScriptEngine.ScriptEngines)
198 //{
199 foreach (ScriptEngine m_ScriptEngine in new ArrayList(ScriptEngine.ScriptEngines))
200 {
201 lastScriptEngine = m_ScriptEngine;
202 // Every now and then check if we should shut down
203 //if (PleaseShutdown || EventQueueManager.ThreadsToExit > 0)
204 //{
205 // // Someone should shut down, lets get exclusive lock
206 // lock (EventQueueManager.ThreadsToExitLock)
207 // {
208 // // Lets re-check in case someone grabbed it
209 // if (EventQueueManager.ThreadsToExit > 0)
210 // {
211 // // Its crowded here so we'll shut down
212 // EventQueueManager.ThreadsToExit--;
213 // Stop();
214 // return;
215 // }
216 // else
217 // {
218 // // We have been asked to shut down
219 // Stop();
220 // return;
221 // }
222 // }
223 //}
224
225 //try
226 // {
227 EventQueueManager.QueueItemStruct QIS = BlankQIS;
228 bool GotItem = false;
229
230 //if (PleaseShutdown)
231 // return;
232
233 if (m_ScriptEngine.m_EventQueueManager == null || m_ScriptEngine.m_EventQueueManager.eventQueue == null)
234 continue;
235
236 if (m_ScriptEngine.m_EventQueueManager.eventQueue.Count == 0)
237 {
238 // Nothing to do? Sleep a bit waiting for something to do
239 Thread.Sleep(nothingToDoSleepms);
240 }
241 else
242 {
243 // Something in queue, process
244 //myScriptEngine.Log.Info("[" + ScriptEngineName + "]: Processing event for localID: " + QIS.localID + ", itemID: " + QIS.itemID + ", FunctionName: " + QIS.FunctionName);
245
246 // OBJECT BASED LOCK - TWO THREADS WORKING ON SAME OBJECT IS NOT GOOD
247 lock (m_ScriptEngine.m_EventQueueManager.eventQueue)
248 {
249 GotItem = false;
250 for (int qc = 0; qc < m_ScriptEngine.m_EventQueueManager.eventQueue.Count; qc++)
251 {
252 // Get queue item
253 QIS = m_ScriptEngine.m_EventQueueManager.eventQueue.Dequeue();
254
255 // Check if object is being processed by someone else
256 if (m_ScriptEngine.m_EventQueueManager.TryLock(QIS.localID) == false)
257 {
258 // Object is already being processed, requeue it
259 m_ScriptEngine.m_EventQueueManager.eventQueue.Enqueue(QIS);
260 }
261 else
262 {
263 // We have lock on an object and can process it
264 GotItem = true;
265 break;
266 }
267 }
268 }
269
270 if (GotItem == true)
271 {
272 // Execute function
273 try
274 {
275 ///cfk 2-7-08 dont need this right now and the default Linux build has DEBUG defined
276#if DEBUG
277 //eventQueueManager.m_ScriptEngine.Log.Debug("[" + ScriptEngineName + "]: " +
278 // "Executing event:\r\n"
279 // + "QIS.localID: " + QIS.localID
280 // + ", QIS.itemID: " + QIS.itemID
281 // + ", QIS.functionName: " +
282 // QIS.functionName);
283#endif
284 // Only pipe event if land supports it.
285 if (m_ScriptEngine.World.PipeEventsForScript(QIS.localID))
286 {
287 LastExecutionStarted = DateTime.Now.Ticks;
288 KillCurrentScript = false;
289 InExecution = true;
290 m_ScriptEngine.m_ScriptManager.ExecuteEvent(QIS.localID,
291 QIS.itemID,
292 QIS.functionName,
293 QIS.llDetectParams,
294 QIS.param);
295 InExecution = false;
296 }
297 }
298 catch (Exception e)
299 {
300 InExecution = false;
301 // DISPLAY ERROR INWORLD
302 string text = "Error executing script function \"" + QIS.functionName +
303 "\":\r\n";
304 if (e.InnerException != null)
305 {
306 // Send inner exception
307 string line = " (unknown line)";
308 Regex rx = new Regex(@"SecondLife\.Script\..+[\s:](?<line>\d+)\.?\r?$", RegexOptions.Compiled);
309 if (rx.Match(e.InnerException.ToString()).Success)
310 line = " (line " + rx.Match(e.InnerException.ToString()).Result("${line}") + ")";
311 text += e.InnerException.Message.ToString() + line;
312 }
313 else
314 {
315 text += "\r\n";
316 // Send normal
317 text += e.Message.ToString();
318 }
319 if (KillCurrentScript)
320 text += "\r\nScript will be deactivated!";
321
322 try
323 {
324 if (text.Length > 1500)
325 text = text.Substring(0, 1500);
326 IScriptHost m_host =
327 m_ScriptEngine.World.GetSceneObjectPart(QIS.localID);
328 //if (m_host != null)
329 //{
330 m_ScriptEngine.World.SimChat(Utils.StringToBytes(text),
331 ChatTypeEnum.DebugChannel, 2147483647,
332 m_host.AbsolutePosition,
333 m_host.Name, m_host.UUID, false);
334 }
335 catch (Exception)
336 {
337 //}
338 //else
339 //{
340 // T oconsole
341 m_ScriptEngine.m_EventQueueManager.m_ScriptEngine.Log.Error("[" + ScriptEngineName +
342 "]: " +
343 "Unable to send text in-world:\r\n" +
344 text);
345 }
346 finally
347 {
348 // So we are done sending message in-world
349 if (KillCurrentScript)
350 {
351 m_ScriptEngine.m_EventQueueManager.m_ScriptEngine.m_ScriptManager.StopScript(
352 QIS.localID, QIS.itemID);
353 }
354 }
355
356 // Pass it on so it's displayed on the console
357 // and in the logs (mikem 2008.06.02).
358 throw e.InnerException;
359 }
360 finally
361 {
362 InExecution = false;
363 m_ScriptEngine.m_EventQueueManager.ReleaseLock(QIS.localID);
364 }
365 }
366 }
367 }
368 // }
369 }
370
371 ///// <summary>
372 ///// If set to true then threads and stuff should try to make a graceful exit
373 ///// </summary>
374 //public bool PleaseShutdown
375 //{
376 // get { return _PleaseShutdown; }
377 // set { _PleaseShutdown = value; }
378 //}
379 //private bool _PleaseShutdown = false;
380 }
381}
diff --git a/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/MaintenanceThread.cs b/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/MaintenanceThread.cs
deleted file mode 100644
index ef87b2f..0000000
--- a/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/MaintenanceThread.cs
+++ /dev/null
@@ -1,243 +0,0 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections;
30using System.Reflection;
31using System.Threading;
32using log4net;
33using OpenSim.Framework;
34
35namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
36{
37 /// <summary>
38 /// This class does maintenance on script engine.
39 /// </summary>
40 public class MaintenanceThread : iScriptEngineFunctionModule
41 {
42
43 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
44
45 //public ScriptEngine m_ScriptEngine;
46 private int MaintenanceLoopms;
47 private int MaintenanceLoopTicks_ScriptLoadUnload;
48 private int MaintenanceLoopTicks_Other;
49
50
51 public MaintenanceThread()
52 {
53 //m_ScriptEngine = _ScriptEngine;
54
55 ReadConfig();
56
57 // Start maintenance thread
58 StartMaintenanceThread();
59 }
60
61 ~MaintenanceThread()
62 {
63 StopMaintenanceThread();
64 }
65
66 public void ReadConfig()
67 {
68 // Bad hack, but we need a m_ScriptEngine :)
69 lock (ScriptEngine.ScriptEngines)
70 {
71 foreach (ScriptEngine m_ScriptEngine in ScriptEngine.ScriptEngines)
72 {
73 MaintenanceLoopms = m_ScriptEngine.ScriptConfigSource.GetInt("MaintenanceLoopms", 50);
74 MaintenanceLoopTicks_ScriptLoadUnload =
75 m_ScriptEngine.ScriptConfigSource.GetInt("MaintenanceLoopTicks_ScriptLoadUnload", 1);
76 MaintenanceLoopTicks_Other =
77 m_ScriptEngine.ScriptConfigSource.GetInt("MaintenanceLoopTicks_Other", 10);
78
79 return;
80 }
81 }
82 }
83
84 #region " Maintenance thread "
85 /// <summary>
86 /// Maintenance thread. Enforcing max execution time for example.
87 /// </summary>
88 public Thread MaintenanceThreadThread;
89
90 /// <summary>
91 /// Starts maintenance thread
92 /// </summary>
93 private void StartMaintenanceThread()
94 {
95 if (MaintenanceThreadThread == null)
96 {
97 MaintenanceThreadThread = new Thread(MaintenanceLoop);
98 MaintenanceThreadThread.Name = "ScriptMaintenanceThread";
99 MaintenanceThreadThread.IsBackground = true;
100 MaintenanceThreadThread.Start();
101 ThreadTracker.Add(MaintenanceThreadThread);
102 }
103 }
104
105 /// <summary>
106 /// Stops maintenance thread
107 /// </summary>
108 private void StopMaintenanceThread()
109 {
110#if DEBUG
111 //m_ScriptEngine.Log.Debug("[" + m_ScriptEngine.ScriptEngineName + "]: StopMaintenanceThread() called");
112#endif
113 //PleaseShutdown = true;
114 Thread.Sleep(100);
115 try
116 {
117 if (MaintenanceThreadThread != null && MaintenanceThreadThread.IsAlive)
118 {
119 MaintenanceThreadThread.Abort();
120 }
121 }
122 catch (Exception)
123 {
124 //m_ScriptEngine.Log.Error("[" + m_ScriptEngine.ScriptEngineName + "]: Exception stopping maintenence thread: " + ex.ToString());
125 }
126 }
127
128 // private ScriptEngine lastScriptEngine; // Keep track of what ScriptEngine instance we are at so we can give exception
129 /// <summary>
130 /// A thread should run in this loop and check all running scripts
131 /// </summary>
132 public void MaintenanceLoop()
133 {
134 //if (m_ScriptEngine.m_EventQueueManager.maxFunctionExecutionTimens < MaintenanceLoopms)
135 // m_ScriptEngine.Log.Warn("[" + m_ScriptEngine.ScriptEngineName + "]: " +
136 // "Configuration error: MaxEventExecutionTimeMs is less than MaintenanceLoopms. The Maintenance Loop will only check scripts once per run.");
137
138 long Last_maxFunctionExecutionTimens = 0; // DateTime.Now.Ticks;
139 long Last_ReReadConfigFilens = DateTime.Now.Ticks;
140 int MaintenanceLoopTicks_ScriptLoadUnload_Count = 0;
141 int MaintenanceLoopTicks_Other_Count = 0;
142 bool MaintenanceLoopTicks_ScriptLoadUnload_ResetCount = false;
143 bool MaintenanceLoopTicks_Other_ResetCount = false;
144
145 while (true)
146 {
147 try
148 {
149 while (true)
150 {
151 Thread.Sleep(MaintenanceLoopms); // Sleep before next pass
152
153 // Reset counters?
154 if (MaintenanceLoopTicks_ScriptLoadUnload_ResetCount)
155 {
156 MaintenanceLoopTicks_ScriptLoadUnload_ResetCount = false;
157 MaintenanceLoopTicks_ScriptLoadUnload_Count = 0;
158 }
159 if (MaintenanceLoopTicks_Other_ResetCount)
160 {
161 MaintenanceLoopTicks_Other_ResetCount = false;
162 MaintenanceLoopTicks_Other_Count = 0;
163 }
164
165 // Increase our counters
166 MaintenanceLoopTicks_ScriptLoadUnload_Count++;
167 MaintenanceLoopTicks_Other_Count++;
168
169
170 //lock (ScriptEngine.ScriptEngines)
171 //{
172 foreach (ScriptEngine m_ScriptEngine in new ArrayList(ScriptEngine.ScriptEngines))
173 {
174 // lastScriptEngine = m_ScriptEngine;
175 // Re-reading config every x seconds
176 if (MaintenanceLoopTicks_Other_Count >= MaintenanceLoopTicks_Other)
177 {
178 MaintenanceLoopTicks_Other_ResetCount = true;
179 if (m_ScriptEngine.RefreshConfigFilens > 0)
180 {
181 // Check if its time to re-read config
182 if (DateTime.Now.Ticks - Last_ReReadConfigFilens >
183 m_ScriptEngine.RefreshConfigFilens)
184 {
185 //Console.WriteLine("Time passed: " + (DateTime.Now.Ticks - Last_ReReadConfigFilens) + ">" + m_ScriptEngine.RefreshConfigFilens);
186 // Its time to re-read config file
187 m_ScriptEngine.ReadConfig();
188 Last_ReReadConfigFilens = DateTime.Now.Ticks; // Reset time
189 }
190
191
192 // Adjust number of running script threads if not correct
193 if (m_ScriptEngine.m_EventQueueManager != null)
194 m_ScriptEngine.m_EventQueueManager.AdjustNumberOfScriptThreads();
195
196 // Check if any script has exceeded its max execution time
197 if (EventQueueManager.EnforceMaxExecutionTime)
198 {
199 // We are enforcing execution time
200 if (DateTime.Now.Ticks - Last_maxFunctionExecutionTimens >
201 EventQueueManager.maxFunctionExecutionTimens)
202 {
203 // Its time to check again
204 m_ScriptEngine.m_EventQueueManager.CheckScriptMaxExecTime(); // Do check
205 Last_maxFunctionExecutionTimens = DateTime.Now.Ticks; // Reset time
206 }
207 }
208 }
209 }
210 if (MaintenanceLoopTicks_ScriptLoadUnload_Count >= MaintenanceLoopTicks_ScriptLoadUnload)
211 {
212 MaintenanceLoopTicks_ScriptLoadUnload_ResetCount = true;
213 // LOAD / UNLOAD SCRIPTS
214 if (m_ScriptEngine.m_ScriptManager != null)
215 m_ScriptEngine.m_ScriptManager.DoScriptLoadUnload();
216 }
217 }
218 //}
219 }
220 }
221 catch(ThreadAbortException)
222 {
223 m_log.Error("Thread aborted in MaintenanceLoopThread. If this is during shutdown, please ignore");
224 }
225 catch (Exception ex)
226 {
227 m_log.ErrorFormat("Exception in MaintenanceLoopThread. Thread will recover after 5 sec throttle. Exception: {0}", ex.ToString());
228 }
229 }
230 }
231 #endregion
232
233 ///// <summary>
234 ///// If set to true then threads and stuff should try to make a graceful exit
235 ///// </summary>
236 //public bool PleaseShutdown
237 //{
238 // get { return _PleaseShutdown; }
239 // set { _PleaseShutdown = value; }
240 //}
241 //private bool _PleaseShutdown = false;
242 }
243}
diff --git a/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/ScriptEngine.cs b/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/ScriptEngine.cs
deleted file mode 100644
index f259ec1..0000000
--- a/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/ScriptEngine.cs
+++ /dev/null
@@ -1,317 +0,0 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Reflection;
31using log4net;
32using Nini.Config;
33using OpenSim.Region.Interfaces;
34using OpenSim.Region.Environment.Interfaces;
35using OpenSim.Region.Environment.Scenes;
36using OpenSim.Region.ScriptEngine.Interfaces;
37using OpenMetaverse;
38using OpenSim.Region.ScriptEngine.Shared;
39
40namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
41{
42 /// <summary>
43 /// This is the root object for ScriptEngine. Objects access each other trough this class.
44 /// </summary>
45 ///
46 [Serializable]
47 public abstract class ScriptEngine : IRegionModule, IScriptModule, iScriptEngineFunctionModule, IEventReceiver
48 {
49 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
50
51 public static List<ScriptEngine> ScriptEngines = new List<ScriptEngine>();
52 private Scene m_Scene;
53 public Scene World
54 {
55 get { return m_Scene; }
56 }
57 public EventManager m_EventManager; // Handles and queues incoming events from OpenSim
58 public EventQueueManager m_EventQueueManager; // Executes events, handles script threads
59 public ScriptManager m_ScriptManager; // Load, unload and execute scripts
60 public AppDomainManager m_AppDomainManager; // Handles loading/unloading of scripts into AppDomains
61 public static MaintenanceThread m_MaintenanceThread; // Thread that does different kinds of maintenance, for example refreshing config and killing scripts that has been running too long
62
63 public IConfigSource ConfigSource;
64 public IConfig ScriptConfigSource;
65 public abstract string ScriptEngineName { get; }
66 private bool m_enabled = false;
67 private bool m_hookUpToServer = false;
68
69 public IConfig Config
70 {
71 get { return ScriptConfigSource; }
72 }
73
74 /// <summary>
75 /// How many seconds between re-reading config-file. 0 = never. ScriptEngine will try to adjust to new config changes.
76 /// </summary>
77 public int RefreshConfigFileSeconds {
78 get { return (int)(RefreshConfigFilens / 10000000); }
79 set { RefreshConfigFilens = value * 10000000; }
80 }
81 public long RefreshConfigFilens;
82
83 public ScriptManager GetScriptManager()
84 {
85 return _GetScriptManager();
86 }
87
88 public abstract ScriptManager _GetScriptManager();
89
90 public ILog Log
91 {
92 get { return m_log; }
93 }
94
95 public ScriptEngine()
96 {
97 Common.mySE = this; // For logging, just need any instance, doesn't matter
98 lock (ScriptEngines)
99 {
100 ScriptEngines.Add(this); // Keep a list of ScriptEngines for shared threads to process all instances
101 }
102 }
103
104 public void InitializeEngine(Scene Sceneworld, IConfigSource config, bool HookUpToServer, ScriptManager newScriptManager)
105 {
106 m_Scene = Sceneworld;
107 ConfigSource = config;
108 m_hookUpToServer = HookUpToServer;
109
110 m_log.Info("[" + ScriptEngineName + "]: ScriptEngine initializing");
111
112 // Make sure we have config
113 if (ConfigSource.Configs[ScriptEngineName] == null)
114 ConfigSource.AddConfig(ScriptEngineName);
115 ScriptConfigSource = ConfigSource.Configs[ScriptEngineName];
116
117 m_enabled = ScriptConfigSource.GetBoolean("Enabled", true);
118 if (!m_enabled)
119 return;
120
121 //m_log.Info("[" + ScriptEngineName + "]: InitializeEngine");
122
123 // Create all objects we'll be using
124 m_EventQueueManager = new EventQueueManager(this);
125 m_EventManager = new EventManager(this, HookUpToServer);
126 // We need to start it
127 m_ScriptManager = newScriptManager;
128 m_ScriptManager.Setup();
129 m_AppDomainManager = new AppDomainManager(this);
130 if (m_MaintenanceThread == null)
131 m_MaintenanceThread = new MaintenanceThread();
132
133 m_log.Info("[" + ScriptEngineName + "]: Reading configuration from config section \"" + ScriptEngineName + "\"");
134 ReadConfig();
135
136 m_Scene.StackModuleInterface<IScriptModule>(this);
137 }
138
139 public void PostInitialise()
140 {
141 if (!m_enabled)
142 return;
143
144 if (m_hookUpToServer)
145 m_EventManager.HookUpEvents();
146
147 m_ScriptManager.Start();
148 }
149
150 public void Shutdown()
151 {
152 // We are shutting down
153 lock (ScriptEngines)
154 {
155 ScriptEngines.Remove(this);
156 }
157 }
158
159 public void ReadConfig()
160 {
161#if DEBUG
162 //m_log.Debug("[" + ScriptEngineName + "]: Refreshing configuration for all modules");
163#endif
164 RefreshConfigFileSeconds = ScriptConfigSource.GetInt("RefreshConfig", 30);
165
166
167 // Create a new object (probably not necessary?)
168// ScriptConfigSource = ConfigSource.Configs[ScriptEngineName];
169
170 if (m_EventQueueManager != null) m_EventQueueManager.ReadConfig();
171 if (m_EventManager != null) m_EventManager.ReadConfig();
172 if (m_ScriptManager != null) m_ScriptManager.ReadConfig();
173 if (m_AppDomainManager != null) m_AppDomainManager.ReadConfig();
174 if (m_MaintenanceThread != null) m_MaintenanceThread.ReadConfig();
175 }
176
177 #region IRegionModule
178
179 public abstract void Initialise(Scene scene, IConfigSource config);
180
181 public void Close()
182 {
183 }
184
185 public string Name
186 {
187 get { return "Common." + ScriptEngineName; }
188 }
189
190 public bool IsSharedModule
191 {
192 get { return false; }
193 }
194
195 public bool PostObjectEvent(uint localID, EventParams p)
196 {
197 return m_EventQueueManager.AddToObjectQueue(localID, p.EventName, p.DetectParams, p.Params);
198 }
199
200 public bool PostScriptEvent(UUID itemID, EventParams p)
201 {
202 uint localID = m_ScriptManager.GetLocalID(itemID);
203 return m_EventQueueManager.AddToScriptQueue(localID, itemID, p.EventName, p.DetectParams, p.Params);
204 }
205
206 public DetectParams GetDetectParams(UUID itemID, int number)
207 {
208 uint localID = m_ScriptManager.GetLocalID(itemID);
209 if (localID == 0)
210 return null;
211
212 IScript Script = m_ScriptManager.GetScript(localID, itemID);
213
214 if (Script == null)
215 return null;
216
217 DetectParams[] det = m_ScriptManager.GetDetectParams(Script);
218
219 if (number < 0 || number >= det.Length)
220 return null;
221
222 return det[number];
223 }
224
225 public int GetStartParameter(UUID itemID)
226 {
227 return 0;
228 }
229 #endregion
230
231 public void SetState(UUID itemID, string state)
232 {
233 uint localID = m_ScriptManager.GetLocalID(itemID);
234 if (localID == 0)
235 return;
236
237 IScript Script = m_ScriptManager.GetScript(localID, itemID);
238
239 if (Script == null)
240 return;
241
242 string currentState = Script.State;
243
244 if (currentState != state)
245 {
246 try
247 {
248 m_EventManager.state_exit(localID);
249
250 }
251 catch (AppDomainUnloadedException)
252 {
253 Console.WriteLine("[SCRIPT]: state change called when script was unloaded. Nothing to worry about, but noting the occurance");
254 }
255
256 Script.State = state;
257
258 try
259 {
260 int eventFlags = m_ScriptManager.GetStateEventFlags(localID, itemID);
261 SceneObjectPart part = m_Scene.GetSceneObjectPart(itemID);
262 if (part != null)
263 part.SetScriptEvents(itemID, eventFlags);
264 m_EventManager.state_entry(localID);
265 }
266 catch (AppDomainUnloadedException)
267 {
268 Console.WriteLine("[SCRIPT]: state change called when script was unloaded. Nothing to worry about, but noting the occurance");
269 }
270 }
271 }
272
273 public bool GetScriptState(UUID itemID)
274 {
275 uint localID = m_ScriptManager.GetLocalID(itemID);
276 if (localID == 0)
277 return false;
278
279 IScript script = m_ScriptManager.GetScript(localID, itemID);
280 if (script == null)
281 return false;
282
283 return script.Exec.Running?true:false;
284 }
285
286 public void SetScriptState(UUID itemID, bool state)
287 {
288 uint localID = m_ScriptManager.GetLocalID(itemID);
289 if (localID == 0)
290 return;
291
292 IScript script = m_ScriptManager.GetScript(localID, itemID);
293 if (script == null)
294 return;
295
296 script.Exec.Running = state;
297 }
298
299 public void ApiResetScript(UUID itemID)
300 {
301 uint localID = m_ScriptManager.GetLocalID(itemID);
302 if (localID == 0)
303 return;
304
305 m_ScriptManager.ResetScript(localID, itemID);
306 }
307
308 public void ResetScript(UUID itemID)
309 {
310 uint localID = m_ScriptManager.GetLocalID(itemID);
311 if (localID == 0)
312 return;
313
314 m_ScriptManager.ResetScript(localID, itemID);
315 }
316 }
317}
diff --git a/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/ScriptManager.cs b/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/ScriptManager.cs
deleted file mode 100644
index 987a0a0..0000000
--- a/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/ScriptManager.cs
+++ /dev/null
@@ -1,510 +0,0 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.IO;
31using System.Reflection;
32using System.Runtime.Serialization.Formatters.Binary;
33using System.Threading;
34using OpenMetaverse;
35using OpenSim.Region.Environment.Scenes;
36using OpenSim.Region.ScriptEngine.Shared;
37
38namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
39{
40 /// <summary>
41 /// Loads scripts
42 /// Compiles them if necessary
43 /// Execute functions for EventQueueManager (Sends them to script on other AppDomain for execution)
44 /// </summary>
45 ///
46
47 // This class is as close as you get to the script without being inside script class. It handles all the dirty work for other classes.
48 // * Keeps track of running scripts
49 // * Compiles script if necessary (through "Compiler")
50 // * Loads script (through "AppDomainManager" called from for example "EventQueueManager")
51 // * Executes functions inside script (called from for example "EventQueueManager" class)
52 // * Unloads script (through "AppDomainManager" called from for example "EventQueueManager")
53 // * Dedicated load/unload thread, and queues loading/unloading.
54 // This so that scripts starting or stopping will not slow down other theads or whole system.
55 //
56 [Serializable]
57 public abstract class ScriptManager : iScriptEngineFunctionModule
58 {
59 #region Declares
60
61 private Thread scriptLoadUnloadThread;
62 private static Thread staticScriptLoadUnloadThread;
63 // private int scriptLoadUnloadThread_IdleSleepms;
64 private Queue<LUStruct> LUQueue = new Queue<LUStruct>();
65 private static bool PrivateThread;
66 private int LoadUnloadMaxQueueSize;
67 private Object scriptLock = new Object();
68 private bool m_started = false;
69 private Dictionary<IScript, DetectParams[]> detparms = new Dictionary<IScript, DetectParams[]>();
70
71 // Load/Unload structure
72 private struct LUStruct
73 {
74 public uint localID;
75 public UUID itemID;
76 public string script;
77 public LUType Action;
78 public int startParam;
79 public bool postOnRez;
80 }
81
82 private enum LUType
83 {
84 Unknown = 0,
85 Load = 1,
86 Unload = 2
87 }
88
89 // Xantor 20080525: Keep a list of compiled scripts this session for reuse
90 public Dictionary<UUID, String> scriptList = new Dictionary<UUID, string>();
91
92 // Object<string, Script<string, script>>
93 // IMPORTANT: Types and MemberInfo-derived objects require a LOT of memory.
94 // Instead use RuntimeTypeHandle, RuntimeFieldHandle and RunTimeHandle (IntPtr) instead!
95 public Dictionary<uint, Dictionary<UUID, IScript>> Scripts =
96 new Dictionary<uint, Dictionary<UUID, IScript>>();
97
98
99 public Scene World
100 {
101 get { return m_scriptEngine.World; }
102 }
103
104 #endregion
105
106 public void ReadConfig()
107 {
108 // scriptLoadUnloadThread_IdleSleepms = m_scriptEngine.ScriptConfigSource.GetInt("ScriptLoadUnloadLoopms", 30);
109 // TODO: Requires sharing of all ScriptManagers to single thread
110 PrivateThread = true; // m_scriptEngine.ScriptConfigSource.GetBoolean("PrivateScriptLoadUnloadThread", false);
111 LoadUnloadMaxQueueSize = m_scriptEngine.ScriptConfigSource.GetInt("LoadUnloadMaxQueueSize", 100);
112 }
113
114 #region Object init/shutdown
115
116 public ScriptEngine m_scriptEngine;
117
118 public ScriptManager(ScriptEngine scriptEngine)
119 {
120 m_scriptEngine = scriptEngine;
121 }
122 public abstract void Initialize();
123 public void Setup()
124 {
125 ReadConfig();
126 Initialize();
127 }
128 public void Start()
129 {
130 m_started = true;
131
132
133 AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
134
135 //
136 // CREATE THREAD
137 // Private or shared
138 //
139 if (PrivateThread)
140 {
141 // Assign one thread per region
142 //scriptLoadUnloadThread = StartScriptLoadUnloadThread();
143 }
144 else
145 {
146 // Shared thread - make sure one exist, then assign it to the private
147 if (staticScriptLoadUnloadThread == null)
148 {
149 //staticScriptLoadUnloadThread = StartScriptLoadUnloadThread();
150 }
151 scriptLoadUnloadThread = staticScriptLoadUnloadThread;
152 }
153 }
154
155// TODO: unused
156// private static int privateThreadCount = 0;
157// private Thread StartScriptLoadUnloadThread()
158// {
159// Thread t = new Thread(ScriptLoadUnloadThreadLoop);
160// string name = "ScriptLoadUnloadThread:";
161// if (PrivateThread)
162// {
163// name += "Private:" + privateThreadCount;
164// privateThreadCount++;
165// }
166// else
167// {
168// name += "Shared";
169// }
170// t.Name = name;
171// t.IsBackground = true;
172// t.Priority = ThreadPriority.Normal;
173// t.Start();
174// OpenSim.Framework.ThreadTracker.Add(t);
175// return t;
176// }
177
178 ~ScriptManager()
179 {
180 // Abort load/unload thread
181 try
182 {
183 //PleaseShutdown = true;
184 //Thread.Sleep(100);
185 if (scriptLoadUnloadThread != null && scriptLoadUnloadThread.IsAlive == true)
186 {
187 scriptLoadUnloadThread.Abort();
188 //scriptLoadUnloadThread.Join();
189 }
190 }
191 catch
192 {
193 }
194 }
195
196 #endregion
197
198 #region Load / Unload scripts (Thread loop)
199
200// TODO: unused
201// private void ScriptLoadUnloadThreadLoop()
202// {
203// try
204// {
205// while (true)
206// {
207// if (LUQueue.Count == 0)
208// Thread.Sleep(scriptLoadUnloadThread_IdleSleepms);
209// //if (PleaseShutdown)
210// // return;
211// DoScriptLoadUnload();
212// }
213// }
214// catch (ThreadAbortException tae)
215// {
216// string a = tae.ToString();
217// a = String.Empty;
218// // Expected
219// }
220// }
221
222 public void DoScriptLoadUnload()
223 {
224 if (!m_started)
225 return;
226
227 lock (LUQueue)
228 {
229 if (LUQueue.Count > 0)
230 {
231m_scriptEngine.Log.InfoFormat("[{0}]: Loading script", m_scriptEngine.ScriptEngineName);
232 LUStruct item = LUQueue.Dequeue();
233
234 if (item.Action == LUType.Unload)
235 {
236 _StopScript(item.localID, item.itemID);
237 RemoveScript(item.localID, item.itemID);
238 }
239 else if (item.Action == LUType.Load)
240 {
241 _StartScript(item.localID, item.itemID, item.script, item.startParam, item.postOnRez);
242 }
243 }
244 }
245 }
246
247 #endregion
248
249 #region Helper functions
250
251 private static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
252 {
253 //Console.WriteLine("ScriptManager.CurrentDomain_AssemblyResolve: " + args.Name);
254 return Assembly.GetExecutingAssembly().FullName == args.Name ? Assembly.GetExecutingAssembly() : null;
255 }
256
257 #endregion
258
259
260
261 #region Start/Stop/Reset script
262
263 // private readonly Object startStopLock = new Object();
264
265 /// <summary>
266 /// Fetches, loads and hooks up a script to an objects events
267 /// </summary>
268 /// <param name="itemID"></param>
269 /// <param name="localID"></param>
270 public void StartScript(uint localID, UUID itemID, string Script, int startParam, bool postOnRez)
271 {
272 lock (LUQueue)
273 {
274 if ((LUQueue.Count >= LoadUnloadMaxQueueSize) && m_started)
275 {
276 m_scriptEngine.Log.Error("[" + m_scriptEngine.ScriptEngineName + "]: ERROR: Load/unload queue item count is at " + LUQueue.Count + ". Config variable \"LoadUnloadMaxQueueSize\" is set to " + LoadUnloadMaxQueueSize + ", so ignoring new script.");
277 return;
278 }
279
280 LUStruct ls = new LUStruct();
281 ls.localID = localID;
282 ls.itemID = itemID;
283 ls.script = Script;
284 ls.Action = LUType.Load;
285 ls.startParam = startParam;
286 ls.postOnRez = postOnRez;
287 LUQueue.Enqueue(ls);
288m_scriptEngine.Log.InfoFormat("[{0}]: Queued script for load", m_scriptEngine.ScriptEngineName);
289 }
290 }
291
292 /// <summary>
293 /// Disables and unloads a script
294 /// </summary>
295 /// <param name="localID"></param>
296 /// <param name="itemID"></param>
297 public void StopScript(uint localID, UUID itemID)
298 {
299 LUStruct ls = new LUStruct();
300 ls.localID = localID;
301 ls.itemID = itemID;
302 ls.Action = LUType.Unload;
303 ls.startParam = 0;
304 ls.postOnRez = false;
305 lock (LUQueue)
306 {
307 LUQueue.Enqueue(ls);
308 }
309 }
310
311 // Create a new instance of the compiler (reuse)
312 //private Compiler.LSL.Compiler LSLCompiler = new Compiler.LSL.Compiler();
313
314 public abstract void _StartScript(uint localID, UUID itemID, string Script, int startParam, bool postOnRez);
315 public abstract void _StopScript(uint localID, UUID itemID);
316
317
318 #endregion
319
320 #region Perform event execution in script
321
322 /// <summary>
323 /// Execute a LL-event-function in Script
324 /// </summary>
325 /// <param name="localID">Object the script is located in</param>
326 /// <param name="itemID">Script ID</param>
327 /// <param name="FunctionName">Name of function</param>
328 /// <param name="args">Arguments to pass to function</param>
329 internal void ExecuteEvent(uint localID, UUID itemID, string FunctionName, DetectParams[] qParams, object[] args)
330 {
331 //cfk 2-7-08 dont need this right now and the default Linux build has DEBUG defined
332 ///#if DEBUG
333 /// Console.WriteLine("ScriptEngine: Inside ExecuteEvent for event " + FunctionName);
334 ///#endif
335 // Execute a function in the script
336 //m_scriptEngine.Log.Info("[" + ScriptEngineName + "]: Executing Function localID: " + localID + ", itemID: " + itemID + ", FunctionName: " + FunctionName);
337 //ScriptBaseInterface Script = (ScriptBaseInterface)GetScript(localID, itemID);
338 IScript Script = GetScript(localID, itemID);
339 if (Script == null)
340 {
341 return;
342 }
343 //cfk 2-7-08 dont need this right now and the default Linux build has DEBUG defined
344 ///#if DEBUG
345 /// Console.WriteLine("ScriptEngine: Executing event: " + FunctionName);
346 ///#endif
347 // Must be done in correct AppDomain, so leaving it up to the script itself
348 detparms[Script] = qParams;
349 Script.Exec.ExecuteEvent(FunctionName, args);
350 detparms.Remove(Script);
351 }
352
353 public uint GetLocalID(UUID itemID)
354 {
355 foreach (KeyValuePair<uint, Dictionary<UUID, IScript> > k in Scripts)
356 {
357 if (k.Value.ContainsKey(itemID))
358 return k.Key;
359 }
360 return 0;
361 }
362
363 public int GetStateEventFlags(uint localID, UUID itemID)
364 {
365 // Console.WriteLine("GetStateEventFlags for <" + localID + "," + itemID + ">");
366 try
367 {
368 IScript Script = GetScript(localID, itemID);
369 if (Script == null)
370 {
371 return 0;
372 }
373 ExecutorBase.scriptEvents evflags = Script.Exec.GetStateEventFlags();
374 return (int)evflags;
375 }
376 catch (Exception)
377 {
378 }
379
380 return 0;
381 }
382
383
384 #endregion
385
386 #region Internal functions to keep track of script
387
388 public List<UUID> GetScriptKeys(uint localID)
389 {
390 if (Scripts.ContainsKey(localID) == false)
391 return new List<UUID>();
392
393 Dictionary<UUID, IScript> Obj;
394 Scripts.TryGetValue(localID, out Obj);
395
396 return new List<UUID>(Obj.Keys);
397 }
398
399 public IScript GetScript(uint localID, UUID itemID)
400 {
401 lock (scriptLock)
402 {
403 IScript Script = null;
404
405 if (Scripts.ContainsKey(localID) == false)
406 return null;
407
408 Dictionary<UUID, IScript> Obj;
409 Scripts.TryGetValue(localID, out Obj);
410 if (Obj.ContainsKey(itemID) == false)
411 return null;
412
413 // Get script
414 Obj.TryGetValue(itemID, out Script);
415 return Script;
416 }
417 }
418
419 public void SetScript(uint localID, UUID itemID, IScript Script)
420 {
421 lock (scriptLock)
422 {
423 // Create object if it doesn't exist
424 if (Scripts.ContainsKey(localID) == false)
425 {
426 Scripts.Add(localID, new Dictionary<UUID, IScript>());
427 }
428
429 // Delete script if it exists
430 Dictionary<UUID, IScript> Obj;
431 Scripts.TryGetValue(localID, out Obj);
432 if (Obj.ContainsKey(itemID) == true)
433 Obj.Remove(itemID);
434
435 // Add to object
436 Obj.Add(itemID, Script);
437 }
438 }
439
440 public void RemoveScript(uint localID, UUID itemID)
441 {
442 if (localID == 0)
443 localID = GetLocalID(itemID);
444
445 // Don't have that object?
446 if (Scripts.ContainsKey(localID) == false)
447 return;
448
449 // Delete script if it exists
450 Dictionary<UUID, IScript> Obj;
451 Scripts.TryGetValue(localID, out Obj);
452 if (Obj.ContainsKey(itemID) == true)
453 Obj.Remove(itemID);
454 }
455
456 #endregion
457
458
459 public void ResetScript(uint localID, UUID itemID)
460 {
461 IScript s = GetScript(localID, itemID);
462 string script = s.Source;
463 StopScript(localID, itemID);
464 SceneObjectPart part = World.GetSceneObjectPart(localID);
465 part.GetInventoryItem(itemID).PermsMask = 0;
466 part.GetInventoryItem(itemID).PermsGranter = UUID.Zero;
467 StartScript(localID, itemID, script, s.StartParam, false);
468 }
469
470
471 #region Script serialization/deserialization
472
473 public void GetSerializedScript(uint localID, UUID itemID)
474 {
475 // Serialize the script and return it
476 // Should not be a problem
477 FileStream fs = File.Create("SERIALIZED_SCRIPT_" + itemID);
478 BinaryFormatter b = new BinaryFormatter();
479 b.Serialize(fs, GetScript(localID, itemID));
480 fs.Close();
481 }
482
483 public void PutSerializedScript(uint localID, UUID itemID)
484 {
485 // Deserialize the script and inject it into an AppDomain
486
487 // How to inject into an AppDomain?
488 }
489
490 #endregion
491
492 ///// <summary>
493 ///// If set to true then threads and stuff should try to make a graceful exit
494 ///// </summary>
495 //public bool PleaseShutdown
496 //{
497 // get { return _PleaseShutdown; }
498 // set { _PleaseShutdown = value; }
499 //}
500 //private bool _PleaseShutdown = false;
501
502 public DetectParams[] GetDetectParams(IScript script)
503 {
504 if (detparms.ContainsKey(script))
505 return detparms[script];
506
507 return null;
508 }
509 }
510}
diff --git a/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/iScriptEngineFunctionModule.cs b/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/iScriptEngineFunctionModule.cs
deleted file mode 100644
index 768ba6d..0000000
--- a/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/iScriptEngineFunctionModule.cs
+++ /dev/null
@@ -1,35 +0,0 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
29{
30 public interface iScriptEngineFunctionModule
31 {
32 void ReadConfig();
33// bool PleaseShutdown { get; set; }
34 }
35}