aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/ScriptManager.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/Common/ScriptEngineBase/ScriptManager.cs
parent* Wind updates. Still random.. but in 4 directions instead of two! (diff)
downloadopensim-SC-824283ca3c2ab54868ed61fdb0a329221d69e5fa.zip
opensim-SC-824283ca3c2ab54868ed61fdb0a329221d69e5fa.tar.gz
opensim-SC-824283ca3c2ab54868ed61fdb0a329221d69e5fa.tar.bz2
opensim-SC-824283ca3c2ab54868ed61fdb0a329221d69e5fa.tar.xz
Remove all the subclassing complexity and script server interfaces from
DNE and move all of DNE into the DotNetEngine directory. Remove references that would cause the script runtime to load the entire engine + scene into each script appdomain. This might help DNE memory consumption.
Diffstat (limited to 'OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/ScriptManager.cs')
-rw-r--r--OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/ScriptManager.cs510
1 files changed, 0 insertions, 510 deletions
diff --git a/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/ScriptManager.cs b/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/ScriptManager.cs
deleted file mode 100644
index 987a0a0..0000000
--- a/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/ScriptManager.cs
+++ /dev/null
@@ -1,510 +0,0 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.IO;
31using System.Reflection;
32using System.Runtime.Serialization.Formatters.Binary;
33using System.Threading;
34using OpenMetaverse;
35using OpenSim.Region.Environment.Scenes;
36using OpenSim.Region.ScriptEngine.Shared;
37
38namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
39{
40 /// <summary>
41 /// Loads scripts
42 /// Compiles them if necessary
43 /// Execute functions for EventQueueManager (Sends them to script on other AppDomain for execution)
44 /// </summary>
45 ///
46
47 // This class is as close as you get to the script without being inside script class. It handles all the dirty work for other classes.
48 // * Keeps track of running scripts
49 // * Compiles script if necessary (through "Compiler")
50 // * Loads script (through "AppDomainManager" called from for example "EventQueueManager")
51 // * Executes functions inside script (called from for example "EventQueueManager" class)
52 // * Unloads script (through "AppDomainManager" called from for example "EventQueueManager")
53 // * Dedicated load/unload thread, and queues loading/unloading.
54 // This so that scripts starting or stopping will not slow down other theads or whole system.
55 //
56 [Serializable]
57 public abstract class ScriptManager : iScriptEngineFunctionModule
58 {
59 #region Declares
60
61 private Thread scriptLoadUnloadThread;
62 private static Thread staticScriptLoadUnloadThread;
63 // private int scriptLoadUnloadThread_IdleSleepms;
64 private Queue<LUStruct> LUQueue = new Queue<LUStruct>();
65 private static bool PrivateThread;
66 private int LoadUnloadMaxQueueSize;
67 private Object scriptLock = new Object();
68 private bool m_started = false;
69 private Dictionary<IScript, DetectParams[]> detparms = new Dictionary<IScript, DetectParams[]>();
70
71 // Load/Unload structure
72 private struct LUStruct
73 {
74 public uint localID;
75 public UUID itemID;
76 public string script;
77 public LUType Action;
78 public int startParam;
79 public bool postOnRez;
80 }
81
82 private enum LUType
83 {
84 Unknown = 0,
85 Load = 1,
86 Unload = 2
87 }
88
89 // Xantor 20080525: Keep a list of compiled scripts this session for reuse
90 public Dictionary<UUID, String> scriptList = new Dictionary<UUID, string>();
91
92 // Object<string, Script<string, script>>
93 // IMPORTANT: Types and MemberInfo-derived objects require a LOT of memory.
94 // Instead use RuntimeTypeHandle, RuntimeFieldHandle and RunTimeHandle (IntPtr) instead!
95 public Dictionary<uint, Dictionary<UUID, IScript>> Scripts =
96 new Dictionary<uint, Dictionary<UUID, IScript>>();
97
98
99 public Scene World
100 {
101 get { return m_scriptEngine.World; }
102 }
103
104 #endregion
105
106 public void ReadConfig()
107 {
108 // scriptLoadUnloadThread_IdleSleepms = m_scriptEngine.ScriptConfigSource.GetInt("ScriptLoadUnloadLoopms", 30);
109 // TODO: Requires sharing of all ScriptManagers to single thread
110 PrivateThread = true; // m_scriptEngine.ScriptConfigSource.GetBoolean("PrivateScriptLoadUnloadThread", false);
111 LoadUnloadMaxQueueSize = m_scriptEngine.ScriptConfigSource.GetInt("LoadUnloadMaxQueueSize", 100);
112 }
113
114 #region Object init/shutdown
115
116 public ScriptEngine m_scriptEngine;
117
118 public ScriptManager(ScriptEngine scriptEngine)
119 {
120 m_scriptEngine = scriptEngine;
121 }
122 public abstract void Initialize();
123 public void Setup()
124 {
125 ReadConfig();
126 Initialize();
127 }
128 public void Start()
129 {
130 m_started = true;
131
132
133 AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
134
135 //
136 // CREATE THREAD
137 // Private or shared
138 //
139 if (PrivateThread)
140 {
141 // Assign one thread per region
142 //scriptLoadUnloadThread = StartScriptLoadUnloadThread();
143 }
144 else
145 {
146 // Shared thread - make sure one exist, then assign it to the private
147 if (staticScriptLoadUnloadThread == null)
148 {
149 //staticScriptLoadUnloadThread = StartScriptLoadUnloadThread();
150 }
151 scriptLoadUnloadThread = staticScriptLoadUnloadThread;
152 }
153 }
154
155// TODO: unused
156// private static int privateThreadCount = 0;
157// private Thread StartScriptLoadUnloadThread()
158// {
159// Thread t = new Thread(ScriptLoadUnloadThreadLoop);
160// string name = "ScriptLoadUnloadThread:";
161// if (PrivateThread)
162// {
163// name += "Private:" + privateThreadCount;
164// privateThreadCount++;
165// }
166// else
167// {
168// name += "Shared";
169// }
170// t.Name = name;
171// t.IsBackground = true;
172// t.Priority = ThreadPriority.Normal;
173// t.Start();
174// OpenSim.Framework.ThreadTracker.Add(t);
175// return t;
176// }
177
178 ~ScriptManager()
179 {
180 // Abort load/unload thread
181 try
182 {
183 //PleaseShutdown = true;
184 //Thread.Sleep(100);
185 if (scriptLoadUnloadThread != null && scriptLoadUnloadThread.IsAlive == true)
186 {
187 scriptLoadUnloadThread.Abort();
188 //scriptLoadUnloadThread.Join();
189 }
190 }
191 catch
192 {
193 }
194 }
195
196 #endregion
197
198 #region Load / Unload scripts (Thread loop)
199
200// TODO: unused
201// private void ScriptLoadUnloadThreadLoop()
202// {
203// try
204// {
205// while (true)
206// {
207// if (LUQueue.Count == 0)
208// Thread.Sleep(scriptLoadUnloadThread_IdleSleepms);
209// //if (PleaseShutdown)
210// // return;
211// DoScriptLoadUnload();
212// }
213// }
214// catch (ThreadAbortException tae)
215// {
216// string a = tae.ToString();
217// a = String.Empty;
218// // Expected
219// }
220// }
221
222 public void DoScriptLoadUnload()
223 {
224 if (!m_started)
225 return;
226
227 lock (LUQueue)
228 {
229 if (LUQueue.Count > 0)
230 {
231m_scriptEngine.Log.InfoFormat("[{0}]: Loading script", m_scriptEngine.ScriptEngineName);
232 LUStruct item = LUQueue.Dequeue();
233
234 if (item.Action == LUType.Unload)
235 {
236 _StopScript(item.localID, item.itemID);
237 RemoveScript(item.localID, item.itemID);
238 }
239 else if (item.Action == LUType.Load)
240 {
241 _StartScript(item.localID, item.itemID, item.script, item.startParam, item.postOnRez);
242 }
243 }
244 }
245 }
246
247 #endregion
248
249 #region Helper functions
250
251 private static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
252 {
253 //Console.WriteLine("ScriptManager.CurrentDomain_AssemblyResolve: " + args.Name);
254 return Assembly.GetExecutingAssembly().FullName == args.Name ? Assembly.GetExecutingAssembly() : null;
255 }
256
257 #endregion
258
259
260
261 #region Start/Stop/Reset script
262
263 // private readonly Object startStopLock = new Object();
264
265 /// <summary>
266 /// Fetches, loads and hooks up a script to an objects events
267 /// </summary>
268 /// <param name="itemID"></param>
269 /// <param name="localID"></param>
270 public void StartScript(uint localID, UUID itemID, string Script, int startParam, bool postOnRez)
271 {
272 lock (LUQueue)
273 {
274 if ((LUQueue.Count >= LoadUnloadMaxQueueSize) && m_started)
275 {
276 m_scriptEngine.Log.Error("[" + m_scriptEngine.ScriptEngineName + "]: ERROR: Load/unload queue item count is at " + LUQueue.Count + ". Config variable \"LoadUnloadMaxQueueSize\" is set to " + LoadUnloadMaxQueueSize + ", so ignoring new script.");
277 return;
278 }
279
280 LUStruct ls = new LUStruct();
281 ls.localID = localID;
282 ls.itemID = itemID;
283 ls.script = Script;
284 ls.Action = LUType.Load;
285 ls.startParam = startParam;
286 ls.postOnRez = postOnRez;
287 LUQueue.Enqueue(ls);
288m_scriptEngine.Log.InfoFormat("[{0}]: Queued script for load", m_scriptEngine.ScriptEngineName);
289 }
290 }
291
292 /// <summary>
293 /// Disables and unloads a script
294 /// </summary>
295 /// <param name="localID"></param>
296 /// <param name="itemID"></param>
297 public void StopScript(uint localID, UUID itemID)
298 {
299 LUStruct ls = new LUStruct();
300 ls.localID = localID;
301 ls.itemID = itemID;
302 ls.Action = LUType.Unload;
303 ls.startParam = 0;
304 ls.postOnRez = false;
305 lock (LUQueue)
306 {
307 LUQueue.Enqueue(ls);
308 }
309 }
310
311 // Create a new instance of the compiler (reuse)
312 //private Compiler.LSL.Compiler LSLCompiler = new Compiler.LSL.Compiler();
313
314 public abstract void _StartScript(uint localID, UUID itemID, string Script, int startParam, bool postOnRez);
315 public abstract void _StopScript(uint localID, UUID itemID);
316
317
318 #endregion
319
320 #region Perform event execution in script
321
322 /// <summary>
323 /// Execute a LL-event-function in Script
324 /// </summary>
325 /// <param name="localID">Object the script is located in</param>
326 /// <param name="itemID">Script ID</param>
327 /// <param name="FunctionName">Name of function</param>
328 /// <param name="args">Arguments to pass to function</param>
329 internal void ExecuteEvent(uint localID, UUID itemID, string FunctionName, DetectParams[] qParams, object[] args)
330 {
331 //cfk 2-7-08 dont need this right now and the default Linux build has DEBUG defined
332 ///#if DEBUG
333 /// Console.WriteLine("ScriptEngine: Inside ExecuteEvent for event " + FunctionName);
334 ///#endif
335 // Execute a function in the script
336 //m_scriptEngine.Log.Info("[" + ScriptEngineName + "]: Executing Function localID: " + localID + ", itemID: " + itemID + ", FunctionName: " + FunctionName);
337 //ScriptBaseInterface Script = (ScriptBaseInterface)GetScript(localID, itemID);
338 IScript Script = GetScript(localID, itemID);
339 if (Script == null)
340 {
341 return;
342 }
343 //cfk 2-7-08 dont need this right now and the default Linux build has DEBUG defined
344 ///#if DEBUG
345 /// Console.WriteLine("ScriptEngine: Executing event: " + FunctionName);
346 ///#endif
347 // Must be done in correct AppDomain, so leaving it up to the script itself
348 detparms[Script] = qParams;
349 Script.Exec.ExecuteEvent(FunctionName, args);
350 detparms.Remove(Script);
351 }
352
353 public uint GetLocalID(UUID itemID)
354 {
355 foreach (KeyValuePair<uint, Dictionary<UUID, IScript> > k in Scripts)
356 {
357 if (k.Value.ContainsKey(itemID))
358 return k.Key;
359 }
360 return 0;
361 }
362
363 public int GetStateEventFlags(uint localID, UUID itemID)
364 {
365 // Console.WriteLine("GetStateEventFlags for <" + localID + "," + itemID + ">");
366 try
367 {
368 IScript Script = GetScript(localID, itemID);
369 if (Script == null)
370 {
371 return 0;
372 }
373 ExecutorBase.scriptEvents evflags = Script.Exec.GetStateEventFlags();
374 return (int)evflags;
375 }
376 catch (Exception)
377 {
378 }
379
380 return 0;
381 }
382
383
384 #endregion
385
386 #region Internal functions to keep track of script
387
388 public List<UUID> GetScriptKeys(uint localID)
389 {
390 if (Scripts.ContainsKey(localID) == false)
391 return new List<UUID>();
392
393 Dictionary<UUID, IScript> Obj;
394 Scripts.TryGetValue(localID, out Obj);
395
396 return new List<UUID>(Obj.Keys);
397 }
398
399 public IScript GetScript(uint localID, UUID itemID)
400 {
401 lock (scriptLock)
402 {
403 IScript Script = null;
404
405 if (Scripts.ContainsKey(localID) == false)
406 return null;
407
408 Dictionary<UUID, IScript> Obj;
409 Scripts.TryGetValue(localID, out Obj);
410 if (Obj.ContainsKey(itemID) == false)
411 return null;
412
413 // Get script
414 Obj.TryGetValue(itemID, out Script);
415 return Script;
416 }
417 }
418
419 public void SetScript(uint localID, UUID itemID, IScript Script)
420 {
421 lock (scriptLock)
422 {
423 // Create object if it doesn't exist
424 if (Scripts.ContainsKey(localID) == false)
425 {
426 Scripts.Add(localID, new Dictionary<UUID, IScript>());
427 }
428
429 // Delete script if it exists
430 Dictionary<UUID, IScript> Obj;
431 Scripts.TryGetValue(localID, out Obj);
432 if (Obj.ContainsKey(itemID) == true)
433 Obj.Remove(itemID);
434
435 // Add to object
436 Obj.Add(itemID, Script);
437 }
438 }
439
440 public void RemoveScript(uint localID, UUID itemID)
441 {
442 if (localID == 0)
443 localID = GetLocalID(itemID);
444
445 // Don't have that object?
446 if (Scripts.ContainsKey(localID) == false)
447 return;
448
449 // Delete script if it exists
450 Dictionary<UUID, IScript> Obj;
451 Scripts.TryGetValue(localID, out Obj);
452 if (Obj.ContainsKey(itemID) == true)
453 Obj.Remove(itemID);
454 }
455
456 #endregion
457
458
459 public void ResetScript(uint localID, UUID itemID)
460 {
461 IScript s = GetScript(localID, itemID);
462 string script = s.Source;
463 StopScript(localID, itemID);
464 SceneObjectPart part = World.GetSceneObjectPart(localID);
465 part.GetInventoryItem(itemID).PermsMask = 0;
466 part.GetInventoryItem(itemID).PermsGranter = UUID.Zero;
467 StartScript(localID, itemID, script, s.StartParam, false);
468 }
469
470
471 #region Script serialization/deserialization
472
473 public void GetSerializedScript(uint localID, UUID itemID)
474 {
475 // Serialize the script and return it
476 // Should not be a problem
477 FileStream fs = File.Create("SERIALIZED_SCRIPT_" + itemID);
478 BinaryFormatter b = new BinaryFormatter();
479 b.Serialize(fs, GetScript(localID, itemID));
480 fs.Close();
481 }
482
483 public void PutSerializedScript(uint localID, UUID itemID)
484 {
485 // Deserialize the script and inject it into an AppDomain
486
487 // How to inject into an AppDomain?
488 }
489
490 #endregion
491
492 ///// <summary>
493 ///// If set to true then threads and stuff should try to make a graceful exit
494 ///// </summary>
495 //public bool PleaseShutdown
496 //{
497 // get { return _PleaseShutdown; }
498 // set { _PleaseShutdown = value; }
499 //}
500 //private bool _PleaseShutdown = false;
501
502 public DetectParams[] GetDetectParams(IScript script)
503 {
504 if (detparms.ContainsKey(script))
505 return detparms[script];
506
507 return null;
508 }
509 }
510}