diff options
Diffstat (limited to 'OpenSim/ScriptEngine/Components/DotNetEngine/Scheduler')
6 files changed, 901 insertions, 4 deletions
diff --git a/OpenSim/ScriptEngine/Components/DotNetEngine/Scheduler/BaseClassFactory.cs b/OpenSim/ScriptEngine/Components/DotNetEngine/Scheduler/BaseClassFactory.cs new file mode 100644 index 0000000..2f19cae --- /dev/null +++ b/OpenSim/ScriptEngine/Components/DotNetEngine/Scheduler/BaseClassFactory.cs | |||
@@ -0,0 +1,213 @@ | |||
1 | using System; | ||
2 | using System.Collections.Generic; | ||
3 | using System.IO; | ||
4 | using System.Reflection; | ||
5 | using System.Reflection.Emit; | ||
6 | using System.Text; | ||
7 | using OpenSim.ScriptEngine.Shared; | ||
8 | |||
9 | namespace OpenSim.ScriptEngine.Components.DotNetEngine.Scheduler | ||
10 | { | ||
11 | public class BaseClassFactory | ||
12 | { | ||
13 | |||
14 | |||
15 | public static void MakeBaseClass(ScriptStructure script) | ||
16 | { | ||
17 | string asmName = "ScriptAssemblies"; | ||
18 | string ModuleID = asmName; | ||
19 | string ClassID = "Script"; | ||
20 | string moveToDir = "ScriptEngines"; | ||
21 | string asmFileName = ModuleID + "_" + ClassID + ".dll"; | ||
22 | if (!Directory.Exists(moveToDir)) | ||
23 | Directory.CreateDirectory(moveToDir); | ||
24 | |||
25 | ILGenerator ilgen; | ||
26 | AssemblyBuilder asmBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly( | ||
27 | new AssemblyName(asmName), AssemblyBuilderAccess.RunAndSave); | ||
28 | |||
29 | // The module builder | ||
30 | ModuleBuilder modBuilder = asmBuilder.DefineDynamicModule(ModuleID, asmFileName); | ||
31 | |||
32 | // The class builder | ||
33 | TypeBuilder classBuilder = modBuilder.DefineType(ClassID, TypeAttributes.Class | TypeAttributes.Public); | ||
34 | |||
35 | // The default constructor | ||
36 | ConstructorBuilder ctorBuilder = classBuilder.DefineDefaultConstructor(MethodAttributes.Public); | ||
37 | |||
38 | |||
39 | Type[] paramsTypeArray = new Type[] {typeof (System.ParamArrayAttribute)}; | ||
40 | Type[] executeFunctionTypeArray = new Type[] {typeof (string), typeof (System.ParamArrayAttribute)}; | ||
41 | foreach (IScriptCommandProvider cp in script.RegionInfo.CommandProviders.Values) | ||
42 | { | ||
43 | Type t = cp.GetType(); | ||
44 | foreach (MethodInfo mi in t.GetMethods()) | ||
45 | { | ||
46 | MethodBuilder methodBuilder = classBuilder.DefineMethod(mi.Name, mi.Attributes, mi.GetType(), Type.EmptyTypes); | ||
47 | methodBuilder.SetParameters(paramsTypeArray); | ||
48 | //ParameterBuilder paramBuilder = methodBuilder.DefineParameter(1, ParameterAttributes.None, "args"); | ||
49 | |||
50 | ilgen = methodBuilder.GetILGenerator(); | ||
51 | //ilgen.Emit(OpCodes.Nop); | ||
52 | //ilgen.Emit(OpCodes.Ldarg_0); | ||
53 | //ilgen.Emit(OpCodes.Ldc_I4_0); | ||
54 | //ilgen.Emit(OpCodes.Ldelem_Ref); | ||
55 | //ilgen.MarkSequencePoint(doc, 6, 1, 6, 100); | ||
56 | |||
57 | MethodInfo ExecuteFunction = typeof(ScriptAssemblies.IScript).GetMethod( | ||
58 | "ExecuteFunction", | ||
59 | executeFunctionTypeArray); | ||
60 | |||
61 | ilgen.DeclareLocal(typeof(string)); | ||
62 | ilgen.Emit(OpCodes.Nop); | ||
63 | ilgen.Emit(OpCodes.Ldstr, mi.Name); | ||
64 | ilgen.Emit(OpCodes.Stloc_0); | ||
65 | ilgen.Emit(OpCodes.Ldarg_0); | ||
66 | ilgen.Emit(OpCodes.Ldloc_0); | ||
67 | ilgen.Emit(OpCodes.Ldarg_1); | ||
68 | |||
69 | // FieldInfo testInfo = classBuilder. | ||
70 | //BindingFlags.NonPublic | BindingFlags.Instance); | ||
71 | |||
72 | //ilgen.Emit(OpCodes.Ldfld, testInfo); | ||
73 | |||
74 | //ilgen.EmitCall(OpCodes.Call, ExecuteFunction, executeFunctionTypeArray); | ||
75 | ilgen.EmitCall(OpCodes.Call, typeof(System.Console).GetMethod("WriteLine"), executeFunctionTypeArray); | ||
76 | |||
77 | // // string.Format("Hello, {0} World!", toWhom) | ||
78 | // // | ||
79 | // ilgen.Emit(OpCodes.Ldstr, "Hello, {0} World!"); | ||
80 | // ilgen.Emit(OpCodes.Ldarg_1); | ||
81 | // ilgen.Emit(OpCodes.Call, typeof(string).GetMethod | ||
82 | //("Format", new Type[] { typeof(string), typeof(object) })); | ||
83 | |||
84 | // // Console.WriteLine("Hello, World!"); | ||
85 | // // | ||
86 | // ilgen.Emit(OpCodes.Call, typeof(Console).GetMethod | ||
87 | // ("WriteLine", new Type[] { typeof(string) })); | ||
88 | ilgen.Emit(OpCodes.Ret); | ||
89 | |||
90 | |||
91 | |||
92 | //Label eom = ilgen.DefineLabel(); | ||
93 | //ilgen.Emit(OpCodes.Br_S, eom); | ||
94 | //ilgen.MarkLabel(eom); | ||
95 | //ilgen.Emit(OpCodes.Ret); | ||
96 | //Type test = methodBuilder.SetParameters(); | ||
97 | |||
98 | |||
99 | //methodBuilder.SetParameters(typeof (object[])); | ||
100 | |||
101 | |||
102 | } | ||
103 | } | ||
104 | |||
105 | |||
106 | //// Two fields: m_firstname, m_lastname | ||
107 | //FieldBuilder fBuilderFirstName = classBuilder.DefineField("m_firstname", typeof(string), FieldAttributes.Private); | ||
108 | //FieldBuilder fBuilderLastName = classBuilder.DefineField("m_lastname", typeof(string), FieldAttributes.Private); | ||
109 | |||
110 | //// Two properties for this object: FirstName, LastName | ||
111 | //PropertyBuilder pBuilderFirstName = classBuilder.DefineProperty("FirstName", System.Reflection.PropertyAttributes.HasDefault, typeof(string), null); | ||
112 | //PropertyBuilder pBuilderLastName = classBuilder.DefineProperty("LastName", System.Reflection.PropertyAttributes.HasDefault, typeof(string), null); | ||
113 | |||
114 | //// Custom attributes for get, set accessors | ||
115 | //MethodAttributes getSetAttr = MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName; | ||
116 | |||
117 | //// get,set accessors for FirstName | ||
118 | //MethodBuilder mGetFirstNameBuilder = classBuilder.DefineMethod("get_FirstName", getSetAttr, typeof(string), Type.EmptyTypes); | ||
119 | |||
120 | //// Code generation | ||
121 | //ilgen = mGetFirstNameBuilder.GetILGenerator(); | ||
122 | //ilgen.Emit(OpCodes.Ldarg_0); | ||
123 | //ilgen.Emit(OpCodes.Ldfld, fBuilderFirstName); // returning the firstname field | ||
124 | //ilgen.Emit(OpCodes.Ret); | ||
125 | |||
126 | //MethodBuilder mSetFirstNameBuilder = classBuilder.DefineMethod("set_FirstName", getSetAttr, null, new Type[] { typeof(string) }); | ||
127 | |||
128 | //// Code generation | ||
129 | //ilgen = mSetFirstNameBuilder.GetILGenerator(); | ||
130 | //ilgen.Emit(OpCodes.Ldarg_0); | ||
131 | //ilgen.Emit(OpCodes.Ldarg_1); | ||
132 | //ilgen.Emit(OpCodes.Stfld, fBuilderFirstName); // setting the firstname field from the first argument (1) | ||
133 | //ilgen.Emit(OpCodes.Ret); | ||
134 | |||
135 | //// get,set accessors for LastName | ||
136 | //MethodBuilder mGetLastNameBuilder = classBuilder.DefineMethod("get_LastName", getSetAttr, typeof(string), Type.EmptyTypes); | ||
137 | |||
138 | //// Code generation | ||
139 | //ilgen = mGetLastNameBuilder.GetILGenerator(); | ||
140 | //ilgen.Emit(OpCodes.Ldarg_0); | ||
141 | //ilgen.Emit(OpCodes.Ldfld, fBuilderLastName); // returning the firstname field | ||
142 | //ilgen.Emit(OpCodes.Ret); | ||
143 | |||
144 | //MethodBuilder mSetLastNameBuilder = classBuilder.DefineMethod("set_LastName", getSetAttr, null, new Type[] { typeof(string) }); | ||
145 | |||
146 | //// Code generation | ||
147 | //ilgen = mSetLastNameBuilder.GetILGenerator(); | ||
148 | //ilgen.Emit(OpCodes.Ldarg_0); | ||
149 | //ilgen.Emit(OpCodes.Ldarg_1); | ||
150 | //ilgen.Emit(OpCodes.Stfld, fBuilderLastName); // setting the firstname field from the first argument (1) | ||
151 | //ilgen.Emit(OpCodes.Ret); | ||
152 | |||
153 | //// Assigning get/set accessors | ||
154 | //pBuilderFirstName.SetGetMethod(mGetFirstNameBuilder); | ||
155 | //pBuilderFirstName.SetSetMethod(mSetFirstNameBuilder); | ||
156 | |||
157 | //pBuilderLastName.SetGetMethod(mGetLastNameBuilder); | ||
158 | //pBuilderLastName.SetSetMethod(mSetLastNameBuilder); | ||
159 | |||
160 | //// Now, a custom method named GetFullName that concatenates FirstName and LastName properties | ||
161 | //MethodBuilder mGetFullNameBuilder = classBuilder.DefineMethod("GetFullName", MethodAttributes.Public, typeof(string), Type.EmptyTypes); | ||
162 | |||
163 | //// Code generation | ||
164 | //ilgen = mGetFullNameBuilder.GetILGenerator(); | ||
165 | //ilgen.Emit(OpCodes.Ldarg_0); | ||
166 | //ilgen.Emit(OpCodes.Call, mGetFirstNameBuilder); // getting the firstname | ||
167 | //ilgen.Emit(OpCodes.Ldstr, " "); // an space | ||
168 | //ilgen.Emit(OpCodes.Ldarg_0); | ||
169 | //ilgen.Emit(OpCodes.Call, mGetLastNameBuilder); // getting the lastname | ||
170 | |||
171 | //// We need the 'Concat' method from string type | ||
172 | //MethodInfo concatMethod = typeof(String).GetMethod("Concat", new Type[] { typeof(string), typeof(string), typeof(string) }); | ||
173 | |||
174 | //ilgen.Emit(OpCodes.Call, concatMethod); // calling concat and returning the result | ||
175 | //ilgen.Emit(OpCodes.Ret); | ||
176 | |||
177 | //// Another constructor that initializes firstname and lastname | ||
178 | //ConstructorBuilder ctorBuilder2 = classBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, new Type[] { typeof(string), typeof(string) }); | ||
179 | //ctorBuilder2.DefineParameter(1, ParameterAttributes.In, "firstname"); | ||
180 | //ctorBuilder2.DefineParameter(2, ParameterAttributes.In, "lastname"); | ||
181 | |||
182 | //// Code generation | ||
183 | //ilgen = ctorBuilder2.GetILGenerator(); | ||
184 | |||
185 | //// First of all, we need to call the base constructor, | ||
186 | //// the Object's constructor in this sample | ||
187 | //Type objType = Type.GetType("System.Object"); | ||
188 | //ConstructorInfo objCtor = objType.GetConstructor(Type.EmptyTypes); | ||
189 | |||
190 | //ilgen.Emit(OpCodes.Ldarg_0); | ||
191 | //ilgen.Emit(OpCodes.Call, objCtor); // calling the Object's constructor | ||
192 | |||
193 | //ilgen.Emit(OpCodes.Ldarg_0); | ||
194 | //ilgen.Emit(OpCodes.Ldarg_1); | ||
195 | //ilgen.Emit(OpCodes.Call, mSetFirstNameBuilder); // setting the firstname field from the first argument (1) | ||
196 | //ilgen.Emit(OpCodes.Ldarg_0); | ||
197 | //ilgen.Emit(OpCodes.Ldarg_2); | ||
198 | //ilgen.Emit(OpCodes.Call, mSetLastNameBuilder); // setting the lastname field from the second argument (2) | ||
199 | //ilgen.Emit(OpCodes.Ret); | ||
200 | |||
201 | // Finally, create the type and save the assembly | ||
202 | classBuilder.CreateType(); | ||
203 | |||
204 | asmBuilder.Save(asmFileName); | ||
205 | string toFile = Path.Combine(moveToDir, asmFileName); | ||
206 | if (File.Exists(toFile)) | ||
207 | File.Delete(toFile); | ||
208 | File.Move(asmFileName, toFile); | ||
209 | |||
210 | string a = ""; | ||
211 | } | ||
212 | } | ||
213 | } \ No newline at end of file | ||
diff --git a/OpenSim/ScriptEngine/Components/DotNetEngine/Scheduler/LoadUnloadStructure.cs b/OpenSim/ScriptEngine/Components/DotNetEngine/Scheduler/LoadUnloadStructure.cs new file mode 100644 index 0000000..d3d0509 --- /dev/null +++ b/OpenSim/ScriptEngine/Components/DotNetEngine/Scheduler/LoadUnloadStructure.cs | |||
@@ -0,0 +1,22 @@ | |||
1 | using System; | ||
2 | using System.Collections.Generic; | ||
3 | using System.Text; | ||
4 | using OpenSim.ScriptEngine.Shared; | ||
5 | |||
6 | namespace OpenSim.ScriptEngine.Components.DotNetEngine.Scheduler | ||
7 | { | ||
8 | public struct LoadUnloadStructure | ||
9 | { | ||
10 | public ScriptStructure Script; | ||
11 | public LUType Action; | ||
12 | public bool PostOnRez; | ||
13 | public int StartParam; | ||
14 | |||
15 | public enum LUType | ||
16 | { | ||
17 | Unknown = 0, | ||
18 | Load = 1, | ||
19 | Unload = 2 | ||
20 | } | ||
21 | } | ||
22 | } | ||
diff --git a/OpenSim/ScriptEngine/Components/DotNetEngine/Scheduler/Scheduler.cs b/OpenSim/ScriptEngine/Components/DotNetEngine/Scheduler/Scheduler.cs index 52c59eb..1143b03 100644 --- a/OpenSim/ScriptEngine/Components/DotNetEngine/Scheduler/Scheduler.cs +++ b/OpenSim/ScriptEngine/Components/DotNetEngine/Scheduler/Scheduler.cs | |||
@@ -27,18 +27,29 @@ | |||
27 | using System; | 27 | using System; |
28 | using System.Collections.Generic; | 28 | using System.Collections.Generic; |
29 | using System.Text; | 29 | using System.Text; |
30 | using OpenSim.ApplicationPlugins.ScriptEngine.Components; | 30 | using OpenMetaverse; |
31 | using OpenSim.ScriptEngine.Shared; | ||
31 | 32 | ||
32 | namespace OpenSim.ScriptEngine.Components.DotNetEngine.Scheduler | 33 | namespace OpenSim.ScriptEngine.Components.DotNetEngine.Scheduler |
33 | { | 34 | { |
34 | public class Scheduler: SchedulerBase | 35 | public class Scheduler : IScriptScheduler |
35 | { | 36 | { |
36 | public override void Start() | 37 | |
38 | private ScriptManager m_ScriptManager = new ScriptManager(); | ||
39 | public void AddScript(ScriptStructure scriptStructure) | ||
37 | { | 40 | { |
41 | m_ScriptManager.AddScript(scriptStructure); | ||
38 | } | 42 | } |
39 | 43 | ||
40 | public override void Close() | 44 | public void Removecript(uint id, UUID itemID) |
41 | { | 45 | { |
46 | m_ScriptManager.RemoveScript(id, itemID); | ||
42 | } | 47 | } |
48 | |||
49 | public void Close() | ||
50 | { | ||
51 | m_ScriptManager.Close(); | ||
52 | } | ||
53 | |||
43 | } | 54 | } |
44 | } | 55 | } |
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 | */ | ||
27 | using System; | ||
28 | using System.Collections; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Reflection; | ||
31 | using System.Text; | ||
32 | using log4net; | ||
33 | using OpenSim.ScriptEngine.Shared; | ||
34 | using IScript=OpenSim.Region.ScriptEngine.Shared.ScriptBase.IScript; | ||
35 | |||
36 | namespace 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 | ||
diff --git a/OpenSim/ScriptEngine/Components/DotNetEngine/Scheduler/ScriptManager.cs b/OpenSim/ScriptEngine/Components/DotNetEngine/Scheduler/ScriptManager.cs new file mode 100644 index 0000000..3452b03 --- /dev/null +++ b/OpenSim/ScriptEngine/Components/DotNetEngine/Scheduler/ScriptManager.cs | |||
@@ -0,0 +1,176 @@ | |||
1 | using System; | ||
2 | using System.Collections.Generic; | ||
3 | using System.Diagnostics; | ||
4 | using System.Reflection; | ||
5 | using System.Text; | ||
6 | using System.Threading; | ||
7 | using log4net; | ||
8 | using OpenMetaverse; | ||
9 | using OpenSim.Region.ScriptEngine.Shared; | ||
10 | using OpenSim.ScriptEngine.Shared; | ||
11 | using EventParams=OpenSim.ScriptEngine.Shared.EventParams; | ||
12 | |||
13 | namespace OpenSim.ScriptEngine.Components.DotNetEngine.Scheduler | ||
14 | { | ||
15 | public partial class ScriptManager: IScriptExecutor | ||
16 | { | ||
17 | private const int NoWorkSleepMs = 50; | ||
18 | private const int NoWorkSleepMsInc = 1; // How much time to increase wait with on every iteration | ||
19 | private const int NoWorkSleepMsIncMax = 300; // Max time to wait | ||
20 | |||
21 | internal static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
22 | public string Name { get { return "SECS.DotNetEngine.ScriptManager"; } } | ||
23 | private static Thread ScriptLoadUnloadThread; | ||
24 | public Dictionary<uint, Dictionary<UUID, ScriptStructure>> Scripts = new Dictionary<uint, Dictionary<UUID, ScriptStructure>>(); | ||
25 | |||
26 | private RegionInfoStructure CurrentRegion; | ||
27 | public void Initialize(RegionInfoStructure currentRegion) | ||
28 | { | ||
29 | CurrentRegion = currentRegion; | ||
30 | } | ||
31 | |||
32 | public ScriptManager() | ||
33 | { | ||
34 | ScriptLoadUnloadThread = new Thread(LoadUnloadLoop); | ||
35 | ScriptLoadUnloadThread.Name = "ScriptLoadUnloadThread"; | ||
36 | ScriptLoadUnloadThread.IsBackground = true; | ||
37 | ScriptLoadUnloadThread.Start(); | ||
38 | } | ||
39 | public void Close() { } | ||
40 | |||
41 | private void LoadUnloadLoop () | ||
42 | { | ||
43 | int _NoWorkSleepMsInc = 0; | ||
44 | while (true) | ||
45 | { | ||
46 | if (DoScriptLoadUnload()) | ||
47 | { | ||
48 | // We found work, reset counter | ||
49 | _NoWorkSleepMsInc = NoWorkSleepMs; | ||
50 | } else | ||
51 | { | ||
52 | // We didn't find work | ||
53 | // Sleep | ||
54 | Thread.Sleep(NoWorkSleepMs + NoWorkSleepMsInc); | ||
55 | // Increase sleep delay | ||
56 | _NoWorkSleepMsInc += NoWorkSleepMsInc; | ||
57 | // Make sure we don't exceed max | ||
58 | if (_NoWorkSleepMsInc > NoWorkSleepMsIncMax) | ||
59 | _NoWorkSleepMsInc = NoWorkSleepMsIncMax; | ||
60 | } | ||
61 | } | ||
62 | } | ||
63 | |||
64 | #region Add/Remove/Find script functions for our Script memory structure | ||
65 | private void MemAddScript(ScriptStructure script) | ||
66 | { | ||
67 | lock (scriptLock) | ||
68 | { | ||
69 | // Create object if it doesn't exist | ||
70 | if (!Scripts.ContainsKey(script.LocalID)) | ||
71 | Scripts.Add(script.LocalID, new Dictionary<UUID, ScriptStructure>()); | ||
72 | |||
73 | // Delete script if it exists | ||
74 | Dictionary<UUID, ScriptStructure> Obj; | ||
75 | if (Scripts.TryGetValue(script.LocalID, out Obj)) | ||
76 | if (Obj.ContainsKey(script.ItemID) == true) | ||
77 | Obj.Remove(script.ItemID); | ||
78 | |||
79 | // Add to object | ||
80 | Obj.Add(script.ItemID, script); | ||
81 | } | ||
82 | } | ||
83 | private void MemRemoveScript(uint LocalID, UUID ItemID) | ||
84 | { | ||
85 | // TODO: Also clean up command queue and async commands for object | ||
86 | lock (scriptLock) | ||
87 | { | ||
88 | // Create object if it doesn't exist | ||
89 | if (!Scripts.ContainsKey(LocalID)) | ||
90 | return; | ||
91 | |||
92 | // Delete script if it exists | ||
93 | Dictionary<UUID, ScriptStructure> Obj; | ||
94 | if (Scripts.TryGetValue(LocalID, out Obj)) | ||
95 | if (Obj.ContainsKey(ItemID) == true) | ||
96 | Obj.Remove(ItemID); | ||
97 | |||
98 | // Empty? | ||
99 | if (Obj.Count == 0) | ||
100 | Scripts.Remove(LocalID); | ||
101 | |||
102 | } | ||
103 | } | ||
104 | public bool TryGetScript(uint localID, UUID itemID, ref ScriptStructure script) | ||
105 | { | ||
106 | lock (scriptLock) | ||
107 | { | ||
108 | |||
109 | if (Scripts.ContainsKey(localID) == false) | ||
110 | return false; | ||
111 | |||
112 | Dictionary<UUID, ScriptStructure> Obj; | ||
113 | if (Scripts.TryGetValue(localID, out Obj)) | ||
114 | if (Obj.ContainsKey(itemID) == false) | ||
115 | return false; | ||
116 | |||
117 | // Get script | ||
118 | return Obj.TryGetValue(itemID, out script); | ||
119 | } | ||
120 | } | ||
121 | public ScriptStructure GetScript(uint localID, UUID itemID) | ||
122 | { | ||
123 | lock (scriptLock) | ||
124 | { | ||
125 | |||
126 | if (Scripts.ContainsKey(localID) == false) | ||
127 | throw new Exception("No script with LocalID " + localID + " was found."); | ||
128 | |||
129 | Dictionary<UUID, ScriptStructure> Obj; | ||
130 | if (Scripts.TryGetValue(localID, out Obj)) | ||
131 | if (Obj.ContainsKey(itemID) == false) | ||
132 | throw new Exception("No script with ItemID " + itemID + " was found."); | ||
133 | |||
134 | // Get script | ||
135 | return Obj[itemID]; | ||
136 | } | ||
137 | } | ||
138 | public bool TryGetScripts(uint localID, ref Dictionary<UUID, ScriptStructure> returnList) | ||
139 | { | ||
140 | Dictionary<UUID, ScriptStructure> getList = GetScripts(localID); | ||
141 | if (getList != null) | ||
142 | { | ||
143 | returnList = getList; | ||
144 | return true; | ||
145 | } | ||
146 | return false; | ||
147 | } | ||
148 | public Dictionary<UUID, ScriptStructure> GetScripts(uint localID) | ||
149 | { | ||
150 | lock (scriptLock) | ||
151 | { | ||
152 | |||
153 | if (Scripts.ContainsKey(localID) == false) | ||
154 | return null; | ||
155 | return Scripts[localID]; | ||
156 | } | ||
157 | } | ||
158 | #endregion | ||
159 | |||
160 | public void ExecuteCommand(EventParams p) | ||
161 | { | ||
162 | ScriptStructure ss = new ScriptStructure(); | ||
163 | if (TryGetScript(p.LocalID, p.ItemID, ref ss)) | ||
164 | ExecuteCommand(ref ss, p); | ||
165 | } | ||
166 | |||
167 | public void ExecuteCommand(ref ScriptStructure scriptContainer, EventParams p) | ||
168 | { | ||
169 | m_log.DebugFormat("[{0}] ######################################################", Name); | ||
170 | m_log.DebugFormat("[{0}] Command execution ItemID {1}: \"{2}\".", Name, scriptContainer.ItemID, p.EventName); | ||
171 | scriptContainer.ExecuteEvent(p); | ||
172 | m_log.DebugFormat("[{0}] ######################################################", Name); | ||
173 | } | ||
174 | |||
175 | } | ||
176 | } | ||
diff --git a/OpenSim/ScriptEngine/Components/DotNetEngine/Scheduler/ScriptManager_ScriptLoadUnload.cs b/OpenSim/ScriptEngine/Components/DotNetEngine/Scheduler/ScriptManager_ScriptLoadUnload.cs new file mode 100644 index 0000000..7d362f9 --- /dev/null +++ b/OpenSim/ScriptEngine/Components/DotNetEngine/Scheduler/ScriptManager_ScriptLoadUnload.cs | |||
@@ -0,0 +1,259 @@ | |||
1 | using System; | ||
2 | using System.Collections.Generic; | ||
3 | using System.Globalization; | ||
4 | using System.Reflection; | ||
5 | using System.Text; | ||
6 | using System.Threading; | ||
7 | using log4net; | ||
8 | using OpenMetaverse; | ||
9 | using OpenSim.Framework; | ||
10 | using OpenSim.Region.Environment.Scenes; | ||
11 | using OpenSim.Region.ScriptEngine.Interfaces; | ||
12 | using OpenSim.Region.ScriptEngine.Shared.ScriptBase; | ||
13 | using OpenSim.ScriptEngine.Shared; | ||
14 | |||
15 | namespace OpenSim.ScriptEngine.Components.DotNetEngine.Scheduler | ||
16 | { | ||
17 | public partial class ScriptManager | ||
18 | { | ||
19 | private Queue<LoadUnloadStructure> LUQueue = new Queue<LoadUnloadStructure>(); | ||
20 | private int LoadUnloadMaxQueueSize = 500; | ||
21 | private Object scriptLock = new Object(); | ||
22 | //private Dictionary<InstanceData, DetectParams[]> detparms = new Dictionary<InstanceData, DetectParams[]>(); | ||
23 | |||
24 | // Load/Unload structure | ||
25 | |||
26 | |||
27 | public void AddScript(ScriptStructure script) | ||
28 | { | ||
29 | lock (LUQueue) | ||
30 | { | ||
31 | if ((LUQueue.Count >= LoadUnloadMaxQueueSize)) | ||
32 | { | ||
33 | m_log.ErrorFormat("[{0}] ERROR: Load queue count is at {1} of max {2}. Ignoring load request for script LocalID: {3}, ItemID: {4}.", | ||
34 | Name, LUQueue.Count, LoadUnloadMaxQueueSize, script.LocalID, script.ItemID); | ||
35 | return; | ||
36 | } | ||
37 | |||
38 | LoadUnloadStructure ls = new LoadUnloadStructure(); | ||
39 | ls.Script = script; | ||
40 | ls.Action = LoadUnloadStructure.LUType.Load; | ||
41 | LUQueue.Enqueue(ls); | ||
42 | } | ||
43 | |||
44 | } | ||
45 | public void RemoveScript(uint localID, UUID itemID) | ||
46 | { | ||
47 | LoadUnloadStructure ls = new LoadUnloadStructure(); | ||
48 | |||
49 | // See if we can find script | ||
50 | if (!TryGetScript(localID, itemID, ref ls.Script)) | ||
51 | { | ||
52 | // Set manually | ||
53 | ls.Script.LocalID = localID; | ||
54 | ls.Script.ItemID = itemID; | ||
55 | } | ||
56 | ls.Script.StartParam = 0; | ||
57 | |||
58 | ls.Action = LoadUnloadStructure.LUType.Unload; | ||
59 | ls.PostOnRez = false; | ||
60 | |||
61 | lock (LUQueue) | ||
62 | { | ||
63 | LUQueue.Enqueue(ls); | ||
64 | } | ||
65 | } | ||
66 | |||
67 | internal bool DoScriptLoadUnload() | ||
68 | { | ||
69 | bool ret = false; | ||
70 | // if (!m_started) | ||
71 | // return; | ||
72 | |||
73 | lock (LUQueue) | ||
74 | { | ||
75 | if (LUQueue.Count > 0) | ||
76 | { | ||
77 | LoadUnloadStructure item = LUQueue.Dequeue(); | ||
78 | ret = true; | ||
79 | |||
80 | if (item.Action == LoadUnloadStructure.LUType.Unload) | ||
81 | { | ||
82 | m_log.DebugFormat("[{0}] Unloading script", Name); | ||
83 | _StopScript(item.Script.LocalID, item.Script.ItemID); | ||
84 | RemoveScript(item.Script.LocalID, item.Script.ItemID); | ||
85 | } | ||
86 | else if (item.Action == LoadUnloadStructure.LUType.Load) | ||
87 | { | ||
88 | m_log.DebugFormat("[{0}] Loading script", Name); | ||
89 | _StartScript(item); | ||
90 | } | ||
91 | } | ||
92 | } | ||
93 | return ret; | ||
94 | } | ||
95 | |||
96 | //public void _StartScript(uint localID, UUID itemID, string Script, int startParam, bool postOnRez) | ||
97 | private void _StartScript(LoadUnloadStructure ScriptObject) | ||
98 | { | ||
99 | m_log.DebugFormat( | ||
100 | "[{0}]: ScriptManager StartScript: localID: {1}, itemID: {2}", | ||
101 | Name, ScriptObject.Script.LocalID, ScriptObject.Script.ItemID); | ||
102 | |||
103 | // We will initialize and start the script. | ||
104 | // It will be up to the script itself to hook up the correct events. | ||
105 | |||
106 | SceneObjectPart m_host = ScriptObject.Script.RegionInfo.Scene.GetSceneObjectPart(ScriptObject.Script.LocalID); | ||
107 | |||
108 | if (null == m_host) | ||
109 | { | ||
110 | m_log.ErrorFormat( | ||
111 | "[{0}]: Could not find scene object part corresponding " + | ||
112 | "to localID {1} to start script", | ||
113 | Name, ScriptObject.Script.LocalID); | ||
114 | |||
115 | return; | ||
116 | } | ||
117 | |||
118 | UUID assetID = UUID.Zero; | ||
119 | TaskInventoryItem taskInventoryItem = new TaskInventoryItem(); | ||
120 | if (m_host.TaskInventory.TryGetValue(ScriptObject.Script.ItemID, out taskInventoryItem)) | ||
121 | assetID = taskInventoryItem.AssetID; | ||
122 | |||
123 | ScenePresence presence = | ||
124 | ScriptObject.Script.RegionInfo.Scene.GetScenePresence(taskInventoryItem.OwnerID); | ||
125 | |||
126 | CultureInfo USCulture = new CultureInfo("en-US"); | ||
127 | Thread.CurrentThread.CurrentCulture = USCulture; | ||
128 | |||
129 | try | ||
130 | { | ||
131 | // | ||
132 | // Compile script to an assembly | ||
133 | // | ||
134 | //TODO: DEBUG | ||
135 | BaseClassFactory.MakeBaseClass(ScriptObject.Script); | ||
136 | |||
137 | m_log.DebugFormat("[{0}] Compiling script {1}", Name, ScriptObject.Script.Name); | ||
138 | |||
139 | string fileName = ""; | ||
140 | try | ||
141 | { | ||
142 | IScriptCompiler compiler = | ||
143 | ScriptObject.Script.RegionInfo.FindCompiler(ScriptObject.Script.ScriptMetaData); | ||
144 | RegionInfoStructure currentRegionInfo = ScriptObject.Script.RegionInfo; | ||
145 | fileName = compiler.Compile(ScriptObject.Script.ScriptMetaData, | ||
146 | ref ScriptObject.Script.Source); | ||
147 | ScriptObject.Script.AssemblyFileName = fileName; | ||
148 | } | ||
149 | catch (Exception e) | ||
150 | { | ||
151 | m_log.ErrorFormat("[{0}] Internal error while compiling \"{1}\": {2}", Name, ScriptObject.Script.Name, e.ToString()); | ||
152 | } | ||
153 | m_log.DebugFormat("[{0}] Compiled \"{1}\" to assembly: \"{2}\".", Name, ScriptObject.Script.Name, fileName); | ||
154 | |||
155 | // Add it to our script memstruct | ||
156 | MemAddScript(ScriptObject.Script); | ||
157 | |||
158 | ScriptAssemblies.IScript CompiledScript; | ||
159 | CompiledScript = CurrentRegion.ScriptLoader.LoadScript(ScriptObject.Script); | ||
160 | ScriptObject.Script.State = "default"; | ||
161 | ScriptObject.Script.ScriptObject = CompiledScript; | ||
162 | ScriptObject.Script.Disabled = false; | ||
163 | ScriptObject.Script.Running = true; | ||
164 | //id.LineMap = LSLCompiler.LineMap(); | ||
165 | //id.Script = CompiledScript; | ||
166 | //id.Source = item.Script.Script; | ||
167 | //item.StartParam = startParam; | ||
168 | |||
169 | |||
170 | |||
171 | // TODO: Fire the first start-event | ||
172 | //int eventFlags = | ||
173 | // m_scriptEngine.m_ScriptManager.GetStateEventFlags( | ||
174 | // localID, itemID); | ||
175 | |||
176 | //m_host.SetScriptEvents(itemID, eventFlags); | ||
177 | ScriptObject.Script.RegionInfo.Executors_Execute(ScriptObject.Script, | ||
178 | new EventParams(ScriptObject.Script.LocalID, ScriptObject.Script.ItemID, "state_entry", new object[] { }, new Region.ScriptEngine.Shared.DetectParams[0]) | ||
179 | ); | ||
180 | |||
181 | if (ScriptObject.PostOnRez) | ||
182 | { | ||
183 | ScriptObject.Script.RegionInfo.Executors_Execute(ScriptObject.Script, | ||
184 | new EventParams(ScriptObject.Script.LocalID, "on_rez", new object[] | ||
185 | {new Region.ScriptEngine.Shared.LSL_Types.LSLInteger(ScriptObject.StartParam) | ||
186 | }, new Region.ScriptEngine.Shared.DetectParams[0])); | ||
187 | } | ||
188 | } | ||
189 | catch (Exception e) // LEGIT: User Scripting | ||
190 | { | ||
191 | if (presence != null && (!ScriptObject.PostOnRez)) | ||
192 | presence.ControllingClient.SendAgentAlertMessage( | ||
193 | "Script saved with errors, check debug window!", | ||
194 | false); | ||
195 | try | ||
196 | { | ||
197 | // DISPLAY ERROR INWORLD | ||
198 | string text = "Error compiling script:\n" + | ||
199 | e.Message.ToString(); | ||
200 | if (text.Length > 1100) | ||
201 | text = text.Substring(0, 1099); | ||
202 | |||
203 | ScriptObject.Script.RegionInfo.Scene.SimChat(Utils.StringToBytes(text), | ||
204 | ChatTypeEnum.DebugChannel, 2147483647, | ||
205 | m_host.AbsolutePosition, m_host.Name, m_host.UUID, | ||
206 | false); | ||
207 | } | ||
208 | catch (Exception e2) // LEGIT: User Scripting | ||
209 | { | ||
210 | m_log.Error("[" + | ||
211 | Name + | ||
212 | "]: Error displaying error in-world: " + | ||
213 | e2.ToString()); | ||
214 | m_log.Error("[" + | ||
215 | Name + "]: " + | ||
216 | "Errormessage: Error compiling script:\r\n" + | ||
217 | e2.Message.ToString()); | ||
218 | } | ||
219 | } | ||
220 | } | ||
221 | |||
222 | |||
223 | |||
224 | public void _StopScript(uint localID, UUID itemID) | ||
225 | { | ||
226 | ScriptStructure ss = new ScriptStructure(); | ||
227 | if (!TryGetScript(localID, itemID, ref ss)) | ||
228 | return; | ||
229 | |||
230 | // Stop long command on script | ||
231 | //AsyncCommandManager.RemoveScript(ss); | ||
232 | |||
233 | try | ||
234 | { | ||
235 | // Get AppDomain | ||
236 | // Tell script not to accept new requests | ||
237 | ss.Running = false; | ||
238 | ss.Disabled = true; | ||
239 | AppDomain ad = ss.AppDomain; | ||
240 | |||
241 | // Remove from internal structure | ||
242 | MemRemoveScript(localID, itemID); | ||
243 | |||
244 | // TODO: Tell AppDomain that we have stopped script | ||
245 | |||
246 | } | ||
247 | catch (Exception e) // LEGIT: User Scripting | ||
248 | { | ||
249 | m_log.Error("[" + | ||
250 | Name + | ||
251 | "]: Exception stopping script localID: " + | ||
252 | localID + " LLUID: " + itemID.ToString() + | ||
253 | ": " + e.ToString()); | ||
254 | } | ||
255 | } | ||
256 | |||
257 | |||
258 | } | ||
259 | } | ||