aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/ScriptEngine/Components/DotNetEngine/Scheduler/ScriptLoader.cs
diff options
context:
space:
mode:
authorTedd Hansen2008-11-08 17:35:48 +0000
committerTedd Hansen2008-11-08 17:35:48 +0000
commit9511a8c76370f21e839114007dcd2b25c69b009a (patch)
treeb63323dfd96ecd1cc3cd560939bd66bb43ec9c1c /OpenSim/ScriptEngine/Components/DotNetEngine/Scheduler/ScriptLoader.cs
parent* Added IClientIM to IClientCore interfaces (diff)
downloadopensim-SC-9511a8c76370f21e839114007dcd2b25c69b009a.zip
opensim-SC-9511a8c76370f21e839114007dcd2b25c69b009a.tar.gz
opensim-SC-9511a8c76370f21e839114007dcd2b25c69b009a.tar.bz2
opensim-SC-9511a8c76370f21e839114007dcd2b25c69b009a.tar.xz
Work in progress on SECS stuff. Have been holding it off until after 0.6 release. Still messy as hell and doesn't really work yet. Will undergo dramatic changes. AND MOST IMPORTANTLY: Will be conformed to work in coop with todays DNE and XEngine, hopefully one day providing a common interface for all components.
Diffstat (limited to 'OpenSim/ScriptEngine/Components/DotNetEngine/Scheduler/ScriptLoader.cs')
-rw-r--r--OpenSim/ScriptEngine/Components/DotNetEngine/Scheduler/ScriptLoader.cs216
1 files changed, 216 insertions, 0 deletions
diff --git a/OpenSim/ScriptEngine/Components/DotNetEngine/Scheduler/ScriptLoader.cs b/OpenSim/ScriptEngine/Components/DotNetEngine/Scheduler/ScriptLoader.cs
new file mode 100644
index 0000000..cb4a870
--- /dev/null
+++ b/OpenSim/ScriptEngine/Components/DotNetEngine/Scheduler/ScriptLoader.cs
@@ -0,0 +1,216 @@
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 */
27using System;
28using System.Collections;
29using System.Collections.Generic;
30using System.Reflection;
31using System.Text;
32using log4net;
33using OpenSim.ScriptEngine.Shared;
34using IScript=OpenSim.Region.ScriptEngine.Shared.ScriptBase.IScript;
35
36namespace OpenSim.ScriptEngine.Components.DotNetEngine.Scheduler
37{
38 public class ScriptLoader : IScriptLoader
39 {
40 //
41 // This class does AppDomain handling and loading/unloading of
42 // scripts in it. It is instanced in "ScriptEngine" and controlled
43 // from "ScriptManager"
44 //
45 // 1. Create a new AppDomain if old one is full (or doesn't exist)
46 // 2. Load scripts into AppDomain
47 // 3. Unload scripts from AppDomain (stopping them and marking
48 // them as inactive)
49 // 4. Unload AppDomain completely when all scripts in it has stopped
50 //
51
52 public string Name { get { return "SECS.DotNetEngine.Scheduler.ScriptLoader"; } }
53 private int maxScriptsPerAppDomain = 10;
54
55 // Internal list of all AppDomains
56 private List<AppDomainStructure> appDomains =
57 new List<AppDomainStructure>();
58 private Dictionary<string, AppDomainStructure> AppDomainFiles = new Dictionary<string, AppDomainStructure>();
59 public readonly string[] AssembliesInAppDomain = new string[] { "OpenSim.ScriptEngine.Shared.Script.dll", "OpenSim.Region.ScriptEngine.Shared.dll" };
60
61 internal static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
62
63 // Structure to keep track of data around AppDomain
64 private class AppDomainStructure
65 {
66 public AppDomain CurrentAppDomain; // The AppDomain itself
67 public int ScriptsLoaded; // Number of scripts loaded into AppDomain
68 public int ScriptsWaitingUnload; // Number of dead scripts
69 }
70
71 // Current AppDomain
72 private AppDomainStructure currentAD;
73
74 private object getLock = new object(); // Mutex
75 private object freeLock = new object(); // Mutex
76
77 // Find a free AppDomain, creating one if necessary
78 private AppDomainStructure GetFreeAppDomain()
79 {
80 lock (getLock)
81 {
82 // Current full?
83 if (currentAD != null &&
84 currentAD.ScriptsLoaded >= maxScriptsPerAppDomain)
85 {
86 // Add it to AppDomains list and empty current
87 appDomains.Add(currentAD);
88 currentAD = null;
89 }
90 // No current
91 if (currentAD == null)
92 {
93 // Create a new current AppDomain
94 currentAD = new AppDomainStructure();
95 currentAD.CurrentAppDomain = PrepareNewAppDomain();
96 }
97
98 return currentAD;
99 }
100 }
101
102 private int AppDomainNameCount;
103 public ScriptAssemblies.IScript LoadScript(ScriptStructure script)
104 {
105 // Find next available AppDomain to put it in
106 AppDomainStructure FreeAppDomain;
107
108 // If we already have loaded file, then reuse that AppDomains
109 if (AppDomainFiles.ContainsKey(script.AssemblyFileName))
110 FreeAppDomain = AppDomainFiles[script.AssemblyFileName];
111 else
112 FreeAppDomain = GetFreeAppDomain();
113
114 // Set script object AppDomain
115 script.AppDomain = FreeAppDomain.CurrentAppDomain;
116
117 // Create instance of script
118 ScriptAssemblies.IScript mbrt = (ScriptAssemblies.IScript)
119 FreeAppDomain.CurrentAppDomain.CreateInstanceFromAndUnwrap(
120 script.AssemblyFileName, "ScriptAssemblies.Script");
121 //, true, BindingFlags.CreateInstance, null);
122 FreeAppDomain.ScriptsLoaded++;
123
124 return mbrt;
125 }
126
127 // Create and prepare a new AppDomain for scripts
128 private AppDomain PrepareNewAppDomain()
129 {
130 // Create and prepare a new AppDomain
131 AppDomainNameCount++;
132
133 // TODO: Currently security match current appdomain
134
135 // Construct and initialize settings for a second AppDomain.
136 AppDomainSetup ads = new AppDomainSetup();
137 ads.ApplicationBase = AppDomain.CurrentDomain.BaseDirectory;
138 ads.DisallowBindingRedirects = true;
139 ads.DisallowCodeDownload = true;
140 ads.LoaderOptimization = LoaderOptimization.MultiDomainHost;
141 ads.ShadowCopyFiles = "false"; // Disable shadowing
142 ads.ConfigurationFile =
143 AppDomain.CurrentDomain.SetupInformation.ConfigurationFile;
144
145 AppDomain AD = AppDomain.CreateDomain("ScriptAppDomain_" +
146 AppDomainNameCount, null, ads);
147
148 foreach (string file in AssembliesInAppDomain)
149 {
150 m_log.InfoFormat("[{0}] AppDomain Loading: \"{1}\"->\"{2}\".", Name, file,
151 AssemblyName.GetAssemblyName(file).ToString());
152 AD.Load(AssemblyName.GetAssemblyName(file));
153 }
154
155 // Return the new AppDomain
156 return AD;
157 }
158
159 // Unload appdomains that are full and have only dead scripts
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
177 // Unload
178 AppDomain.Unload(ads.CurrentAppDomain);
179 }
180 }
181 }
182 }
183 }
184
185 // Increase "dead script" counter for an AppDomain
186 public void StopScript(AppDomain ad)
187 {
188 lock (freeLock)
189 {
190 // Check if it is current AppDomain
191 if (currentAD.CurrentAppDomain == ad)
192 {
193 // Yes - increase
194 currentAD.ScriptsWaitingUnload++;
195 return;
196 }
197
198 // Lopp through all AppDomains
199 foreach (AppDomainStructure ads in new ArrayList(appDomains))
200 {
201 if (ads.CurrentAppDomain == ad)
202 {
203 // Found it
204 ads.ScriptsWaitingUnload++;
205 break;
206 }
207 }
208 }
209
210 UnloadAppDomains(); // Outsite lock, has its own GetLock
211 }
212
213
214
215 }
216} \ No newline at end of file