aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ScriptEngine/DotNetEngine/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/DotNetEngine/ScriptManager.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/ScriptManager.cs')
-rw-r--r--OpenSim/Region/ScriptEngine/DotNetEngine/ScriptManager.cs460
1 files changed, 452 insertions, 8 deletions
diff --git a/OpenSim/Region/ScriptEngine/DotNetEngine/ScriptManager.cs b/OpenSim/Region/ScriptEngine/DotNetEngine/ScriptManager.cs
index 8ff3bfd..12a8fe4 100644
--- a/OpenSim/Region/ScriptEngine/DotNetEngine/ScriptManager.cs
+++ b/OpenSim/Region/ScriptEngine/DotNetEngine/ScriptManager.cs
@@ -34,22 +34,66 @@ using OpenSim.Region.Environment.Scenes;
34using OpenSim.Region.ScriptEngine.Common; 34using OpenSim.Region.ScriptEngine.Common;
35using OpenSim.Region.ScriptEngine.Shared; 35using OpenSim.Region.ScriptEngine.Shared;
36using OpenSim.Region.ScriptEngine.Shared.Api; 36using OpenSim.Region.ScriptEngine.Shared.Api;
37using OpenSim.Region.ScriptEngine.Common.ScriptEngineBase; 37using System.Collections.Generic;
38using System.IO;
39using System.Runtime.Serialization.Formatters.Binary;
40using System.Threading;
38 41
39namespace OpenSim.Region.ScriptEngine.DotNetEngine 42namespace OpenSim.Region.ScriptEngine.DotNetEngine
40{ 43{
41 public class ScriptManager : Common.ScriptEngineBase.ScriptManager 44 public class ScriptManager
42 { 45 {
43 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 46 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
44 47
45 public ScriptManager(Common.ScriptEngineBase.ScriptEngine scriptEngine) 48 #region Declares
46 : base(scriptEngine) 49
50 private Thread scriptLoadUnloadThread;
51 private static Thread staticScriptLoadUnloadThread;
52 // private int scriptLoadUnloadThread_IdleSleepms;
53 private Queue<LUStruct> LUQueue = new Queue<LUStruct>();
54 private static bool PrivateThread;
55 private int LoadUnloadMaxQueueSize;
56 private Object scriptLock = new Object();
57 private bool m_started = false;
58 private Dictionary<IScript, DetectParams[]> detparms = new Dictionary<IScript, DetectParams[]>();
59
60 // Load/Unload structure
61 private struct LUStruct
62 {
63 public uint localID;
64 public UUID itemID;
65 public string script;
66 public LUType Action;
67 public int startParam;
68 public bool postOnRez;
69 }
70
71 private enum LUType
72 {
73 Unknown = 0,
74 Load = 1,
75 Unload = 2
76 }
77
78 // Xantor 20080525: Keep a list of compiled scripts this session for reuse
79 public Dictionary<UUID, String> scriptList = new Dictionary<UUID, string>();
80
81 // Object<string, Script<string, script>>
82 // IMPORTANT: Types and MemberInfo-derived objects require a LOT of memory.
83 // Instead use RuntimeTypeHandle, RuntimeFieldHandle and RunTimeHandle (IntPtr) instead!
84 public Dictionary<uint, Dictionary<UUID, IScript>> Scripts =
85 new Dictionary<uint, Dictionary<UUID, IScript>>();
86
87
88 public Scene World
47 { 89 {
48 base.m_scriptEngine = scriptEngine; 90 get { return m_scriptEngine.World; }
49 } 91 }
92
93 #endregion
50 private Compiler.LSL.Compiler LSLCompiler; 94 private Compiler.LSL.Compiler LSLCompiler;
51 95
52 public override void Initialize() 96 public void Initialize()
53 { 97 {
54 // Create our compiler 98 // Create our compiler
55 LSLCompiler = new Compiler.LSL.Compiler(m_scriptEngine); 99 LSLCompiler = new Compiler.LSL.Compiler(m_scriptEngine);
@@ -62,7 +106,7 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine
62 // PROVIDE SCRIPT WITH ITS INTERFACE TO OpenSim 106 // PROVIDE SCRIPT WITH ITS INTERFACE TO OpenSim
63 107
64 108
65 public override void _StartScript(uint localID, UUID itemID, string Script, int startParam, bool postOnRez) 109 public void _StartScript(uint localID, UUID itemID, string Script, int startParam, bool postOnRez)
66 { 110 {
67 m_log.DebugFormat( 111 m_log.DebugFormat(
68 "[{0}]: ScriptManager StartScript: localID: {1}, itemID: {2}", 112 "[{0}]: ScriptManager StartScript: localID: {1}, itemID: {2}",
@@ -173,7 +217,7 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine
173 } 217 }
174 } 218 }
175 219
176 public override void _StopScript(uint localID, UUID itemID) 220 public void _StopScript(uint localID, UUID itemID)
177 { 221 {
178 IScript LSLBC = GetScript(localID, itemID); 222 IScript LSLBC = GetScript(localID, itemID);
179 if (LSLBC == null) 223 if (LSLBC == null)
@@ -202,5 +246,405 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine
202 ": " + e.ToString()); 246 ": " + e.ToString());
203 } 247 }
204 } 248 }
249
250 public void ReadConfig()
251 {
252 // scriptLoadUnloadThread_IdleSleepms = m_scriptEngine.ScriptConfigSource.GetInt("ScriptLoadUnloadLoopms", 30);
253 // TODO: Requires sharing of all ScriptManagers to single thread
254 PrivateThread = true; // m_scriptEngine.ScriptConfigSource.GetBoolean("PrivateScriptLoadUnloadThread", false);
255 LoadUnloadMaxQueueSize = m_scriptEngine.ScriptConfigSource.GetInt("LoadUnloadMaxQueueSize", 100);
256 }
257
258 #region Object init/shutdown
259
260 public ScriptEngine m_scriptEngine;
261
262 public ScriptManager(ScriptEngine scriptEngine)
263 {
264 m_scriptEngine = scriptEngine;
265 }
266 public void Setup()
267 {
268 ReadConfig();
269 Initialize();
270 }
271 public void Start()
272 {
273 m_started = true;
274
275
276 AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
277
278 //
279 // CREATE THREAD
280 // Private or shared
281 //
282 if (PrivateThread)
283 {
284 // Assign one thread per region
285 //scriptLoadUnloadThread = StartScriptLoadUnloadThread();
286 }
287 else
288 {
289 // Shared thread - make sure one exist, then assign it to the private
290 if (staticScriptLoadUnloadThread == null)
291 {
292 //staticScriptLoadUnloadThread = StartScriptLoadUnloadThread();
293 }
294 scriptLoadUnloadThread = staticScriptLoadUnloadThread;
295 }
296 }
297
298// TODO: unused
299// private static int privateThreadCount = 0;
300// private Thread StartScriptLoadUnloadThread()
301// {
302// Thread t = new Thread(ScriptLoadUnloadThreadLoop);
303// string name = "ScriptLoadUnloadThread:";
304// if (PrivateThread)
305// {
306// name += "Private:" + privateThreadCount;
307// privateThreadCount++;
308// }
309// else
310// {
311// name += "Shared";
312// }
313// t.Name = name;
314// t.IsBackground = true;
315// t.Priority = ThreadPriority.Normal;
316// t.Start();
317// OpenSim.Framework.ThreadTracker.Add(t);
318// return t;
319// }
320
321 ~ScriptManager()
322 {
323 // Abort load/unload thread
324 try
325 {
326 //PleaseShutdown = true;
327 //Thread.Sleep(100);
328 if (scriptLoadUnloadThread != null && scriptLoadUnloadThread.IsAlive == true)
329 {
330 scriptLoadUnloadThread.Abort();
331 //scriptLoadUnloadThread.Join();
332 }
333 }
334 catch
335 {
336 }
337 }
338
339 #endregion
340
341 #region Load / Unload scripts (Thread loop)
342
343// TODO: unused
344// private void ScriptLoadUnloadThreadLoop()
345// {
346// try
347// {
348// while (true)
349// {
350// if (LUQueue.Count == 0)
351// Thread.Sleep(scriptLoadUnloadThread_IdleSleepms);
352// //if (PleaseShutdown)
353// // return;
354// DoScriptLoadUnload();
355// }
356// }
357// catch (ThreadAbortException tae)
358// {
359// string a = tae.ToString();
360// a = String.Empty;
361// // Expected
362// }
363// }
364
365 public void DoScriptLoadUnload()
366 {
367 if (!m_started)
368 return;
369
370 lock (LUQueue)
371 {
372 if (LUQueue.Count > 0)
373 {
374m_scriptEngine.Log.InfoFormat("[{0}]: Loading script", m_scriptEngine.ScriptEngineName);
375 LUStruct item = LUQueue.Dequeue();
376
377 if (item.Action == LUType.Unload)
378 {
379 _StopScript(item.localID, item.itemID);
380 RemoveScript(item.localID, item.itemID);
381 }
382 else if (item.Action == LUType.Load)
383 {
384 _StartScript(item.localID, item.itemID, item.script, item.startParam, item.postOnRez);
385 }
386 }
387 }
388 }
389
390 #endregion
391
392 #region Helper functions
393
394 private static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
395 {
396 //Console.WriteLine("ScriptManager.CurrentDomain_AssemblyResolve: " + args.Name);
397 return Assembly.GetExecutingAssembly().FullName == args.Name ? Assembly.GetExecutingAssembly() : null;
398 }
399
400 #endregion
401
402
403
404 #region Start/Stop/Reset script
405
406 // private readonly Object startStopLock = new Object();
407
408 /// <summary>
409 /// Fetches, loads and hooks up a script to an objects events
410 /// </summary>
411 /// <param name="itemID"></param>
412 /// <param name="localID"></param>
413 public void StartScript(uint localID, UUID itemID, string Script, int startParam, bool postOnRez)
414 {
415 lock (LUQueue)
416 {
417 if ((LUQueue.Count >= LoadUnloadMaxQueueSize) && m_started)
418 {
419 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.");
420 return;
421 }
422
423 LUStruct ls = new LUStruct();
424 ls.localID = localID;
425 ls.itemID = itemID;
426 ls.script = Script;
427 ls.Action = LUType.Load;
428 ls.startParam = startParam;
429 ls.postOnRez = postOnRez;
430 LUQueue.Enqueue(ls);
431m_scriptEngine.Log.InfoFormat("[{0}]: Queued script for load", m_scriptEngine.ScriptEngineName);
432 }
433 }
434
435 /// <summary>
436 /// Disables and unloads a script
437 /// </summary>
438 /// <param name="localID"></param>
439 /// <param name="itemID"></param>
440 public void StopScript(uint localID, UUID itemID)
441 {
442 LUStruct ls = new LUStruct();
443 ls.localID = localID;
444 ls.itemID = itemID;
445 ls.Action = LUType.Unload;
446 ls.startParam = 0;
447 ls.postOnRez = false;
448 lock (LUQueue)
449 {
450 LUQueue.Enqueue(ls);
451 }
452 }
453
454 // Create a new instance of the compiler (reuse)
455 //private Compiler.LSL.Compiler LSLCompiler = new Compiler.LSL.Compiler();
456
457
458 #endregion
459
460 #region Perform event execution in script
461
462 /// <summary>
463 /// Execute a LL-event-function in Script
464 /// </summary>
465 /// <param name="localID">Object the script is located in</param>
466 /// <param name="itemID">Script ID</param>
467 /// <param name="FunctionName">Name of function</param>
468 /// <param name="args">Arguments to pass to function</param>
469 internal void ExecuteEvent(uint localID, UUID itemID, string FunctionName, DetectParams[] qParams, object[] args)
470 {
471 //cfk 2-7-08 dont need this right now and the default Linux build has DEBUG defined
472 ///#if DEBUG
473 /// Console.WriteLine("ScriptEngine: Inside ExecuteEvent for event " + FunctionName);
474 ///#endif
475 // Execute a function in the script
476 //m_scriptEngine.Log.Info("[" + ScriptEngineName + "]: Executing Function localID: " + localID + ", itemID: " + itemID + ", FunctionName: " + FunctionName);
477 //ScriptBaseInterface Script = (ScriptBaseInterface)GetScript(localID, itemID);
478 IScript Script = GetScript(localID, itemID);
479 if (Script == null)
480 {
481 return;
482 }
483 //cfk 2-7-08 dont need this right now and the default Linux build has DEBUG defined
484 ///#if DEBUG
485 /// Console.WriteLine("ScriptEngine: Executing event: " + FunctionName);
486 ///#endif
487 // Must be done in correct AppDomain, so leaving it up to the script itself
488 detparms[Script] = qParams;
489 Script.Exec.ExecuteEvent(FunctionName, args);
490 detparms.Remove(Script);
491 }
492
493 public uint GetLocalID(UUID itemID)
494 {
495 foreach (KeyValuePair<uint, Dictionary<UUID, IScript> > k in Scripts)
496 {
497 if (k.Value.ContainsKey(itemID))
498 return k.Key;
499 }
500 return 0;
501 }
502
503 public int GetStateEventFlags(uint localID, UUID itemID)
504 {
505 // Console.WriteLine("GetStateEventFlags for <" + localID + "," + itemID + ">");
506 try
507 {
508 IScript Script = GetScript(localID, itemID);
509 if (Script == null)
510 {
511 return 0;
512 }
513 ExecutorBase.scriptEvents evflags = Script.Exec.GetStateEventFlags();
514 return (int)evflags;
515 }
516 catch (Exception)
517 {
518 }
519
520 return 0;
521 }
522
523
524 #endregion
525
526 #region Internal functions to keep track of script
527
528 public List<UUID> GetScriptKeys(uint localID)
529 {
530 if (Scripts.ContainsKey(localID) == false)
531 return new List<UUID>();
532
533 Dictionary<UUID, IScript> Obj;
534 Scripts.TryGetValue(localID, out Obj);
535
536 return new List<UUID>(Obj.Keys);
537 }
538
539 public IScript GetScript(uint localID, UUID itemID)
540 {
541 lock (scriptLock)
542 {
543 IScript Script = null;
544
545 if (Scripts.ContainsKey(localID) == false)
546 return null;
547
548 Dictionary<UUID, IScript> Obj;
549 Scripts.TryGetValue(localID, out Obj);
550 if (Obj.ContainsKey(itemID) == false)
551 return null;
552
553 // Get script
554 Obj.TryGetValue(itemID, out Script);
555 return Script;
556 }
557 }
558
559 public void SetScript(uint localID, UUID itemID, IScript Script)
560 {
561 lock (scriptLock)
562 {
563 // Create object if it doesn't exist
564 if (Scripts.ContainsKey(localID) == false)
565 {
566 Scripts.Add(localID, new Dictionary<UUID, IScript>());
567 }
568
569 // Delete script if it exists
570 Dictionary<UUID, IScript> Obj;
571 Scripts.TryGetValue(localID, out Obj);
572 if (Obj.ContainsKey(itemID) == true)
573 Obj.Remove(itemID);
574
575 // Add to object
576 Obj.Add(itemID, Script);
577 }
578 }
579
580 public void RemoveScript(uint localID, UUID itemID)
581 {
582 if (localID == 0)
583 localID = GetLocalID(itemID);
584
585 // Don't have that object?
586 if (Scripts.ContainsKey(localID) == false)
587 return;
588
589 // Delete script if it exists
590 Dictionary<UUID, IScript> Obj;
591 Scripts.TryGetValue(localID, out Obj);
592 if (Obj.ContainsKey(itemID) == true)
593 Obj.Remove(itemID);
594 }
595
596 #endregion
597
598
599 public void ResetScript(uint localID, UUID itemID)
600 {
601 IScript s = GetScript(localID, itemID);
602 string script = s.Source;
603 StopScript(localID, itemID);
604 SceneObjectPart part = World.GetSceneObjectPart(localID);
605 part.GetInventoryItem(itemID).PermsMask = 0;
606 part.GetInventoryItem(itemID).PermsGranter = UUID.Zero;
607 StartScript(localID, itemID, script, s.StartParam, false);
608 }
609
610
611 #region Script serialization/deserialization
612
613 public void GetSerializedScript(uint localID, UUID itemID)
614 {
615 // Serialize the script and return it
616 // Should not be a problem
617 FileStream fs = File.Create("SERIALIZED_SCRIPT_" + itemID);
618 BinaryFormatter b = new BinaryFormatter();
619 b.Serialize(fs, GetScript(localID, itemID));
620 fs.Close();
621 }
622
623 public void PutSerializedScript(uint localID, UUID itemID)
624 {
625 // Deserialize the script and inject it into an AppDomain
626
627 // How to inject into an AppDomain?
628 }
629
630 #endregion
631
632 ///// <summary>
633 ///// If set to true then threads and stuff should try to make a graceful exit
634 ///// </summary>
635 //public bool PleaseShutdown
636 //{
637 // get { return _PleaseShutdown; }
638 // set { _PleaseShutdown = value; }
639 //}
640 //private bool _PleaseShutdown = false;
641
642 public DetectParams[] GetDetectParams(IScript script)
643 {
644 if (detparms.ContainsKey(script))
645 return detparms[script];
646
647 return null;
648 }
205 } 649 }
206} 650}