diff options
author | Tedd Hansen | 2008-02-01 23:36:36 +0000 |
---|---|---|
committer | Tedd Hansen | 2008-02-01 23:36:36 +0000 |
commit | d02a90823f2873f1b4de63062e3909d03a5a91fa (patch) | |
tree | cb0d8f79fd36bec98bbac39c1185ee40c75e7c6d | |
parent | SCRIPT SUPPORT IS STILL BROKEN. (diff) | |
download | opensim-SC-d02a90823f2873f1b4de63062e3909d03a5a91fa.zip opensim-SC-d02a90823f2873f1b4de63062e3909d03a5a91fa.tar.gz opensim-SC-d02a90823f2873f1b4de63062e3909d03a5a91fa.tar.bz2 opensim-SC-d02a90823f2873f1b4de63062e3909d03a5a91fa.tar.xz |
SCRIPTING STILL BROKEN
Added comments and regions, restructured code
Changed a lot of AppDomain junk from console from using Console.Write to Log.Verbose and set it to #if DEBUG
All modules should now refresh their configuration runtime
Made all logging in ScriptEngine.Common get script name from actual engine
Renamed LSLLongCmdHandler to AsyncLSLCommandManager
Added auto-recover with 5 sec throttle for new MaintenanceThread
17 files changed, 621 insertions, 404 deletions
diff --git a/OpenSim/Region/ScriptEngine/Common/LSL_BaseClass.cs b/OpenSim/Region/ScriptEngine/Common/LSL_BaseClass.cs index dd46fa4..96a7dae 100644 --- a/OpenSim/Region/ScriptEngine/Common/LSL_BaseClass.cs +++ b/OpenSim/Region/ScriptEngine/Common/LSL_BaseClass.cs | |||
@@ -112,7 +112,7 @@ namespace OpenSim.Region.ScriptEngine.Common | |||
112 | { | 112 | { |
113 | m_LSL_Functions = LSL_Functions; | 113 | m_LSL_Functions = LSL_Functions; |
114 | 114 | ||
115 | //MainLog.Instance.Notice("ScriptEngine", "LSL_BaseClass.Start() called."); | 115 | //MainLog.Instance.Notice(ScriptEngineName, "LSL_BaseClass.Start() called."); |
116 | 116 | ||
117 | // Get this AppDomain's settings and display some of them. | 117 | // Get this AppDomain's settings and display some of them. |
118 | AppDomainSetup ads = AppDomain.CurrentDomain.SetupInformation; | 118 | AppDomainSetup ads = AppDomain.CurrentDomain.SetupInformation; |
diff --git a/OpenSim/Region/ScriptEngine/Common/LSL_BuiltIn_Commands.cs b/OpenSim/Region/ScriptEngine/Common/LSL_BuiltIn_Commands.cs index df049d8..bbf301d 100644 --- a/OpenSim/Region/ScriptEngine/Common/LSL_BuiltIn_Commands.cs +++ b/OpenSim/Region/ScriptEngine/Common/LSL_BuiltIn_Commands.cs | |||
@@ -61,7 +61,7 @@ namespace OpenSim.Region.ScriptEngine.Common | |||
61 | m_localID = localID; | 61 | m_localID = localID; |
62 | m_itemID = itemID; | 62 | m_itemID = itemID; |
63 | 63 | ||
64 | //MainLog.Instance.Notice("ScriptEngine", "LSL_BaseClass.Start() called. Hosted by [" + m_host.Name + ":" + m_host.UUID + "@" + m_host.AbsolutePosition + "]"); | 64 | //MainLog.Instance.Notice(ScriptEngineName, "LSL_BaseClass.Start() called. Hosted by [" + m_host.Name + ":" + m_host.UUID + "@" + m_host.AbsolutePosition + "]"); |
65 | } | 65 | } |
66 | 66 | ||
67 | private DateTime m_timer = DateTime.Now; | 67 | private DateTime m_timer = DateTime.Now; |
@@ -1038,7 +1038,7 @@ namespace OpenSim.Region.ScriptEngine.Common | |||
1038 | public void llSetTimerEvent(double sec) | 1038 | public void llSetTimerEvent(double sec) |
1039 | { | 1039 | { |
1040 | // Setting timer repeat | 1040 | // Setting timer repeat |
1041 | m_ScriptEngine.m_LSLLongCmdHandler.SetTimerEvent(m_localID, m_itemID, sec); | 1041 | m_ScriptEngine.m_ASYNCLSLCommandManager.SetTimerEvent(m_localID, m_itemID, sec); |
1042 | } | 1042 | } |
1043 | 1043 | ||
1044 | public void llSleep(double sec) | 1044 | public void llSleep(double sec) |
diff --git a/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/AppDomainManager.cs b/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/AppDomainManager.cs index 3519d54..2ed0529 100644 --- a/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/AppDomainManager.cs +++ b/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/AppDomainManager.cs | |||
@@ -35,7 +35,7 @@ using OpenSim.Region.ScriptEngine.Common; | |||
35 | 35 | ||
36 | namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase | 36 | namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase |
37 | { | 37 | { |
38 | public class AppDomainManager | 38 | public class AppDomainManager : iScriptEngineFunctionModule |
39 | { | 39 | { |
40 | 40 | ||
41 | // | 41 | // |
@@ -85,12 +85,17 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase | |||
85 | private object getLock = new object(); // Mutex | 85 | private object getLock = new object(); // Mutex |
86 | private object freeLock = new object(); // Mutex | 86 | private object freeLock = new object(); // Mutex |
87 | 87 | ||
88 | //private ScriptEngine m_scriptEngine; | 88 | private ScriptEngine m_scriptEngine; |
89 | //public AppDomainManager(ScriptEngine scriptEngine) | 89 | //public AppDomainManager(ScriptEngine scriptEngine) |
90 | public AppDomainManager(int MaxScriptsPerDomain) | 90 | public AppDomainManager(ScriptEngine scriptEngine) |
91 | { | 91 | { |
92 | maxScriptsPerAppDomain = MaxScriptsPerDomain; | 92 | m_scriptEngine = scriptEngine; |
93 | //m_scriptEngine = scriptEngine; | 93 | ReadConfig(); |
94 | } | ||
95 | |||
96 | public void ReadConfig() | ||
97 | { | ||
98 | maxScriptsPerAppDomain = m_scriptEngine.ScriptConfigSource.GetInt("ScriptsPerAppDomain", 1); | ||
94 | } | 99 | } |
95 | 100 | ||
96 | /// <summary> | 101 | /// <summary> |
@@ -99,7 +104,7 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase | |||
99 | /// <returns>Free AppDomain</returns> | 104 | /// <returns>Free AppDomain</returns> |
100 | private AppDomainStructure GetFreeAppDomain() | 105 | private AppDomainStructure GetFreeAppDomain() |
101 | { | 106 | { |
102 | Console.WriteLine("Finding free AppDomain"); | 107 | // Console.WriteLine("Finding free AppDomain"); |
103 | lock (getLock) | 108 | lock (getLock) |
104 | { | 109 | { |
105 | // Current full? | 110 | // Current full? |
@@ -117,7 +122,7 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase | |||
117 | currentAD.CurrentAppDomain = PrepareNewAppDomain(); | 122 | currentAD.CurrentAppDomain = PrepareNewAppDomain(); |
118 | } | 123 | } |
119 | 124 | ||
120 | Console.WriteLine("Scripts loaded in this Appdomain: " + currentAD.ScriptsLoaded); | 125 | // Console.WriteLine("Scripts loaded in this Appdomain: " + currentAD.ScriptsLoaded); |
121 | return currentAD; | 126 | return currentAD; |
122 | } // lock | 127 | } // lock |
123 | } | 128 | } |
@@ -144,7 +149,7 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase | |||
144 | ads.ConfigurationFile = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile; | 149 | ads.ConfigurationFile = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile; |
145 | 150 | ||
146 | AppDomain AD = AppDomain.CreateDomain("ScriptAppDomain_" + AppDomainNameCount, null, ads); | 151 | AppDomain AD = AppDomain.CreateDomain("ScriptAppDomain_" + AppDomainNameCount, null, ads); |
147 | Console.WriteLine("Loading: " + | 152 | m_scriptEngine.Log.Verbose(m_scriptEngine.ScriptEngineName, "AppDomain Loading: " + |
148 | AssemblyName.GetAssemblyName("OpenSim.Region.ScriptEngine.Common.dll").ToString()); | 153 | AssemblyName.GetAssemblyName("OpenSim.Region.ScriptEngine.Common.dll").ToString()); |
149 | AD.Load(AssemblyName.GetAssemblyName("OpenSim.Region.ScriptEngine.Common.dll")); | 154 | AD.Load(AssemblyName.GetAssemblyName("OpenSim.Region.ScriptEngine.Common.dll")); |
150 | 155 | ||
@@ -169,17 +174,16 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase | |||
169 | // Is number of unloaded bigger or equal to number of loaded? | 174 | // Is number of unloaded bigger or equal to number of loaded? |
170 | if (ads.ScriptsLoaded <= ads.ScriptsWaitingUnload) | 175 | if (ads.ScriptsLoaded <= ads.ScriptsWaitingUnload) |
171 | { | 176 | { |
172 | Console.WriteLine("Found empty AppDomain, unloading"); | ||
173 | // Remove from internal list | 177 | // Remove from internal list |
174 | appDomains.Remove(ads); | 178 | appDomains.Remove(ads); |
175 | #if DEBUG | 179 | #if DEBUG |
180 | Console.WriteLine("Found empty AppDomain, unloading"); | ||
176 | long m = GC.GetTotalMemory(true); | 181 | long m = GC.GetTotalMemory(true); |
177 | #endif | 182 | #endif |
178 | // Unload | 183 | // Unload |
179 | AppDomain.Unload(ads.CurrentAppDomain); | 184 | AppDomain.Unload(ads.CurrentAppDomain); |
180 | #if DEBUG | 185 | #if DEBUG |
181 | Console.WriteLine("AppDomain unload freed " + (m - GC.GetTotalMemory(true)) + | 186 | m_scriptEngine.Log.Verbose(m_scriptEngine.ScriptEngineName, "AppDomain unload freed " + (m - GC.GetTotalMemory(true)) + " bytes of memory"); |
182 | " bytes of memory"); | ||
183 | #endif | 187 | #endif |
184 | } | 188 | } |
185 | } | 189 | } |
@@ -193,7 +197,9 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase | |||
193 | // Find next available AppDomain to put it in | 197 | // Find next available AppDomain to put it in |
194 | AppDomainStructure FreeAppDomain = GetFreeAppDomain(); | 198 | AppDomainStructure FreeAppDomain = GetFreeAppDomain(); |
195 | 199 | ||
196 | Console.WriteLine("Loading into AppDomain: " + FileName); | 200 | #if DEBUG |
201 | m_scriptEngine.Log.Verbose(m_scriptEngine.ScriptEngineName, "Loading into AppDomain: " + FileName); | ||
202 | #endif | ||
197 | IScript mbrt = | 203 | IScript mbrt = |
198 | (IScript) | 204 | (IScript) |
199 | FreeAppDomain.CurrentAppDomain.CreateInstanceFromAndUnwrap(FileName, "SecondLife.Script"); | 205 | FreeAppDomain.CurrentAppDomain.CreateInstanceFromAndUnwrap(FileName, "SecondLife.Script"); |
@@ -213,7 +219,9 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase | |||
213 | { | 219 | { |
214 | lock (freeLock) | 220 | lock (freeLock) |
215 | { | 221 | { |
216 | Console.WriteLine("Stopping script in AppDomain"); | 222 | #if DEBUG |
223 | m_scriptEngine.Log.Verbose(m_scriptEngine.ScriptEngineName, "Stopping script in AppDomain"); | ||
224 | #endif | ||
217 | // Check if it is current AppDomain | 225 | // Check if it is current AppDomain |
218 | if (currentAD.CurrentAppDomain == ad) | 226 | if (currentAD.CurrentAppDomain == ad) |
219 | { | 227 | { |
@@ -236,5 +244,15 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase | |||
236 | 244 | ||
237 | UnloadAppDomains(); // Outsite lock, has its own GetLock | 245 | UnloadAppDomains(); // Outsite lock, has its own GetLock |
238 | } | 246 | } |
247 | /// <summary> | ||
248 | /// If set to true then threads and stuff should try to make a graceful exit | ||
249 | /// </summary> | ||
250 | public bool PleaseShutdown | ||
251 | { | ||
252 | get { return _PleaseShutdown; } | ||
253 | set { _PleaseShutdown = value; } | ||
254 | } | ||
255 | private bool _PleaseShutdown = false; | ||
256 | |||
239 | } | 257 | } |
240 | } \ No newline at end of file | 258 | } \ No newline at end of file |
diff --git a/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/LSLLongCmdHandler.cs b/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/AsyncLSLCommandManager.cs index 7d66638..5ec8f50 100644 --- a/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/LSLLongCmdHandler.cs +++ b/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/AsyncLSLCommandManager.cs | |||
@@ -1,295 +1,313 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) Contributors, http://opensimulator.org/ | 2 | * Copyright (c) Contributors, http://opensimulator.org/ |
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | 3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. |
4 | * | 4 | * |
5 | * Redistribution and use in source and binary forms, with or without | 5 | * Redistribution and use in source and binary forms, with or without |
6 | * modification, are permitted provided that the following conditions are met: | 6 | * modification, are permitted provided that the following conditions are met: |
7 | * * Redistributions of source code must retain the above copyright | 7 | * * Redistributions of source code must retain the above copyright |
8 | * notice, this list of conditions and the following disclaimer. | 8 | * notice, this list of conditions and the following disclaimer. |
9 | * * Redistributions in binary form must reproduce the above copyright | 9 | * * Redistributions in binary form must reproduce the above copyright |
10 | * notice, this list of conditions and the following disclaimer in the | 10 | * notice, this list of conditions and the following disclaimer in the |
11 | * documentation and/or other materials provided with the distribution. | 11 | * documentation and/or other materials provided with the distribution. |
12 | * * Neither the name of the OpenSim Project nor the | 12 | * * Neither the name of the OpenSim Project nor the |
13 | * names of its contributors may be used to endorse or promote products | 13 | * names of its contributors may be used to endorse or promote products |
14 | * derived from this software without specific prior written permission. | 14 | * derived from this software without specific prior written permission. |
15 | * | 15 | * |
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS AS IS AND ANY | 16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS AS IS AND ANY |
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | 17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | 19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY |
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | 20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
26 | * | 26 | * |
27 | */ | 27 | */ |
28 | 28 | ||
29 | using System; | 29 | using System; |
30 | using System.Collections.Generic; | 30 | using System.Collections.Generic; |
31 | using System.Threading; | 31 | using System.Threading; |
32 | using libsecondlife; | 32 | using libsecondlife; |
33 | using OpenSim.Region.Environment.Interfaces; | 33 | using OpenSim.Region.Environment.Interfaces; |
34 | using OpenSim.Region.Environment.Modules; | 34 | using OpenSim.Region.Environment.Modules; |
35 | 35 | ||
36 | namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase | 36 | namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase |
37 | { | 37 | { |
38 | /// <summary> | 38 | /// <summary> |
39 | /// Handles LSL commands that takes long time and returns an event, for example timers, HTTP requests, etc. | 39 | /// Handles LSL commands that takes long time and returns an event, for example timers, HTTP requests, etc. |
40 | /// </summary> | 40 | /// </summary> |
41 | public class LSLLongCmdHandler | 41 | public class AsyncLSLCommandManager : iScriptEngineFunctionModule |
42 | { | 42 | { |
43 | private Thread cmdHandlerThread; | 43 | private Thread cmdHandlerThread; |
44 | private int cmdHandlerThreadCycleSleepms = 100; | 44 | private int cmdHandlerThreadCycleSleepms; |
45 | 45 | ||
46 | private ScriptEngine m_ScriptEngine; | 46 | private ScriptEngine m_ScriptEngine; |
47 | 47 | ||
48 | public LSLLongCmdHandler(ScriptEngine _ScriptEngine) | 48 | public AsyncLSLCommandManager(ScriptEngine _ScriptEngine) |
49 | { | 49 | { |
50 | m_ScriptEngine = _ScriptEngine; | 50 | m_ScriptEngine = _ScriptEngine; |
51 | 51 | ReadConfig(); | |
52 | // Start the thread that will be doing the work | 52 | |
53 | cmdHandlerThread = new Thread(CmdHandlerThreadLoop); | 53 | // Start the thread that will be doing the work |
54 | cmdHandlerThread.Name = "CmdHandlerThread"; | 54 | cmdHandlerThread = new Thread(CmdHandlerThreadLoop); |
55 | cmdHandlerThread.Priority = ThreadPriority.BelowNormal; | 55 | cmdHandlerThread.Name = "CmdHandlerThread"; |
56 | cmdHandlerThread.IsBackground = true; | 56 | cmdHandlerThread.Priority = ThreadPriority.BelowNormal; |
57 | cmdHandlerThread.Start(); | 57 | cmdHandlerThread.IsBackground = true; |
58 | } | 58 | cmdHandlerThread.Start(); |
59 | 59 | } | |
60 | ~LSLLongCmdHandler() | 60 | |
61 | { | 61 | public void ReadConfig() |
62 | // Shut down thread | 62 | { |
63 | try | 63 | cmdHandlerThreadCycleSleepms = m_ScriptEngine.ScriptConfigSource.GetInt("AsyncLLCommandLoopms", 50); |
64 | { | 64 | } |
65 | if (cmdHandlerThread != null) | 65 | |
66 | { | 66 | |
67 | if (cmdHandlerThread.IsAlive == true) | 67 | ~AsyncLSLCommandManager() |
68 | { | 68 | { |
69 | cmdHandlerThread.Abort(); | 69 | // Shut down thread |
70 | cmdHandlerThread.Join(); | 70 | try |
71 | } | 71 | { |
72 | } | 72 | if (cmdHandlerThread != null) |
73 | } | 73 | { |
74 | catch | 74 | if (cmdHandlerThread.IsAlive == true) |
75 | { | 75 | { |
76 | } | 76 | cmdHandlerThread.Abort(); |
77 | } | 77 | cmdHandlerThread.Join(); |
78 | 78 | } | |
79 | private void CmdHandlerThreadLoop() | 79 | } |
80 | { | 80 | } |
81 | while (true) | 81 | catch |
82 | { | 82 | { |
83 | // Check timers | 83 | } |
84 | CheckTimerEvents(); | 84 | } |
85 | Thread.Sleep(25); | 85 | |
86 | // Check HttpRequests | 86 | private void CmdHandlerThreadLoop() |
87 | CheckHttpRequests(); | 87 | { |
88 | Thread.Sleep(25); | 88 | while (true) |
89 | // Check XMLRPCRequests | 89 | { |
90 | CheckXMLRPCRequests(); | 90 | // Check timers |
91 | Thread.Sleep(25); | 91 | CheckTimerEvents(); |
92 | // Check Listeners | 92 | Thread.Sleep(25); |
93 | CheckListeners(); | 93 | // Check HttpRequests |
94 | Thread.Sleep(25); | 94 | CheckHttpRequests(); |
95 | 95 | Thread.Sleep(25); | |
96 | // Sleep before next cycle | 96 | // Check XMLRPCRequests |
97 | //Thread.Sleep(cmdHandlerThreadCycleSleepms); | 97 | CheckXMLRPCRequests(); |
98 | } | 98 | Thread.Sleep(25); |
99 | } | 99 | // Check Listeners |
100 | 100 | CheckListeners(); | |
101 | /// <summary> | 101 | Thread.Sleep(25); |
102 | /// Remove a specific script (and all its pending commands) | 102 | |
103 | /// </summary> | 103 | // Sleep before next cycle |
104 | /// <param name="m_localID"></param> | 104 | //Thread.Sleep(cmdHandlerThreadCycleSleepms); |
105 | /// <param name="m_itemID"></param> | 105 | } |
106 | public void RemoveScript(uint localID, LLUUID itemID) | 106 | } |
107 | { | 107 | |
108 | // Remove a specific script | 108 | /// <summary> |
109 | 109 | /// Remove a specific script (and all its pending commands) | |
110 | // Remove from: Timers | 110 | /// </summary> |
111 | UnSetTimerEvents(localID, itemID); | 111 | /// <param name="m_localID"></param> |
112 | // Remove from: HttpRequest | 112 | /// <param name="m_itemID"></param> |
113 | IHttpRequests iHttpReq = | 113 | public void RemoveScript(uint localID, LLUUID itemID) |
114 | m_ScriptEngine.World.RequestModuleInterface<IHttpRequests>(); | 114 | { |
115 | iHttpReq.StopHttpRequest(localID, itemID); | 115 | // Remove a specific script |
116 | } | 116 | |
117 | 117 | // Remove from: Timers | |
118 | #region TIMER | 118 | UnSetTimerEvents(localID, itemID); |
119 | 119 | // Remove from: HttpRequest | |
120 | // | 120 | IHttpRequests iHttpReq = |
121 | // TIMER | 121 | m_ScriptEngine.World.RequestModuleInterface<IHttpRequests>(); |
122 | // | 122 | iHttpReq.StopHttpRequest(localID, itemID); |
123 | private class TimerClass | 123 | } |
124 | { | 124 | |
125 | public uint localID; | 125 | #region TIMER |
126 | public LLUUID itemID; | 126 | |
127 | public double interval; | 127 | // |
128 | public DateTime next; | 128 | // TIMER |
129 | } | 129 | // |
130 | 130 | private class TimerClass | |
131 | private List<TimerClass> Timers = new List<TimerClass>(); | 131 | { |
132 | private object TimerListLock = new object(); | 132 | public uint localID; |
133 | 133 | public LLUUID itemID; | |
134 | public void SetTimerEvent(uint m_localID, LLUUID m_itemID, double sec) | 134 | public double interval; |
135 | { | 135 | public DateTime next; |
136 | Console.WriteLine("SetTimerEvent"); | 136 | } |
137 | 137 | ||
138 | // Always remove first, in case this is a re-set | 138 | private List<TimerClass> Timers = new List<TimerClass>(); |
139 | UnSetTimerEvents(m_localID, m_itemID); | 139 | private object TimerListLock = new object(); |
140 | if (sec == 0) // Disabling timer | 140 | |
141 | return; | 141 | public void SetTimerEvent(uint m_localID, LLUUID m_itemID, double sec) |
142 | 142 | { | |
143 | // Add to timer | 143 | Console.WriteLine("SetTimerEvent"); |
144 | TimerClass ts = new TimerClass(); | 144 | |
145 | ts.localID = m_localID; | 145 | // Always remove first, in case this is a re-set |
146 | ts.itemID = m_itemID; | 146 | UnSetTimerEvents(m_localID, m_itemID); |
147 | ts.interval = sec; | 147 | if (sec == 0) // Disabling timer |
148 | ts.next = DateTime.Now.ToUniversalTime().AddSeconds(ts.interval); | 148 | return; |
149 | lock (TimerListLock) | 149 | |
150 | { | 150 | // Add to timer |
151 | Timers.Add(ts); | 151 | TimerClass ts = new TimerClass(); |
152 | } | 152 | ts.localID = m_localID; |
153 | } | 153 | ts.itemID = m_itemID; |
154 | 154 | ts.interval = sec; | |
155 | public void UnSetTimerEvents(uint m_localID, LLUUID m_itemID) | 155 | ts.next = DateTime.Now.ToUniversalTime().AddSeconds(ts.interval); |
156 | { | 156 | lock (TimerListLock) |
157 | // Remove from timer | 157 | { |
158 | lock (TimerListLock) | 158 | Timers.Add(ts); |
159 | { | 159 | } |
160 | List<TimerClass> NewTimers = new List<TimerClass>(); | 160 | } |
161 | foreach (TimerClass ts in Timers) | 161 | |
162 | { | 162 | public void UnSetTimerEvents(uint m_localID, LLUUID m_itemID) |
163 | if (ts.localID != m_localID && ts.itemID != m_itemID) | 163 | { |
164 | { | 164 | // Remove from timer |
165 | NewTimers.Add(ts); | 165 | lock (TimerListLock) |
166 | } | 166 | { |
167 | } | 167 | List<TimerClass> NewTimers = new List<TimerClass>(); |
168 | Timers.Clear(); | 168 | foreach (TimerClass ts in Timers) |
169 | Timers = NewTimers; | 169 | { |
170 | } | 170 | if (ts.localID != m_localID && ts.itemID != m_itemID) |
171 | } | 171 | { |
172 | 172 | NewTimers.Add(ts); | |
173 | public void CheckTimerEvents() | 173 | } |
174 | { | 174 | } |
175 | // Nothing to do here? | 175 | Timers.Clear(); |
176 | if (Timers.Count == 0) | 176 | Timers = NewTimers; |
177 | return; | 177 | } |
178 | 178 | } | |
179 | lock (TimerListLock) | 179 | |
180 | { | 180 | public void CheckTimerEvents() |
181 | // Go through all timers | 181 | { |
182 | foreach (TimerClass ts in Timers) | 182 | // Nothing to do here? |
183 | { | 183 | if (Timers.Count == 0) |
184 | // Time has passed? | 184 | return; |
185 | if (ts.next.ToUniversalTime() < DateTime.Now.ToUniversalTime()) | 185 | |
186 | { | 186 | lock (TimerListLock) |
187 | // Add it to queue | 187 | { |
188 | m_ScriptEngine.m_EventQueueManager.AddToScriptQueue(ts.localID, ts.itemID, "timer", EventQueueManager.llDetectNull, | 188 | // Go through all timers |
189 | new object[] {}); | 189 | foreach (TimerClass ts in Timers) |
190 | // set next interval | 190 | { |
191 | 191 | // Time has passed? | |
192 | 192 | if (ts.next.ToUniversalTime() < DateTime.Now.ToUniversalTime()) | |
193 | ts.next = DateTime.Now.ToUniversalTime().AddSeconds(ts.interval); | 193 | { |
194 | } | 194 | // Add it to queue |
195 | } | 195 | m_ScriptEngine.m_EventQueueManager.AddToScriptQueue(ts.localID, ts.itemID, "timer", EventQueueManager.llDetectNull, |
196 | } // lock | 196 | new object[] {}); |
197 | } | 197 | // set next interval |
198 | 198 | ||
199 | #endregion | 199 | |
200 | 200 | ts.next = DateTime.Now.ToUniversalTime().AddSeconds(ts.interval); | |
201 | #region HTTP REQUEST | 201 | } |
202 | 202 | } | |
203 | public void CheckHttpRequests() | 203 | } // lock |
204 | { | 204 | } |
205 | if (m_ScriptEngine.World == null) | 205 | |
206 | return; | 206 | #endregion |
207 | 207 | ||
208 | IHttpRequests iHttpReq = | 208 | #region HTTP REQUEST |
209 | m_ScriptEngine.World.RequestModuleInterface<IHttpRequests>(); | 209 | |
210 | 210 | public void CheckHttpRequests() | |
211 | HttpRequestClass httpInfo = null; | 211 | { |
212 | 212 | if (m_ScriptEngine.World == null) | |
213 | if (iHttpReq != null) | 213 | return; |
214 | httpInfo = iHttpReq.GetNextCompletedRequest(); | 214 | |
215 | 215 | IHttpRequests iHttpReq = | |
216 | while (httpInfo != null) | 216 | m_ScriptEngine.World.RequestModuleInterface<IHttpRequests>(); |
217 | { | 217 | |
218 | //Console.WriteLine("PICKED HTTP REQ:" + httpInfo.response_body + httpInfo.status); | 218 | HttpRequestClass httpInfo = null; |
219 | 219 | ||
220 | // Deliver data to prim's remote_data handler | 220 | if (iHttpReq != null) |
221 | // | 221 | httpInfo = iHttpReq.GetNextCompletedRequest(); |
222 | // TODO: Returning null for metadata, since the lsl function | 222 | |
223 | // only returns the byte for HTTP_BODY_TRUNCATED, which is not | 223 | while (httpInfo != null) |
224 | // implemented here yet anyway. Should be fixed if/when maxsize | 224 | { |
225 | // is supported | 225 | //Console.WriteLine("PICKED HTTP REQ:" + httpInfo.response_body + httpInfo.status); |
226 | 226 | ||
227 | object[] resobj = new object[] | 227 | // Deliver data to prim's remote_data handler |
228 | { | 228 | // |
229 | httpInfo.reqID.ToString(), httpInfo.status, null, httpInfo.response_body | 229 | // TODO: Returning null for metadata, since the lsl function |
230 | }; | 230 | // only returns the byte for HTTP_BODY_TRUNCATED, which is not |
231 | 231 | // implemented here yet anyway. Should be fixed if/when maxsize | |
232 | m_ScriptEngine.m_EventQueueManager.AddToScriptQueue( | 232 | // is supported |
233 | httpInfo.localID, httpInfo.itemID, "http_response", EventQueueManager.llDetectNull, resobj | 233 | |
234 | ); | 234 | object[] resobj = new object[] |
235 | 235 | { | |
236 | httpInfo.Stop(); | 236 | httpInfo.reqID.ToString(), httpInfo.status, null, httpInfo.response_body |
237 | httpInfo = null; | 237 | }; |
238 | 238 | ||
239 | httpInfo = iHttpReq.GetNextCompletedRequest(); | 239 | m_ScriptEngine.m_EventQueueManager.AddToScriptQueue( |
240 | } | 240 | httpInfo.localID, httpInfo.itemID, "http_response", EventQueueManager.llDetectNull, resobj |
241 | } | 241 | ); |
242 | 242 | ||
243 | #endregion | 243 | httpInfo.Stop(); |
244 | 244 | httpInfo = null; | |
245 | public void CheckXMLRPCRequests() | 245 | |
246 | { | 246 | httpInfo = iHttpReq.GetNextCompletedRequest(); |
247 | if (m_ScriptEngine.World == null) | 247 | } |
248 | return; | 248 | } |
249 | 249 | ||
250 | IXMLRPC xmlrpc = m_ScriptEngine.World.RequestModuleInterface<IXMLRPC>(); | 250 | #endregion |
251 | 251 | ||
252 | if (xmlrpc != null) | 252 | public void CheckXMLRPCRequests() |
253 | { | 253 | { |
254 | while (xmlrpc.hasRequests()) | 254 | if (m_ScriptEngine.World == null) |
255 | { | 255 | return; |
256 | RPCRequestInfo rInfo = xmlrpc.GetNextRequest(); | 256 | |
257 | //Console.WriteLine("PICKED REQUEST"); | 257 | IXMLRPC xmlrpc = m_ScriptEngine.World.RequestModuleInterface<IXMLRPC>(); |
258 | 258 | ||
259 | //Deliver data to prim's remote_data handler | 259 | if (xmlrpc != null) |
260 | object[] resobj = new object[] | 260 | { |
261 | { | 261 | while (xmlrpc.hasRequests()) |
262 | 2, rInfo.GetChannelKey().ToString(), rInfo.GetMessageID().ToString(), String.Empty, | 262 | { |
263 | rInfo.GetIntValue(), | 263 | RPCRequestInfo rInfo = xmlrpc.GetNextRequest(); |
264 | rInfo.GetStrVal() | 264 | //Console.WriteLine("PICKED REQUEST"); |
265 | }; | 265 | |
266 | m_ScriptEngine.m_EventQueueManager.AddToScriptQueue( | 266 | //Deliver data to prim's remote_data handler |
267 | rInfo.GetLocalID(), rInfo.GetItemID(), "remote_data", EventQueueManager.llDetectNull, resobj | 267 | object[] resobj = new object[] |
268 | ); | 268 | { |
269 | } | 269 | 2, rInfo.GetChannelKey().ToString(), rInfo.GetMessageID().ToString(), String.Empty, |
270 | } | 270 | rInfo.GetIntValue(), |
271 | } | 271 | rInfo.GetStrVal() |
272 | 272 | }; | |
273 | public void CheckListeners() | 273 | m_ScriptEngine.m_EventQueueManager.AddToScriptQueue( |
274 | { | 274 | rInfo.GetLocalID(), rInfo.GetItemID(), "remote_data", EventQueueManager.llDetectNull, resobj |
275 | if (m_ScriptEngine.World == null) | 275 | ); |
276 | return; | 276 | } |
277 | IWorldComm comms = m_ScriptEngine.World.RequestModuleInterface<IWorldComm>(); | 277 | } |
278 | 278 | } | |
279 | while (comms.HasMessages()) | 279 | |
280 | { | 280 | public void CheckListeners() |
281 | ListenerInfo lInfo = comms.GetNextMessage(); | 281 | { |
282 | 282 | if (m_ScriptEngine.World == null) | |
283 | //Deliver data to prim's listen handler | 283 | return; |
284 | object[] resobj = new object[] | 284 | IWorldComm comms = m_ScriptEngine.World.RequestModuleInterface<IWorldComm>(); |
285 | { | 285 | |
286 | lInfo.GetChannel(), lInfo.GetName(), lInfo.GetID().ToString(), lInfo.GetMessage() | 286 | while (comms.HasMessages()) |
287 | }; | 287 | { |
288 | 288 | ListenerInfo lInfo = comms.GetNextMessage(); | |
289 | m_ScriptEngine.m_EventQueueManager.AddToScriptQueue( | 289 | |
290 | lInfo.GetLocalID(), lInfo.GetItemID(), "listen", EventQueueManager.llDetectNull, resobj | 290 | //Deliver data to prim's listen handler |
291 | ); | 291 | object[] resobj = new object[] |
292 | } | 292 | { |
293 | } | 293 | lInfo.GetChannel(), lInfo.GetName(), lInfo.GetID().ToString(), lInfo.GetMessage() |
294 | } | 294 | }; |
295 | |||
296 | m_ScriptEngine.m_EventQueueManager.AddToScriptQueue( | ||
297 | lInfo.GetLocalID(), lInfo.GetItemID(), "listen", EventQueueManager.llDetectNull, resobj | ||
298 | ); | ||
299 | } | ||
300 | } | ||
301 | |||
302 | /// <summary> | ||
303 | /// If set to true then threads and stuff should try to make a graceful exit | ||
304 | /// </summary> | ||
305 | public bool PleaseShutdown | ||
306 | { | ||
307 | get { return _PleaseShutdown; } | ||
308 | set { _PleaseShutdown = value; } | ||
309 | } | ||
310 | private bool _PleaseShutdown = false; | ||
311 | |||
312 | } | ||
295 | } \ No newline at end of file | 313 | } \ No newline at end of file |
diff --git a/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/Common.cs b/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/Common.cs index bce26ff..fe6dfcd 100644 --- a/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/Common.cs +++ b/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/Common.cs | |||
@@ -44,14 +44,14 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase | |||
44 | public static void SendToDebug(string Message) | 44 | public static void SendToDebug(string Message) |
45 | { | 45 | { |
46 | //if (Debug == true) | 46 | //if (Debug == true) |
47 | mySE.Log.Verbose("ScriptEngine", "Debug: " + Message); | 47 | mySE.Log.Verbose(mySE.ScriptEngineName, "Debug: " + Message); |
48 | //SendToDebugEvent("\r\n" + DateTime.Now.ToString("[HH:mm:ss] ") + Message); | 48 | //SendToDebugEvent("\r\n" + DateTime.Now.ToString("[HH:mm:ss] ") + Message); |
49 | } | 49 | } |
50 | 50 | ||
51 | public static void SendToLog(string Message) | 51 | public static void SendToLog(string Message) |
52 | { | 52 | { |
53 | //if (Debug == true) | 53 | //if (Debug == true) |
54 | mySE.Log.Verbose("ScriptEngine", "LOG: " + Message); | 54 | mySE.Log.Verbose(mySE.ScriptEngineName, "LOG: " + Message); |
55 | //SendToLogEvent("\r\n" + DateTime.Now.ToString("[HH:mm:ss] ") + Message); | 55 | //SendToLogEvent("\r\n" + DateTime.Now.ToString("[HH:mm:ss] ") + Message); |
56 | } | 56 | } |
57 | } | 57 | } |
diff --git a/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/EventManager.cs b/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/EventManager.cs index 250a5df..678c3d0 100644 --- a/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/EventManager.cs +++ b/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/EventManager.cs | |||
@@ -37,7 +37,7 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase | |||
37 | /// Prepares events so they can be directly executed upon a script by EventQueueManager, then queues it. | 37 | /// Prepares events so they can be directly executed upon a script by EventQueueManager, then queues it. |
38 | /// </summary> | 38 | /// </summary> |
39 | [Serializable] | 39 | [Serializable] |
40 | public class EventManager : OpenSim.Region.ScriptEngine.Common.ScriptServerInterfaces.RemoteEvents | 40 | public class EventManager : OpenSim.Region.ScriptEngine.Common.ScriptServerInterfaces.RemoteEvents, iScriptEngineFunctionModule |
41 | { | 41 | { |
42 | 42 | ||
43 | // | 43 | // |
@@ -59,12 +59,13 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase | |||
59 | public EventManager(ScriptEngine _ScriptEngine, bool performHookUp) | 59 | public EventManager(ScriptEngine _ScriptEngine, bool performHookUp) |
60 | { | 60 | { |
61 | myScriptEngine = _ScriptEngine; | 61 | myScriptEngine = _ScriptEngine; |
62 | ReadConfig(); | ||
62 | 63 | ||
63 | // Hook up to events from OpenSim | 64 | // Hook up to events from OpenSim |
64 | // We may not want to do it because someone is controlling us and will deliver events to us | 65 | // We may not want to do it because someone is controlling us and will deliver events to us |
65 | if (performHookUp) | 66 | if (performHookUp) |
66 | { | 67 | { |
67 | myScriptEngine.Log.Verbose("ScriptEngine", "Hooking up to server events"); | 68 | myScriptEngine.Log.Verbose(myScriptEngine.ScriptEngineName, "Hooking up to server events"); |
68 | myScriptEngine.World.EventManager.OnObjectGrab += touch_start; | 69 | myScriptEngine.World.EventManager.OnObjectGrab += touch_start; |
69 | myScriptEngine.World.EventManager.OnRezScript += OnRezScript; | 70 | myScriptEngine.World.EventManager.OnRezScript += OnRezScript; |
70 | myScriptEngine.World.EventManager.OnRemoveScript += OnRemoveScript; | 71 | myScriptEngine.World.EventManager.OnRemoveScript += OnRemoveScript; |
@@ -73,6 +74,11 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase | |||
73 | } | 74 | } |
74 | } | 75 | } |
75 | 76 | ||
77 | public void ReadConfig() | ||
78 | { | ||
79 | } | ||
80 | |||
81 | |||
76 | public void changed(uint localID, uint change) | 82 | public void changed(uint localID, uint change) |
77 | { | 83 | { |
78 | // Add to queue for all scripts in localID, Object pass change. | 84 | // Add to queue for all scripts in localID, Object pass change. |
@@ -263,5 +269,16 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase | |||
263 | { | 269 | { |
264 | // myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "http_response", EventQueueManager.llDetectNull); | 270 | // myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "http_response", EventQueueManager.llDetectNull); |
265 | } | 271 | } |
272 | |||
273 | /// <summary> | ||
274 | /// If set to true then threads and stuff should try to make a graceful exit | ||
275 | /// </summary> | ||
276 | public bool PleaseShutdown | ||
277 | { | ||
278 | get { return _PleaseShutdown; } | ||
279 | set { _PleaseShutdown = value; } | ||
280 | } | ||
281 | private bool _PleaseShutdown = false; | ||
282 | |||
266 | } | 283 | } |
267 | } \ No newline at end of file | 284 | } \ No newline at end of file |
diff --git a/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/EventQueueManager.cs b/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/EventQueueManager.cs index 04c084a..3ba4618 100644 --- a/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/EventQueueManager.cs +++ b/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/EventQueueManager.cs | |||
@@ -42,7 +42,7 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase | |||
42 | /// Events are queued and executed in separate thread | 42 | /// Events are queued and executed in separate thread |
43 | /// </summary> | 43 | /// </summary> |
44 | [Serializable] | 44 | [Serializable] |
45 | public class EventQueueManager | 45 | public class EventQueueManager : iScriptEngineFunctionModule |
46 | { | 46 | { |
47 | 47 | ||
48 | // | 48 | // |
@@ -197,13 +197,22 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase | |||
197 | 197 | ||
198 | } | 198 | } |
199 | 199 | ||
200 | private void ReadConfig() | 200 | public void ReadConfig() |
201 | { | 201 | { |
202 | // Refresh config | ||
202 | numberOfThreads = m_ScriptEngine.ScriptConfigSource.GetInt("NumberOfScriptThreads", 2); | 203 | numberOfThreads = m_ScriptEngine.ScriptConfigSource.GetInt("NumberOfScriptThreads", 2); |
203 | maxFunctionExecutionTimems = m_ScriptEngine.ScriptConfigSource.GetInt("MaxEventExecutionTimeMs", 5000); | 204 | maxFunctionExecutionTimems = m_ScriptEngine.ScriptConfigSource.GetInt("MaxEventExecutionTimeMs", 5000); |
204 | EnforceMaxExecutionTime = m_ScriptEngine.ScriptConfigSource.GetBoolean("EnforceMaxEventExecutionTime", false); | 205 | EnforceMaxExecutionTime = m_ScriptEngine.ScriptConfigSource.GetBoolean("EnforceMaxEventExecutionTime", false); |
205 | KillScriptOnMaxFunctionExecutionTime = m_ScriptEngine.ScriptConfigSource.GetBoolean("DeactivateScriptOnTimeout", false); | 206 | KillScriptOnMaxFunctionExecutionTime = m_ScriptEngine.ScriptConfigSource.GetBoolean("DeactivateScriptOnTimeout", false); |
206 | 207 | ||
208 | // Now refresh config in all threads | ||
209 | lock (eventQueueThreadsLock) | ||
210 | { | ||
211 | foreach (EventQueueThreadClass EventQueueThread in eventQueueThreads) | ||
212 | { | ||
213 | EventQueueThread.ReadConfig(); | ||
214 | } | ||
215 | } | ||
207 | } | 216 | } |
208 | 217 | ||
209 | #endregion | 218 | #endregion |
@@ -222,7 +231,7 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase | |||
222 | { | 231 | { |
223 | foreach (EventQueueThreadClass EventQueueThread in eventQueueThreads) | 232 | foreach (EventQueueThreadClass EventQueueThread in eventQueueThreads) |
224 | { | 233 | { |
225 | EventQueueThread.Shutdown(); | 234 | AbortThreadClass(EventQueueThread); |
226 | } | 235 | } |
227 | eventQueueThreads.Clear(); | 236 | eventQueueThreads.Clear(); |
228 | staticGlobalEventQueueThreads.Clear(); | 237 | staticGlobalEventQueueThreads.Clear(); |
@@ -243,7 +252,7 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase | |||
243 | EventQueueThreadClass eqtc = new EventQueueThreadClass(this); | 252 | EventQueueThreadClass eqtc = new EventQueueThreadClass(this); |
244 | eventQueueThreads.Add(eqtc); | 253 | eventQueueThreads.Add(eqtc); |
245 | staticGlobalEventQueueThreads.Add(eqtc); | 254 | staticGlobalEventQueueThreads.Add(eqtc); |
246 | m_ScriptEngine.Log.Debug("DotNetEngine", "Started new script execution thread. Current thread count: " + eventQueueThreads.Count); | 255 | m_ScriptEngine.Log.Debug(m_ScriptEngine.ScriptEngineName, "Started new script execution thread. Current thread count: " + eventQueueThreads.Count); |
247 | 256 | ||
248 | } | 257 | } |
249 | private void AbortThreadClass(EventQueueThreadClass threadClass) | 258 | private void AbortThreadClass(EventQueueThreadClass threadClass) |
@@ -252,16 +261,17 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase | |||
252 | eventQueueThreads.Remove(threadClass); | 261 | eventQueueThreads.Remove(threadClass); |
253 | if (staticGlobalEventQueueThreads.Contains(threadClass)) | 262 | if (staticGlobalEventQueueThreads.Contains(threadClass)) |
254 | staticGlobalEventQueueThreads.Remove(threadClass); | 263 | staticGlobalEventQueueThreads.Remove(threadClass); |
264 | |||
255 | try | 265 | try |
256 | { | 266 | { |
257 | threadClass.Shutdown(); | 267 | threadClass.Stop(); |
258 | } | 268 | } |
259 | catch (Exception ex) | 269 | catch (Exception ex) |
260 | { | 270 | { |
261 | m_ScriptEngine.Log.Error("EventQueueManager", "If you see this, could you please report it to Tedd:"); | 271 | m_ScriptEngine.Log.Error(m_ScriptEngine.ScriptEngineName + ":EventQueueManager", "If you see this, could you please report it to Tedd:"); |
262 | m_ScriptEngine.Log.Error("EventQueueManager", "Script thread execution timeout kill ended in exception: " + ex.ToString()); | 272 | m_ScriptEngine.Log.Error(m_ScriptEngine.ScriptEngineName + ":EventQueueManager", "Script thread execution timeout kill ended in exception: " + ex.ToString()); |
263 | } | 273 | } |
264 | m_ScriptEngine.Log.Debug("DotNetEngine", "Killed script execution thread. Remaining thread count: " + eventQueueThreads.Count); | 274 | m_ScriptEngine.Log.Debug(m_ScriptEngine.ScriptEngineName, "Killed script execution thread. Remaining thread count: " + eventQueueThreads.Count); |
265 | } | 275 | } |
266 | #endregion | 276 | #endregion |
267 | 277 | ||
@@ -313,7 +323,7 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase | |||
313 | public void AddToObjectQueue(uint localID, string FunctionName, Queue_llDetectParams_Struct qParams, params object[] param) | 323 | public void AddToObjectQueue(uint localID, string FunctionName, Queue_llDetectParams_Struct qParams, params object[] param) |
314 | { | 324 | { |
315 | // Determine all scripts in Object and add to their queue | 325 | // Determine all scripts in Object and add to their queue |
316 | //myScriptEngine.m_logger.Verbose("ScriptEngine", "EventQueueManager Adding localID: " + localID + ", FunctionName: " + FunctionName); | 326 | //myScriptEngine.m_logger.Verbose(ScriptEngineName, "EventQueueManager Adding localID: " + localID + ", FunctionName: " + FunctionName); |
317 | 327 | ||
318 | 328 | ||
319 | // Do we have any scripts in this object at all? If not, return | 329 | // Do we have any scripts in this object at all? If not, return |
@@ -367,6 +377,10 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase | |||
367 | /// </summary> | 377 | /// </summary> |
368 | public void AdjustNumberOfScriptThreads() | 378 | public void AdjustNumberOfScriptThreads() |
369 | { | 379 | { |
380 | // Is there anything here for us to do? | ||
381 | if (eventQueueThreads.Count == numberOfThreads) | ||
382 | return; | ||
383 | |||
370 | lock (eventQueueThreadsLock) | 384 | lock (eventQueueThreadsLock) |
371 | { | 385 | { |
372 | int diff = numberOfThreads - eventQueueThreads.Count; | 386 | int diff = numberOfThreads - eventQueueThreads.Count; |
@@ -424,5 +438,15 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase | |||
424 | } | 438 | } |
425 | } | 439 | } |
426 | #endregion | 440 | #endregion |
441 | /// <summary> | ||
442 | /// If set to true then threads and stuff should try to make a graceful exit | ||
443 | /// </summary> | ||
444 | public bool PleaseShutdown | ||
445 | { | ||
446 | get { return _PleaseShutdown; } | ||
447 | set { _PleaseShutdown = value; } | ||
448 | } | ||
449 | private bool _PleaseShutdown = false; | ||
450 | |||
427 | } | 451 | } |
428 | } \ No newline at end of file | 452 | } \ No newline at end of file |
diff --git a/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/EventQueueThreadClass.cs b/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/EventQueueThreadClass.cs index e610c36..c19d641 100644 --- a/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/EventQueueThreadClass.cs +++ b/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/EventQueueThreadClass.cs | |||
@@ -12,12 +12,13 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase | |||
12 | /// <summary> | 12 | /// <summary> |
13 | /// Because every thread needs some data set for it (time started to execute current function), it will do its work within a class | 13 | /// Because every thread needs some data set for it (time started to execute current function), it will do its work within a class |
14 | /// </summary> | 14 | /// </summary> |
15 | public class EventQueueThreadClass | 15 | public class EventQueueThreadClass: iScriptEngineFunctionModule |
16 | { | 16 | { |
17 | /// <summary> | 17 | /// <summary> |
18 | /// How many ms to sleep if queue is empty | 18 | /// How many ms to sleep if queue is empty |
19 | /// </summary> | 19 | /// </summary> |
20 | private int nothingToDoSleepms;// = 50; | 20 | private int nothingToDoSleepms;// = 50; |
21 | private ThreadPriority MyThreadPriority; | ||
21 | 22 | ||
22 | public long LastExecutionStarted; | 23 | public long LastExecutionStarted; |
23 | public bool InExecution = false; | 24 | public bool InExecution = false; |
@@ -26,25 +27,27 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase | |||
26 | private EventQueueManager eventQueueManager; | 27 | private EventQueueManager eventQueueManager; |
27 | public Thread EventQueueThread; | 28 | public Thread EventQueueThread; |
28 | private static int ThreadCount = 0; | 29 | private static int ThreadCount = 0; |
29 | private ThreadPriority MyThreadPriority; | 30 | |
31 | private string ScriptEngineName = "ScriptEngine.Common"; | ||
30 | 32 | ||
31 | public EventQueueThreadClass(EventQueueManager eqm) | 33 | public EventQueueThreadClass(EventQueueManager eqm) |
32 | { | 34 | { |
33 | eventQueueManager = eqm; | 35 | eventQueueManager = eqm; |
34 | nothingToDoSleepms = eqm.m_ScriptEngine.ScriptConfigSource.GetInt("SleepTimeIfNoScriptExecutionMs", 50); | 36 | ReadConfig(); |
35 | Start(); | 37 | Start(); |
36 | } | 38 | } |
37 | 39 | ||
38 | ~EventQueueThreadClass() | 40 | ~EventQueueThreadClass() |
39 | { | 41 | { |
40 | Shutdown(); | 42 | Stop(); |
41 | } | 43 | } |
42 | 44 | ||
43 | /// <summary> | 45 | |
44 | /// Start thread | 46 | public void ReadConfig() |
45 | /// </summary> | ||
46 | private void Start() | ||
47 | { | 47 | { |
48 | ScriptEngineName = eventQueueManager.m_ScriptEngine.ScriptEngineName; | ||
49 | nothingToDoSleepms = eventQueueManager.m_ScriptEngine.ScriptConfigSource.GetInt("SleepTimeIfNoScriptExecutionMs", 50); | ||
50 | |||
48 | // Later with ScriptServer we might want to ask OS for stuff too, so doing this a bit manually | 51 | // Later with ScriptServer we might want to ask OS for stuff too, so doing this a bit manually |
49 | string pri = eventQueueManager.m_ScriptEngine.ScriptConfigSource.GetString("ScriptThreadPriority", "BelowNormal"); | 52 | string pri = eventQueueManager.m_ScriptEngine.ScriptConfigSource.GetString("ScriptThreadPriority", "BelowNormal"); |
50 | switch (pri.ToLower()) | 53 | switch (pri.ToLower()) |
@@ -70,6 +73,19 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase | |||
70 | break; | 73 | break; |
71 | } | 74 | } |
72 | 75 | ||
76 | // Now set that priority | ||
77 | if (EventQueueThread != null) | ||
78 | if (EventQueueThread.IsAlive) | ||
79 | EventQueueThread.Priority = MyThreadPriority; | ||
80 | |||
81 | } | ||
82 | |||
83 | |||
84 | /// <summary> | ||
85 | /// Start thread | ||
86 | /// </summary> | ||
87 | private void Start() | ||
88 | { | ||
73 | 89 | ||
74 | EventQueueThread = new Thread(EventQueueThreadLoop); | 90 | EventQueueThread = new Thread(EventQueueThreadLoop); |
75 | EventQueueThread.IsBackground = true; | 91 | EventQueueThread.IsBackground = true; |
@@ -84,18 +100,20 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase | |||
84 | ThreadCount++; | 100 | ThreadCount++; |
85 | } | 101 | } |
86 | 102 | ||
87 | public void Shutdown() | 103 | public void Stop() |
88 | { | 104 | { |
105 | PleaseShutdown = true; // Set shutdown flag | ||
106 | Thread.Sleep(100); // Wait a bit | ||
89 | if (EventQueueThread != null && EventQueueThread.IsAlive == true) | 107 | if (EventQueueThread != null && EventQueueThread.IsAlive == true) |
90 | { | 108 | { |
91 | try | 109 | try |
92 | { | 110 | { |
93 | EventQueueThread.Abort(); | 111 | EventQueueThread.Abort(); // Send abort |
94 | EventQueueThread.Join(); | 112 | EventQueueThread.Join(); // Wait for it |
95 | } | 113 | } |
96 | catch (Exception) | 114 | catch (Exception) |
97 | { | 115 | { |
98 | //myScriptEngine.Log.Verbose("ScriptEngine", "EventQueueManager Exception killing worker thread: " + e.ToString()); | 116 | //myScriptEngine.Log.Verbose(ScriptEngineName, "EventQueueManager Exception killing worker thread: " + e.ToString()); |
99 | } | 117 | } |
100 | } | 118 | } |
101 | } | 119 | } |
@@ -106,10 +124,10 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase | |||
106 | /// </summary> | 124 | /// </summary> |
107 | private void EventQueueThreadLoop() | 125 | private void EventQueueThreadLoop() |
108 | { | 126 | { |
109 | //myScriptEngine.m_logger.Verbose("ScriptEngine", "EventQueueManager Worker thread spawned"); | 127 | //myScriptEngine.m_logger.Verbose(ScriptEngineName, "EventQueueManager Worker thread spawned"); |
110 | try | 128 | try |
111 | { | 129 | { |
112 | while (true) | 130 | while (true) |
113 | { | 131 | { |
114 | try | 132 | try |
115 | { | 133 | { |
@@ -117,7 +135,7 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase | |||
117 | while (true) | 135 | while (true) |
118 | { | 136 | { |
119 | // Every now and then check if we should shut down | 137 | // Every now and then check if we should shut down |
120 | if (eventQueueManager.ThreadsToExit > 0) | 138 | if (PleaseShutdown || eventQueueManager.ThreadsToExit > 0) |
121 | { | 139 | { |
122 | // Someone should shut down, lets get exclusive lock | 140 | // Someone should shut down, lets get exclusive lock |
123 | lock (eventQueueManager.ThreadsToExitLock) | 141 | lock (eventQueueManager.ThreadsToExitLock) |
@@ -125,9 +143,15 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase | |||
125 | // Lets re-check in case someone grabbed it | 143 | // Lets re-check in case someone grabbed it |
126 | if (eventQueueManager.ThreadsToExit > 0) | 144 | if (eventQueueManager.ThreadsToExit > 0) |
127 | { | 145 | { |
128 | // We are go for shutdown | 146 | // Its crowded here so we'll shut down |
129 | eventQueueManager.ThreadsToExit--; | 147 | eventQueueManager.ThreadsToExit--; |
130 | Shutdown(); | 148 | Stop(); |
149 | return; | ||
150 | } | ||
151 | else | ||
152 | { | ||
153 | // We have been asked to shut down | ||
154 | Stop(); | ||
131 | return; | 155 | return; |
132 | } | 156 | } |
133 | } | 157 | } |
@@ -139,6 +163,9 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase | |||
139 | EventQueueManager.QueueItemStruct QIS = BlankQIS; | 163 | EventQueueManager.QueueItemStruct QIS = BlankQIS; |
140 | bool GotItem = false; | 164 | bool GotItem = false; |
141 | 165 | ||
166 | if (PleaseShutdown) | ||
167 | return; | ||
168 | |||
142 | if (eventQueueManager.eventQueue.Count == 0) | 169 | if (eventQueueManager.eventQueue.Count == 0) |
143 | { | 170 | { |
144 | // Nothing to do? Sleep a bit waiting for something to do | 171 | // Nothing to do? Sleep a bit waiting for something to do |
@@ -147,7 +174,7 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase | |||
147 | else | 174 | else |
148 | { | 175 | { |
149 | // Something in queue, process | 176 | // Something in queue, process |
150 | //myScriptEngine.m_logger.Verbose("ScriptEngine", "Processing event for localID: " + QIS.localID + ", itemID: " + QIS.itemID + ", FunctionName: " + QIS.FunctionName); | 177 | //myScriptEngine.m_logger.Verbose(ScriptEngineName, "Processing event for localID: " + QIS.localID + ", itemID: " + QIS.itemID + ", FunctionName: " + QIS.FunctionName); |
151 | 178 | ||
152 | // OBJECT BASED LOCK - TWO THREADS WORKING ON SAME OBJECT IS NOT GOOD | 179 | // OBJECT BASED LOCK - TWO THREADS WORKING ON SAME OBJECT IS NOT GOOD |
153 | lock (eventQueueManager.queueLock) | 180 | lock (eventQueueManager.queueLock) |
@@ -179,7 +206,7 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase | |||
179 | try | 206 | try |
180 | { | 207 | { |
181 | #if DEBUG | 208 | #if DEBUG |
182 | eventQueueManager.m_ScriptEngine.Log.Debug("ScriptEngine", | 209 | eventQueueManager.m_ScriptEngine.Log.Debug(ScriptEngineName, |
183 | "Executing event:\r\n" | 210 | "Executing event:\r\n" |
184 | + "QIS.localID: " + QIS.localID | 211 | + "QIS.localID: " + QIS.localID |
185 | + ", QIS.itemID: " + QIS.itemID | 212 | + ", QIS.itemID: " + QIS.itemID |
@@ -235,7 +262,7 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase | |||
235 | //else | 262 | //else |
236 | //{ | 263 | //{ |
237 | // T oconsole | 264 | // T oconsole |
238 | eventQueueManager.m_ScriptEngine.Log.Error("ScriptEngine", | 265 | eventQueueManager.m_ScriptEngine.Log.Error(ScriptEngineName, |
239 | "Unable to send text in-world:\r\n" + | 266 | "Unable to send text in-world:\r\n" + |
240 | text); | 267 | text); |
241 | } | 268 | } |
@@ -260,19 +287,28 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase | |||
260 | } | 287 | } |
261 | catch (ThreadAbortException tae) | 288 | catch (ThreadAbortException tae) |
262 | { | 289 | { |
263 | eventQueueManager.m_ScriptEngine.Log.Notice("ScriptEngine", "ThreadAbortException while executing function."); | 290 | eventQueueManager.m_ScriptEngine.Log.Notice(ScriptEngineName, "ThreadAbortException while executing function."); |
264 | } | 291 | } |
265 | catch (Exception e) | 292 | catch (Exception e) |
266 | { | 293 | { |
267 | eventQueueManager.m_ScriptEngine.Log.Error("ScriptEngine", "Exception in EventQueueThreadLoop: " + e.ToString()); | 294 | eventQueueManager.m_ScriptEngine.Log.Error(ScriptEngineName, "Exception in EventQueueThreadLoop: " + e.ToString()); |
268 | } | 295 | } |
269 | } // while | 296 | } // while |
270 | } // try | 297 | } // try |
271 | catch (ThreadAbortException) | 298 | catch (ThreadAbortException) |
272 | { | 299 | { |
273 | //myScriptEngine.Log.Verbose("ScriptEngine", "EventQueueManager Worker thread killed: " + tae.Message); | 300 | //myScriptEngine.Log.Verbose(ScriptEngineName, "EventQueueManager Worker thread killed: " + tae.Message); |
274 | } | 301 | } |
275 | } | 302 | } |
276 | 303 | ||
304 | /// <summary> | ||
305 | /// If set to true then threads and stuff should try to make a graceful exit | ||
306 | /// </summary> | ||
307 | public bool PleaseShutdown | ||
308 | { | ||
309 | get { return _PleaseShutdown; } | ||
310 | set { _PleaseShutdown = value; } | ||
311 | } | ||
312 | private bool _PleaseShutdown = false; | ||
277 | } | 313 | } |
278 | } | 314 | } |
diff --git a/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/MaintenanceThread.cs b/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/MaintenanceThread.cs index 9536291..105d47f 100644 --- a/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/MaintenanceThread.cs +++ b/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/MaintenanceThread.cs | |||
@@ -8,7 +8,7 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase | |||
8 | /// <summary> | 8 | /// <summary> |
9 | /// This class does maintenance on script engine. | 9 | /// This class does maintenance on script engine. |
10 | /// </summary> | 10 | /// </summary> |
11 | public class MaintenanceThread | 11 | public class MaintenanceThread : iScriptEngineFunctionModule |
12 | { | 12 | { |
13 | public ScriptEngine m_ScriptEngine; | 13 | public ScriptEngine m_ScriptEngine; |
14 | private int MaintenanceLoopms; | 14 | private int MaintenanceLoopms; |
@@ -28,7 +28,7 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase | |||
28 | StopMaintenanceThread(); | 28 | StopMaintenanceThread(); |
29 | } | 29 | } |
30 | 30 | ||
31 | private void ReadConfig() | 31 | public void ReadConfig() |
32 | { | 32 | { |
33 | MaintenanceLoopms = m_ScriptEngine.ScriptConfigSource.GetInt("MaintenanceLoopms", 50); | 33 | MaintenanceLoopms = m_ScriptEngine.ScriptConfigSource.GetInt("MaintenanceLoopms", 50); |
34 | } | 34 | } |
@@ -80,48 +80,74 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase | |||
80 | /// </summary> | 80 | /// </summary> |
81 | public void MaintenanceLoop() | 81 | public void MaintenanceLoop() |
82 | { | 82 | { |
83 | try | 83 | if (m_ScriptEngine.m_EventQueueManager.maxFunctionExecutionTimens < MaintenanceLoopms) |
84 | m_ScriptEngine.Log.Warn(m_ScriptEngine.ScriptEngineName, | ||
85 | "Configuration error: MaxEventExecutionTimeMs is less than MaintenanceLoopms. The Maintenance Loop will only check scripts once per run."); | ||
86 | |||
87 | while (true) | ||
84 | { | 88 | { |
85 | long Last_maxFunctionExecutionTimens = 0;// DateTime.Now.Ticks; | 89 | try |
86 | long Last_ReReadConfigFilens = DateTime.Now.Ticks; | ||
87 | while (true) | ||
88 | { | 90 | { |
89 | System.Threading.Thread.Sleep(MaintenanceLoopms); // Sleep | 91 | long Last_maxFunctionExecutionTimens = 0; // DateTime.Now.Ticks; |
90 | 92 | long Last_ReReadConfigFilens = DateTime.Now.Ticks; | |
91 | // Re-reading config every x seconds? | 93 | while (true) |
92 | if (m_ScriptEngine.ReReadConfigFileSeconds > 0) | ||
93 | { | 94 | { |
94 | // Check if its time to re-read config | 95 | System.Threading.Thread.Sleep(MaintenanceLoopms); // Sleep before next pass |
95 | if (DateTime.Now.Ticks - Last_ReReadConfigFilens > m_ScriptEngine.ReReadConfigFilens) | 96 | if (PleaseShutdown) |
97 | return; | ||
98 | // | ||
99 | // Re-reading config every x seconds | ||
100 | // | ||
101 | if (m_ScriptEngine.RefreshConfigFileSeconds > 0) | ||
96 | { | 102 | { |
97 | // Its time to re-read config file | 103 | // Check if its time to re-read config |
98 | m_ScriptEngine.ConfigSource.Reload(); // Re-read config | 104 | if (DateTime.Now.Ticks - Last_ReReadConfigFilens > m_ScriptEngine.RefreshConfigFilens) |
99 | Last_ReReadConfigFilens = DateTime.Now.Ticks; // Reset time | 105 | { |
106 | // Its time to re-read config file | ||
107 | m_ScriptEngine.ConfigSource.Reload(); // Refresh config | ||
108 | m_ScriptEngine.ReadConfig(); | ||
109 | Last_ReReadConfigFilens = DateTime.Now.Ticks; // Reset time | ||
110 | } | ||
100 | } | 111 | } |
101 | } | ||
102 | 112 | ||
103 | // Adjust number of running script threads if not correct | 113 | // |
104 | if (m_ScriptEngine.m_EventQueueManager.eventQueueThreads.Count != m_ScriptEngine.m_EventQueueManager.numberOfThreads) | 114 | // Adjust number of running script threads if not correct |
105 | { | 115 | // |
106 | m_ScriptEngine.m_EventQueueManager.AdjustNumberOfScriptThreads(); | 116 | m_ScriptEngine.m_EventQueueManager.AdjustNumberOfScriptThreads(); |
107 | } | ||
108 | |||
109 | 117 | ||
110 | // Check if any script has exceeded its max execution time | 118 | // |
111 | if (m_ScriptEngine.m_EventQueueManager.EnforceMaxExecutionTime) | 119 | // Check if any script has exceeded its max execution time |
112 | { | 120 | // |
113 | if (DateTime.Now.Ticks - Last_maxFunctionExecutionTimens > m_ScriptEngine.m_EventQueueManager.maxFunctionExecutionTimens) | 121 | if (m_ScriptEngine.m_EventQueueManager.EnforceMaxExecutionTime) |
114 | { | 122 | { |
115 | m_ScriptEngine.m_EventQueueManager.CheckScriptMaxExecTime(); // Do check | 123 | // We are enforcing execution time |
116 | Last_maxFunctionExecutionTimens = DateTime.Now.Ticks; // Reset time | 124 | if (DateTime.Now.Ticks - Last_maxFunctionExecutionTimens > |
125 | m_ScriptEngine.m_EventQueueManager.maxFunctionExecutionTimens) | ||
126 | { | ||
127 | // Its time to check again | ||
128 | m_ScriptEngine.m_EventQueueManager.CheckScriptMaxExecTime(); // Do check | ||
129 | Last_maxFunctionExecutionTimens = DateTime.Now.Ticks; // Reset time | ||
130 | } | ||
117 | } | 131 | } |
118 | } | 132 | } |
119 | } | 133 | } |
120 | } | 134 | catch (Exception ex) |
121 | catch (ThreadAbortException tae) | 135 | { |
122 | { | 136 | m_ScriptEngine.Log.Error(m_ScriptEngine.ScriptEngineName, "Exception in MaintenanceLoopThread. Thread will recover after 5 sec throttle. Exception: " + ex.ToString()); |
137 | Thread.Sleep(5000); | ||
138 | } | ||
123 | } | 139 | } |
124 | } | 140 | } |
125 | #endregion | 141 | #endregion |
142 | /// <summary> | ||
143 | /// If set to true then threads and stuff should try to make a graceful exit | ||
144 | /// </summary> | ||
145 | public bool PleaseShutdown | ||
146 | { | ||
147 | get { return _PleaseShutdown; } | ||
148 | set { _PleaseShutdown = value; } | ||
149 | } | ||
150 | private bool _PleaseShutdown = false; | ||
151 | |||
126 | } | 152 | } |
127 | } | 153 | } |
diff --git a/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/ScriptEngine.cs b/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/ScriptEngine.cs index cfcc36e..c237282 100644 --- a/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/ScriptEngine.cs +++ b/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/ScriptEngine.cs | |||
@@ -42,27 +42,28 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase | |||
42 | /// </summary> | 42 | /// </summary> |
43 | /// | 43 | /// |
44 | [Serializable] | 44 | [Serializable] |
45 | public abstract class ScriptEngine : IRegionModule, OpenSim.Region.ScriptEngine.Common.ScriptServerInterfaces.ScriptEngine | 45 | public abstract class ScriptEngine : IRegionModule, OpenSim.Region.ScriptEngine.Common.ScriptServerInterfaces.ScriptEngine, iScriptEngineFunctionModule |
46 | { | 46 | { |
47 | public Scene World; | 47 | public Scene World; |
48 | public EventManager m_EventManager; // Handles and queues incoming events from OpenSim | 48 | public EventManager m_EventManager; // Handles and queues incoming events from OpenSim |
49 | public EventQueueManager m_EventQueueManager; // Executes events | 49 | public EventQueueManager m_EventQueueManager; // Executes events, handles script threads |
50 | public ScriptManager m_ScriptManager; // Load, unload and execute scripts | 50 | public ScriptManager m_ScriptManager; // Load, unload and execute scripts |
51 | public AppDomainManager m_AppDomainManager; | 51 | public AppDomainManager m_AppDomainManager; // Handles loading/unloading of scripts into AppDomains |
52 | public LSLLongCmdHandler m_LSLLongCmdHandler; | 52 | public AsyncLSLCommandManager m_ASYNCLSLCommandManager; // Asyncronous LSL commands (commands that returns with an event) |
53 | public MaintenanceThread m_MaintenanceThread; // Thread that does different kinds of maintenance, for example refreshing config and killing scripts that has been running too long | ||
53 | 54 | ||
54 | public IConfigSource ConfigSource; | 55 | public IConfigSource ConfigSource; |
55 | public IConfig ScriptConfigSource; | 56 | public IConfig ScriptConfigSource; |
56 | public abstract string ScriptConfigSourceName { get; } | 57 | public abstract string ScriptEngineName { get; } |
57 | 58 | ||
58 | /// <summary> | 59 | /// <summary> |
59 | /// How many seconds between re-reading config-file. 0 = never. ScriptEngine will try to adjust to new config changes. | 60 | /// How many seconds between re-reading config-file. 0 = never. ScriptEngine will try to adjust to new config changes. |
60 | /// </summary> | 61 | /// </summary> |
61 | public int ReReadConfigFileSeconds { | 62 | public int RefreshConfigFileSeconds { |
62 | get { return (int)(ReReadConfigFilens / 10000); } | 63 | get { return (int)(RefreshConfigFilens / 10000); } |
63 | set { ReReadConfigFilens = value * 10000; } | 64 | set { RefreshConfigFilens = value * 10000; } |
64 | } | 65 | } |
65 | public long ReReadConfigFilens = 0; | 66 | public long RefreshConfigFilens = 0; |
66 | 67 | ||
67 | public ScriptManager GetScriptManager() | 68 | public ScriptManager GetScriptManager() |
68 | { | 69 | { |
@@ -88,21 +89,22 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase | |||
88 | { | 89 | { |
89 | World = Sceneworld; | 90 | World = Sceneworld; |
90 | m_log = logger; | 91 | m_log = logger; |
91 | ScriptConfigSource = ConfigSource.Configs[ScriptConfigSourceName]; | 92 | ScriptConfigSource = ConfigSource.Configs[ScriptEngineName]; |
92 | 93 | ||
93 | Log.Verbose("ScriptEngine", "DotNet & LSL ScriptEngine initializing"); | 94 | Log.Verbose(ScriptEngineName, "DotNet & LSL ScriptEngine initializing"); |
94 | 95 | ||
95 | //m_logger.Status("ScriptEngine", "InitializeEngine"); | 96 | //m_logger.Status(ScriptEngineName, "InitializeEngine"); |
96 | 97 | ||
97 | // Create all objects we'll be using | 98 | // Create all objects we'll be using |
98 | m_EventQueueManager = new EventQueueManager(this); | 99 | m_EventQueueManager = new EventQueueManager(this); |
99 | m_EventManager = new EventManager(this, HookUpToServer); | 100 | m_EventManager = new EventManager(this, HookUpToServer); |
100 | m_ScriptManager = newScriptManager; | 101 | m_ScriptManager = newScriptManager; |
101 | //m_ScriptManager = new ScriptManager(this); | 102 | m_AppDomainManager = new AppDomainManager(this); |
102 | m_AppDomainManager = new AppDomainManager(ScriptConfigSource.GetInt("ScriptsPerAppDomain", 1)); | 103 | m_ASYNCLSLCommandManager = new AsyncLSLCommandManager(this); |
103 | m_LSLLongCmdHandler = new LSLLongCmdHandler(this); | 104 | m_MaintenanceThread = new MaintenanceThread(this); |
105 | |||
106 | ReadConfig(); | ||
104 | 107 | ||
105 | ReReadConfigFileSeconds = ScriptConfigSource.GetInt("ReReadConfig", 0); | ||
106 | 108 | ||
107 | 109 | ||
108 | // Should we iterate the region for scripts that needs starting? | 110 | // Should we iterate the region for scripts that needs starting? |
@@ -118,6 +120,26 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase | |||
118 | { | 120 | { |
119 | return this.m_EventManager; | 121 | return this.m_EventManager; |
120 | } | 122 | } |
123 | public void ReadConfig() | ||
124 | { | ||
125 | #if DEBUG | ||
126 | Log.Debug(ScriptEngineName, "Refreshing configuration for all modules"); | ||
127 | #endif | ||
128 | RefreshConfigFileSeconds = ScriptConfigSource.GetInt("RefreshConfig", 0); | ||
129 | |||
130 | // Reload from disk | ||
131 | ConfigSource.Reload(); | ||
132 | // Create a new object (probably not necessary?) | ||
133 | // ScriptConfigSource = ConfigSource.Configs[ScriptEngineName]; | ||
134 | |||
135 | if (m_EventQueueManager != null) m_EventQueueManager.ReadConfig(); | ||
136 | if (m_EventManager != null) m_EventManager.ReadConfig(); | ||
137 | if (m_ScriptManager != null) m_ScriptManager.ReadConfig(); | ||
138 | if (m_AppDomainManager != null) m_AppDomainManager.ReadConfig(); | ||
139 | if (m_ASYNCLSLCommandManager != null) m_ASYNCLSLCommandManager.ReadConfig(); | ||
140 | if (m_MaintenanceThread != null) m_MaintenanceThread.ReadConfig(); | ||
141 | |||
142 | } | ||
121 | 143 | ||
122 | 144 | ||
123 | #region IRegionModule | 145 | #region IRegionModule |
@@ -134,7 +156,7 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase | |||
134 | 156 | ||
135 | public string Name | 157 | public string Name |
136 | { | 158 | { |
137 | get { return "DotNetEngine"; } | 159 | get { return "Common." + ScriptEngineName; } |
138 | } | 160 | } |
139 | 161 | ||
140 | public bool IsSharedModule | 162 | public bool IsSharedModule |
@@ -146,5 +168,15 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase | |||
146 | 168 | ||
147 | #endregion | 169 | #endregion |
148 | 170 | ||
171 | /// <summary> | ||
172 | /// If set to true then threads and stuff should try to make a graceful exit | ||
173 | /// </summary> | ||
174 | public bool PleaseShutdown | ||
175 | { | ||
176 | get { return _PleaseShutdown; } | ||
177 | set { _PleaseShutdown = value; } | ||
178 | } | ||
179 | private bool _PleaseShutdown = false; | ||
180 | |||
149 | } | 181 | } |
150 | } \ No newline at end of file | 182 | } \ No newline at end of file |
diff --git a/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/ScriptManager.cs b/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/ScriptManager.cs index ea87581..45cfced 100644 --- a/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/ScriptManager.cs +++ b/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/ScriptManager.cs | |||
@@ -57,12 +57,12 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase | |||
57 | // This so that scripts starting or stopping will not slow down other theads or whole system. | 57 | // This so that scripts starting or stopping will not slow down other theads or whole system. |
58 | // | 58 | // |
59 | [Serializable] | 59 | [Serializable] |
60 | public abstract class ScriptManager | 60 | public abstract class ScriptManager : iScriptEngineFunctionModule |
61 | { | 61 | { |
62 | #region Declares | 62 | #region Declares |
63 | 63 | ||
64 | private Thread scriptLoadUnloadThread; | 64 | private Thread scriptLoadUnloadThread; |
65 | private int scriptLoadUnloadThread_IdleSleepms = 100; | 65 | private int scriptLoadUnloadThread_IdleSleepms; |
66 | private Queue<LUStruct> LUQueue = new Queue<LUStruct>(); | 66 | private Queue<LUStruct> LUQueue = new Queue<LUStruct>(); |
67 | 67 | ||
68 | 68 | ||
@@ -95,6 +95,11 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase | |||
95 | 95 | ||
96 | #endregion | 96 | #endregion |
97 | 97 | ||
98 | public void ReadConfig() | ||
99 | { | ||
100 | scriptLoadUnloadThread_IdleSleepms = m_scriptEngine.ScriptConfigSource.GetInt("ScriptLoadUnloadLoopms", 30); | ||
101 | } | ||
102 | |||
98 | #region Object init/shutdown | 103 | #region Object init/shutdown |
99 | 104 | ||
100 | public ScriptEngineBase.ScriptEngine m_scriptEngine; | 105 | public ScriptEngineBase.ScriptEngine m_scriptEngine; |
@@ -102,6 +107,7 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase | |||
102 | public ScriptManager(ScriptEngineBase.ScriptEngine scriptEngine) | 107 | public ScriptManager(ScriptEngineBase.ScriptEngine scriptEngine) |
103 | { | 108 | { |
104 | m_scriptEngine = scriptEngine; | 109 | m_scriptEngine = scriptEngine; |
110 | ReadConfig(); | ||
105 | AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve); | 111 | AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve); |
106 | scriptLoadUnloadThread = new Thread(ScriptLoadUnloadThreadLoop); | 112 | scriptLoadUnloadThread = new Thread(ScriptLoadUnloadThreadLoop); |
107 | scriptLoadUnloadThread.Name = "ScriptLoadUnloadThread"; | 113 | scriptLoadUnloadThread.Name = "ScriptLoadUnloadThread"; |
@@ -238,7 +244,7 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase | |||
238 | Console.WriteLine("ScriptEngine: Inside ExecuteEvent for event " + FunctionName); | 244 | Console.WriteLine("ScriptEngine: Inside ExecuteEvent for event " + FunctionName); |
239 | #endif | 245 | #endif |
240 | // Execute a function in the script | 246 | // Execute a function in the script |
241 | //m_scriptEngine.Log.Verbose("ScriptEngine", "Executing Function localID: " + localID + ", itemID: " + itemID + ", FunctionName: " + FunctionName); | 247 | //m_scriptEngine.Log.Verbose(ScriptEngineName, "Executing Function localID: " + localID + ", itemID: " + itemID + ", FunctionName: " + FunctionName); |
242 | //ScriptBaseInterface Script = (ScriptBaseInterface)GetScript(localID, itemID); | 248 | //ScriptBaseInterface Script = (ScriptBaseInterface)GetScript(localID, itemID); |
243 | IScript Script = GetScript(localID, itemID); | 249 | IScript Script = GetScript(localID, itemID); |
244 | if (Script == null) | 250 | if (Script == null) |
@@ -345,5 +351,16 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase | |||
345 | } | 351 | } |
346 | 352 | ||
347 | #endregion | 353 | #endregion |
354 | |||
355 | /// <summary> | ||
356 | /// If set to true then threads and stuff should try to make a graceful exit | ||
357 | /// </summary> | ||
358 | public bool PleaseShutdown | ||
359 | { | ||
360 | get { return _PleaseShutdown; } | ||
361 | set { _PleaseShutdown = value; } | ||
362 | } | ||
363 | private bool _PleaseShutdown = false; | ||
364 | |||
348 | } | 365 | } |
349 | } \ No newline at end of file | 366 | } \ No newline at end of file |
diff --git a/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/iScriptEngineFunctionModule.cs b/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/iScriptEngineFunctionModule.cs new file mode 100644 index 0000000..7539074 --- /dev/null +++ b/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/iScriptEngineFunctionModule.cs | |||
@@ -0,0 +1,12 @@ | |||
1 | using System; | ||
2 | using System.Collections.Generic; | ||
3 | using System.Text; | ||
4 | |||
5 | namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase | ||
6 | { | ||
7 | public interface iScriptEngineFunctionModule | ||
8 | { | ||
9 | void ReadConfig(); | ||
10 | bool PleaseShutdown { get; set; } | ||
11 | } | ||
12 | } \ No newline at end of file | ||
diff --git a/OpenSim/Region/ScriptEngine/DotNetEngine/ScriptEngine.cs b/OpenSim/Region/ScriptEngine/DotNetEngine/ScriptEngine.cs index de168b7..5ba37f7 100644 --- a/OpenSim/Region/ScriptEngine/DotNetEngine/ScriptEngine.cs +++ b/OpenSim/Region/ScriptEngine/DotNetEngine/ScriptEngine.cs | |||
@@ -48,7 +48,7 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine | |||
48 | return new ScriptManager(this); | 48 | return new ScriptManager(this); |
49 | } | 49 | } |
50 | 50 | ||
51 | public override string ScriptConfigSourceName | 51 | public override string ScriptEngineName |
52 | { | 52 | { |
53 | get { return "ScriptEngine.DotNetEngine"; } | 53 | get { return "ScriptEngine.DotNetEngine"; } |
54 | } | 54 | } |
diff --git a/OpenSim/Region/ScriptEngine/DotNetEngine/ScriptManager.cs b/OpenSim/Region/ScriptEngine/DotNetEngine/ScriptManager.cs index 5e1b537..9cad388 100644 --- a/OpenSim/Region/ScriptEngine/DotNetEngine/ScriptManager.cs +++ b/OpenSim/Region/ScriptEngine/DotNetEngine/ScriptManager.cs | |||
@@ -124,7 +124,7 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine | |||
124 | 124 | ||
125 | 125 | ||
126 | // Stop long command on script | 126 | // Stop long command on script |
127 | m_scriptEngine.m_LSLLongCmdHandler.RemoveScript(localID, itemID); | 127 | m_scriptEngine.m_ASYNCLSLCommandManager.RemoveScript(localID, itemID); |
128 | 128 | ||
129 | IScript LSLBC = GetScript(localID, itemID); | 129 | IScript LSLBC = GetScript(localID, itemID); |
130 | if (LSLBC == null) | 130 | if (LSLBC == null) |
diff --git a/OpenSim/Region/ScriptEngine/LSOEngine/ScriptEngine.cs b/OpenSim/Region/ScriptEngine/LSOEngine/ScriptEngine.cs index aac210b..49727c2 100644 --- a/OpenSim/Region/ScriptEngine/LSOEngine/ScriptEngine.cs +++ b/OpenSim/Region/ScriptEngine/LSOEngine/ScriptEngine.cs | |||
@@ -52,7 +52,7 @@ namespace OpenSim.Region.ScriptEngine.LSOEngine | |||
52 | return new ScriptManager(this); | 52 | return new ScriptManager(this); |
53 | } | 53 | } |
54 | 54 | ||
55 | public override string ScriptConfigSourceName | 55 | public override string ScriptEngineName |
56 | { | 56 | { |
57 | get { return "ScriptEngine.LSOEngine"; } | 57 | get { return "ScriptEngine.LSOEngine"; } |
58 | } | 58 | } |
diff --git a/OpenSim/Region/ScriptEngine/LSOEngine/ScriptManager.cs b/OpenSim/Region/ScriptEngine/LSOEngine/ScriptManager.cs index de7b466..6664025 100644 --- a/OpenSim/Region/ScriptEngine/LSOEngine/ScriptManager.cs +++ b/OpenSim/Region/ScriptEngine/LSOEngine/ScriptManager.cs | |||
@@ -127,7 +127,7 @@ namespace OpenSim.Region.ScriptEngine.LSOEngine | |||
127 | 127 | ||
128 | 128 | ||
129 | // Stop long command on script | 129 | // Stop long command on script |
130 | m_scriptEngine.m_LSLLongCmdHandler.RemoveScript(localID, itemID); | 130 | m_scriptEngine.m_ASYNCLSLCommandManager.RemoveScript(localID, itemID); |
131 | 131 | ||
132 | IScript LSLBC = GetScript(localID, itemID); | 132 | IScript LSLBC = GetScript(localID, itemID); |
133 | if (LSLBC == null) | 133 | if (LSLBC == null) |
diff --git a/bin/OpenSim.ini.example b/bin/OpenSim.ini.example index 9d664bf..94bacd1 100644 --- a/bin/OpenSim.ini.example +++ b/bin/OpenSim.ini.example | |||
@@ -123,6 +123,13 @@ shout_distance = 100 | |||
123 | ; Same if you have 10 threads, then only 10 scripts can be run simultaneously. | 123 | ; Same if you have 10 threads, then only 10 scripts can be run simultaneously. |
124 | ; But because most scripts exit after their task, the threads are free to go on to the next script. | 124 | ; But because most scripts exit after their task, the threads are free to go on to the next script. |
125 | 125 | ||
126 | ; Refresh ScriptEngine config options (these settings) every xx seconds | ||
127 | ; 0 = Do not refresh | ||
128 | ; Set it to number of seconds between refresh, for example 30. | ||
129 | ; Will allow you to change ScriptEngine settings while server is running just by editing this file. | ||
130 | ; For example to increase or decrease number of threads. | ||
131 | RefreshConfig=0 | ||
132 | |||
126 | ; Number of threads to use for script event execution | 133 | ; Number of threads to use for script event execution |
127 | ; Threads are shared across all regions | 134 | ; Threads are shared across all regions |
128 | NumberOfScriptThreads=2 | 135 | NumberOfScriptThreads=2 |
@@ -136,6 +143,7 @@ ScriptThreadPriority=BelowNormal | |||
136 | ; Number of threads will be <NumberOfScriptThreads>*<NumberOfRegions> | 143 | ; Number of threads will be <NumberOfScriptThreads>*<NumberOfRegions> |
137 | ; false: All regions share <NumberOfScriptThreads> for all their scripts | 144 | ; false: All regions share <NumberOfScriptThreads> for all their scripts |
138 | ; Note! If you run multiple script engines based on "OpenSim.Region.ScriptEngine.Common" then all of them will share the same threads. | 145 | ; Note! If you run multiple script engines based on "OpenSim.Region.ScriptEngine.Common" then all of them will share the same threads. |
146 | ; *** This setting will not work until you restart OpenSim | ||
139 | PrivateRegionThreads=false | 147 | PrivateRegionThreads=false |
140 | 148 | ||
141 | ; How long MAX should a script event be allowed to run (per event execution)? | 149 | ; How long MAX should a script event be allowed to run (per event execution)? |
@@ -164,5 +172,14 @@ SleepTimeIfNoScriptExecutionMs=50 | |||
164 | ; Each AppDomain has some memory overhead. But leaving dead scripts in memory also has memory overhead. | 172 | ; Each AppDomain has some memory overhead. But leaving dead scripts in memory also has memory overhead. |
165 | ScriptsPerAppDomain=1 | 173 | ScriptsPerAppDomain=1 |
166 | 174 | ||
167 | ; ReRead ScriptEngine config options how often? | 175 | ; Script loading / unloading sleep |
168 | ReReadConfig=0 | 176 | ; How long load/unload thread should sleep if there is nothing to do |
177 | ; Higher value makes it respond slower when scripts are added/removed from prims | ||
178 | ; But once active it will process all in queue before sleeping again | ||
179 | ScriptLoadUnloadLoopms=30 | ||
180 | |||
181 | ; Async LL command sleep | ||
182 | ; If no async LL commands are waiting, how long should thread sleep before checking again | ||
183 | ; Async LL commands are LSL-commands that causes an event to be fired back with result | ||
184 | AsyncLLCommandLoopms=50 | ||
185 | |||