aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ScriptEngine/DotNetEngine/AppDomainManager.cs
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/DotNetEngine/AppDomainManager.cs
parent* Wind updates. Still random.. but in 4 directions instead of two! (diff)
downloadopensim-SC_OLD-824283ca3c2ab54868ed61fdb0a329221d69e5fa.zip
opensim-SC_OLD-824283ca3c2ab54868ed61fdb0a329221d69e5fa.tar.gz
opensim-SC_OLD-824283ca3c2ab54868ed61fdb0a329221d69e5fa.tar.bz2
opensim-SC_OLD-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/DotNetEngine/AppDomainManager.cs')
-rw-r--r--OpenSim/Region/ScriptEngine/DotNetEngine/AppDomainManager.cs254
1 files changed, 254 insertions, 0 deletions
diff --git a/OpenSim/Region/ScriptEngine/DotNetEngine/AppDomainManager.cs b/OpenSim/Region/ScriptEngine/DotNetEngine/AppDomainManager.cs
new file mode 100644
index 0000000..969a05e
--- /dev/null
+++ b/OpenSim/Region/ScriptEngine/DotNetEngine/AppDomainManager.cs
@@ -0,0 +1,254 @@
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;
32using OpenSim.Region.ScriptEngine.Common;
33
34namespace OpenSim.Region.ScriptEngine.DotNetEngine
35{
36 public class AppDomainManager : iScriptEngineFunctionModule
37 {
38 //
39 // This class does AppDomain handling and loading/unloading of scripts in it.
40 // It is instanced in "ScriptEngine" and controlled from "ScriptManager"
41 //
42 // 1. Create a new AppDomain if old one is full (or doesn't exist)
43 // 2. Load scripts into AppDomain
44 // 3. Unload scripts from AppDomain (stopping them and marking them as inactive)
45 // 4. Unload AppDomain completely when all scripts in it has stopped
46 //
47
48 private int maxScriptsPerAppDomain = 1;
49
50 /// <summary>
51 /// Internal list of all AppDomains
52 /// </summary>
53 private List<AppDomainStructure> appDomains = new List<AppDomainStructure>();
54
55 /// <summary>
56 /// Structure to keep track of data around AppDomain
57 /// </summary>
58 private class AppDomainStructure
59 {
60 /// <summary>
61 /// The AppDomain itself
62 /// </summary>
63 public AppDomain CurrentAppDomain;
64
65 /// <summary>
66 /// Number of scripts loaded into AppDomain
67 /// </summary>
68 public int ScriptsLoaded;
69
70 /// <summary>
71 /// Number of dead scripts
72 /// </summary>
73 public int ScriptsWaitingUnload;
74 }
75
76 /// <summary>
77 /// Current AppDomain
78 /// </summary>
79 private AppDomainStructure currentAD;
80
81 private object getLock = new object(); // Mutex
82 private object freeLock = new object(); // Mutex
83
84 private ScriptEngine m_scriptEngine;
85 //public AppDomainManager(ScriptEngine scriptEngine)
86 public AppDomainManager(ScriptEngine scriptEngine)
87 {
88 m_scriptEngine = scriptEngine;
89 ReadConfig();
90 }
91
92 public void ReadConfig()
93 {
94 maxScriptsPerAppDomain = m_scriptEngine.ScriptConfigSource.GetInt("ScriptsPerAppDomain", 1);
95 }
96
97 /// <summary>
98 /// Find a free AppDomain, creating one if necessary
99 /// </summary>
100 /// <returns>Free AppDomain</returns>
101 private AppDomainStructure GetFreeAppDomain()
102 {
103 // Console.WriteLine("Finding free AppDomain");
104 lock (getLock)
105 {
106 // Current full?
107 if (currentAD != null && currentAD.ScriptsLoaded >= maxScriptsPerAppDomain)
108 {
109 // Add it to AppDomains list and empty current
110 appDomains.Add(currentAD);
111 currentAD = null;
112 }
113 // No current
114 if (currentAD == null)
115 {
116 // Create a new current AppDomain
117 currentAD = new AppDomainStructure();
118 currentAD.CurrentAppDomain = PrepareNewAppDomain();
119 }
120
121 // Console.WriteLine("Scripts loaded in this Appdomain: " + currentAD.ScriptsLoaded);
122 return currentAD;
123 }
124 }
125
126 private int AppDomainNameCount;
127
128 /// <summary>
129 /// Create and prepare a new AppDomain for scripts
130 /// </summary>
131 /// <returns>The new AppDomain</returns>
132 private AppDomain PrepareNewAppDomain()
133 {
134 // Create and prepare a new AppDomain
135 AppDomainNameCount++;
136 // TODO: Currently security match current appdomain
137
138 // Construct and initialize settings for a second AppDomain.
139 AppDomainSetup ads = new AppDomainSetup();
140 ads.ApplicationBase = AppDomain.CurrentDomain.BaseDirectory;
141 ads.DisallowBindingRedirects = true;
142 ads.DisallowCodeDownload = true;
143 ads.LoaderOptimization = LoaderOptimization.MultiDomainHost;
144 ads.ShadowCopyFiles = "false"; // Disable shadowing
145 ads.ConfigurationFile = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile;
146
147
148 AppDomain AD = AppDomain.CreateDomain("ScriptAppDomain_" + AppDomainNameCount, null, ads);
149 m_scriptEngine.Log.Info("[" + m_scriptEngine.ScriptEngineName + "]: AppDomain Loading: " +
150 AssemblyName.GetAssemblyName("OpenSim.Region.ScriptEngine.Common.dll").ToString());
151 AD.Load(AssemblyName.GetAssemblyName("OpenSim.Region.ScriptEngine.Common.dll"));
152
153 // Return the new AppDomain
154 return AD;
155 }
156
157 /// <summary>
158 /// Unload appdomains that are full and have only dead scripts
159 /// </summary>
160 private void UnloadAppDomains()
161 {
162 lock (freeLock)
163 {
164 // Go through all
165 foreach (AppDomainStructure ads in new ArrayList(appDomains))
166 {
167 // Don't process current AppDomain
168 if (ads.CurrentAppDomain != currentAD.CurrentAppDomain)
169 {
170 // Not current AppDomain
171 // Is number of unloaded bigger or equal to number of loaded?
172 if (ads.ScriptsLoaded <= ads.ScriptsWaitingUnload)
173 {
174 // Remove from internal list
175 appDomains.Remove(ads);
176//#if DEBUG
177 //Console.WriteLine("Found empty AppDomain, unloading");
178 //long m = GC.GetTotalMemory(true); // This force a garbage collect that freezes some windows plateforms
179//#endif
180 // Unload
181 AppDomain.Unload(ads.CurrentAppDomain);
182//#if DEBUG
183 //m_scriptEngine.Log.Info("[" + m_scriptEngine.ScriptEngineName + "]: AppDomain unload freed " + (m - GC.GetTotalMemory(true)) + " bytes of memory");
184//#endif
185 }
186 }
187 }
188 }
189 }
190
191 public IScript LoadScript(string FileName)
192 {
193 // Find next available AppDomain to put it in
194 AppDomainStructure FreeAppDomain = GetFreeAppDomain();
195
196#if DEBUG
197 m_scriptEngine.Log.Info("[" + m_scriptEngine.ScriptEngineName + "]: Loading into AppDomain: " + FileName);
198#endif
199 IScript mbrt =
200 (IScript)
201 FreeAppDomain.CurrentAppDomain.CreateInstanceFromAndUnwrap(FileName, "SecondLife.Script");
202 //Console.WriteLine("ScriptEngine AppDomainManager: is proxy={0}", RemotingServices.IsTransparentProxy(mbrt));
203 FreeAppDomain.ScriptsLoaded++;
204
205 return mbrt;
206 }
207
208
209 /// <summary>
210 /// Increase "dead script" counter for an AppDomain
211 /// </summary>
212 /// <param name="ad"></param>
213 //[Obsolete("Needs fixing, needs a real purpose in life!!!")]
214 public void StopScript(AppDomain ad)
215 {
216 lock (freeLock)
217 {
218#if DEBUG
219 m_scriptEngine.Log.Info("[" + m_scriptEngine.ScriptEngineName + "]: Stopping script in AppDomain");
220#endif
221 // Check if it is current AppDomain
222 if (currentAD.CurrentAppDomain == ad)
223 {
224 // Yes - increase
225 currentAD.ScriptsWaitingUnload++;
226 return;
227 }
228
229 // Lopp through all AppDomains
230 foreach (AppDomainStructure ads in new ArrayList(appDomains))
231 {
232 if (ads.CurrentAppDomain == ad)
233 {
234 // Found it
235 ads.ScriptsWaitingUnload++;
236 break;
237 }
238 }
239 }
240
241 UnloadAppDomains(); // Outsite lock, has its own GetLock
242 }
243
244 /// <summary>
245 /// If set to true then threads and stuff should try to make a graceful exit
246 /// </summary>
247 public bool PleaseShutdown
248 {
249 get { return _PleaseShutdown; }
250 set { _PleaseShutdown = value; }
251 }
252 private bool _PleaseShutdown = false;
253 }
254}