diff options
Diffstat (limited to 'OpenSim/Region/ScriptEngine/XEngine/XEngine.cs')
-rw-r--r-- | OpenSim/Region/ScriptEngine/XEngine/XEngine.cs | 123 |
1 files changed, 64 insertions, 59 deletions
diff --git a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs index 7b19ce3..a60c0ba 100644 --- a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs +++ b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs | |||
@@ -50,6 +50,8 @@ using OpenSim.Region.ScriptEngine.Shared.CodeTools; | |||
50 | using OpenSim.Region.ScriptEngine.Shared.Instance; | 50 | using OpenSim.Region.ScriptEngine.Shared.Instance; |
51 | using OpenSim.Region.ScriptEngine.Interfaces; | 51 | using OpenSim.Region.ScriptEngine.Interfaces; |
52 | 52 | ||
53 | using ScriptCompileQueue = OpenSim.Framework.LocklessQueue<object[]>; | ||
54 | |||
53 | namespace OpenSim.Region.ScriptEngine.XEngine | 55 | namespace OpenSim.Region.ScriptEngine.XEngine |
54 | { | 56 | { |
55 | public class XEngine : INonSharedRegionModule, IScriptModule, IScriptEngine | 57 | public class XEngine : INonSharedRegionModule, IScriptModule, IScriptEngine |
@@ -73,9 +75,11 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
73 | private bool m_InitialStartup = true; | 75 | private bool m_InitialStartup = true; |
74 | private int m_ScriptFailCount; // Number of script fails since compile queue was last empty | 76 | private int m_ScriptFailCount; // Number of script fails since compile queue was last empty |
75 | private string m_ScriptErrorMessage; | 77 | private string m_ScriptErrorMessage; |
78 | private Dictionary<string, string> m_uniqueScripts = new Dictionary<string, string>(); | ||
79 | private bool m_AppDomainLoading; | ||
76 | 80 | ||
77 | // disable warning: need to keep a reference to XEngine.EventManager | 81 | // disable warning: need to keep a reference to XEngine.EventManager |
78 | // alive to avoid it being garbage collected | 82 | // alive to avoid it being garbage collected |
79 | #pragma warning disable 414 | 83 | #pragma warning disable 414 |
80 | private EventManager m_EventManager; | 84 | private EventManager m_EventManager; |
81 | #pragma warning restore 414 | 85 | #pragma warning restore 414 |
@@ -114,7 +118,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
114 | private Dictionary<UUID, List<UUID> > m_DomainScripts = | 118 | private Dictionary<UUID, List<UUID> > m_DomainScripts = |
115 | new Dictionary<UUID, List<UUID> >(); | 119 | new Dictionary<UUID, List<UUID> >(); |
116 | 120 | ||
117 | private Queue m_CompileQueue = new Queue(100); | 121 | private ScriptCompileQueue m_CompileQueue = new ScriptCompileQueue(); |
118 | IWorkItemResult m_CurrentCompile = null; | 122 | IWorkItemResult m_CurrentCompile = null; |
119 | 123 | ||
120 | public string ScriptEngineName | 124 | public string ScriptEngineName |
@@ -201,6 +205,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
201 | m_MaxScriptQueue = m_ScriptConfig.GetInt("MaxScriptEventQueue",300); | 205 | m_MaxScriptQueue = m_ScriptConfig.GetInt("MaxScriptEventQueue",300); |
202 | m_StackSize = m_ScriptConfig.GetInt("ThreadStackSize", 262144); | 206 | m_StackSize = m_ScriptConfig.GetInt("ThreadStackSize", 262144); |
203 | m_SleepTime = m_ScriptConfig.GetInt("MaintenanceInterval", 10) * 1000; | 207 | m_SleepTime = m_ScriptConfig.GetInt("MaintenanceInterval", 10) * 1000; |
208 | m_AppDomainLoading = m_ScriptConfig.GetBoolean("AppDomainLoading", true); | ||
204 | 209 | ||
205 | m_EventLimit = m_ScriptConfig.GetInt("EventLimit", 30); | 210 | m_EventLimit = m_ScriptConfig.GetInt("EventLimit", 30); |
206 | m_KillTimedOutScripts = m_ScriptConfig.GetBoolean("KillTimedOutScripts", false); | 211 | m_KillTimedOutScripts = m_ScriptConfig.GetBoolean("KillTimedOutScripts", false); |
@@ -470,6 +475,12 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
470 | if (engine != ScriptEngineName) | 475 | if (engine != ScriptEngineName) |
471 | return; | 476 | return; |
472 | 477 | ||
478 | // If we've seen this exact script text before, use that reference instead | ||
479 | if (m_uniqueScripts.ContainsKey(script)) | ||
480 | script = m_uniqueScripts[script]; | ||
481 | else | ||
482 | m_uniqueScripts[script] = script; | ||
483 | |||
473 | Object[] parms = new Object[]{localID, itemID, script, startParam, postOnRez, (StateSource)stateSource}; | 484 | Object[] parms = new Object[]{localID, itemID, script, startParam, postOnRez, (StateSource)stateSource}; |
474 | 485 | ||
475 | if (stateSource == (int)StateSource.ScriptedRez) | 486 | if (stateSource == (int)StateSource.ScriptedRez) |
@@ -478,15 +489,19 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
478 | } | 489 | } |
479 | else | 490 | else |
480 | { | 491 | { |
481 | lock (m_CompileQueue) | 492 | m_CompileQueue.Enqueue(parms); |
482 | { | ||
483 | m_CompileQueue.Enqueue(parms); | ||
484 | 493 | ||
485 | if (m_CurrentCompile == null) | 494 | if (m_CurrentCompile == null) |
495 | { | ||
496 | // NOTE: Although we use a lockless queue, the lock here | ||
497 | // is required. It ensures that there are never two | ||
498 | // compile threads running, which, due to a race | ||
499 | // conndition, might otherwise happen | ||
500 | // | ||
501 | lock (m_CompileQueue) | ||
486 | { | 502 | { |
487 | m_CurrentCompile = m_ThreadPool.QueueWorkItem( | 503 | if (m_CurrentCompile == null) |
488 | new WorkItemCallback(this.DoOnRezScriptQueue), | 504 | m_CurrentCompile = m_ThreadPool.QueueWorkItem(DoOnRezScriptQueue, null); |
489 | new Object[0]); | ||
490 | } | 505 | } |
491 | } | 506 | } |
492 | } | 507 | } |
@@ -498,50 +513,38 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
498 | { | 513 | { |
499 | m_InitialStartup = false; | 514 | m_InitialStartup = false; |
500 | System.Threading.Thread.Sleep(15000); | 515 | System.Threading.Thread.Sleep(15000); |
501 | lock (m_CompileQueue) | ||
502 | { | ||
503 | if (m_CompileQueue.Count==0) | ||
504 | // No scripts on region, so won't get triggered later | ||
505 | // by the queue becoming empty so we trigger it here | ||
506 | m_Scene.EventManager.TriggerEmptyScriptCompileQueue(0, String.Empty); | ||
507 | } | ||
508 | } | ||
509 | 516 | ||
510 | Object o; | 517 | if (m_CompileQueue.Count == 0) |
511 | lock (m_CompileQueue) | ||
512 | { | ||
513 | o = m_CompileQueue.Dequeue(); | ||
514 | if (o == null) | ||
515 | { | 518 | { |
516 | m_CurrentCompile = null; | 519 | // No scripts on region, so won't get triggered later |
517 | return null; | 520 | // by the queue becoming empty so we trigger it here |
521 | m_Scene.EventManager.TriggerEmptyScriptCompileQueue(0, String.Empty); | ||
518 | } | 522 | } |
519 | } | 523 | } |
520 | 524 | ||
521 | DoOnRezScript(o); | 525 | object[] o; |
526 | while (m_CompileQueue.Dequeue(out o)) | ||
527 | DoOnRezScript(o); | ||
522 | 528 | ||
529 | // NOTE: Despite having a lockless queue, this lock is required | ||
530 | // to make sure there is never no compile thread while there | ||
531 | // are still scripts to compile. This could otherwise happen | ||
532 | // due to a race condition | ||
533 | // | ||
523 | lock (m_CompileQueue) | 534 | lock (m_CompileQueue) |
524 | { | 535 | { |
525 | if (m_CompileQueue.Count > 0) | 536 | m_CurrentCompile = null; |
526 | { | ||
527 | m_CurrentCompile = m_ThreadPool.QueueWorkItem( | ||
528 | new WorkItemCallback(this.DoOnRezScriptQueue), | ||
529 | new Object[0]); | ||
530 | } | ||
531 | else | ||
532 | { | ||
533 | m_CurrentCompile = null; | ||
534 | m_Scene.EventManager.TriggerEmptyScriptCompileQueue(m_ScriptFailCount, | ||
535 | m_ScriptErrorMessage); | ||
536 | m_ScriptFailCount = 0; | ||
537 | } | ||
538 | } | 537 | } |
538 | m_Scene.EventManager.TriggerEmptyScriptCompileQueue(m_ScriptFailCount, | ||
539 | m_ScriptErrorMessage); | ||
540 | m_ScriptFailCount = 0; | ||
541 | |||
539 | return null; | 542 | return null; |
540 | } | 543 | } |
541 | 544 | ||
542 | private bool DoOnRezScript(object parm) | 545 | private bool DoOnRezScript(object[] parms) |
543 | { | 546 | { |
544 | Object[] p = (Object[])parm; | 547 | Object[] p = parms; |
545 | uint localID = (uint)p[0]; | 548 | uint localID = (uint)p[0]; |
546 | UUID itemID = (UUID)p[1]; | 549 | UUID itemID = (UUID)p[1]; |
547 | string script =(string)p[2]; | 550 | string script =(string)p[2]; |
@@ -590,14 +593,12 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
590 | { | 593 | { |
591 | lock (m_AddingAssemblies) | 594 | lock (m_AddingAssemblies) |
592 | { | 595 | { |
593 | assembly = (string)m_Compiler.PerformScriptCompile(script, | 596 | m_Compiler.PerformScriptCompile(script, assetID.ToString(), item.OwnerID, out assembly, out linemap); |
594 | assetID.ToString(), item.OwnerID); | ||
595 | if (!m_AddingAssemblies.ContainsKey(assembly)) { | 597 | if (!m_AddingAssemblies.ContainsKey(assembly)) { |
596 | m_AddingAssemblies[assembly] = 1; | 598 | m_AddingAssemblies[assembly] = 1; |
597 | } else { | 599 | } else { |
598 | m_AddingAssemblies[assembly]++; | 600 | m_AddingAssemblies[assembly]++; |
599 | } | 601 | } |
600 | linemap = m_Compiler.LineMap(); | ||
601 | } | 602 | } |
602 | 603 | ||
603 | string[] warnings = m_Compiler.GetWarnings(); | 604 | string[] warnings = m_Compiler.GetWarnings(); |
@@ -696,19 +697,22 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
696 | Evidence baseEvidence = AppDomain.CurrentDomain.Evidence; | 697 | Evidence baseEvidence = AppDomain.CurrentDomain.Evidence; |
697 | Evidence evidence = new Evidence(baseEvidence); | 698 | Evidence evidence = new Evidence(baseEvidence); |
698 | 699 | ||
699 | AppDomain sandbox = | 700 | AppDomain sandbox; |
700 | AppDomain.CreateDomain( | 701 | if (m_AppDomainLoading) |
701 | m_Scene.RegionInfo.RegionID.ToString(), | 702 | sandbox = AppDomain.CreateDomain( |
702 | evidence, appSetup); | 703 | m_Scene.RegionInfo.RegionID.ToString(), |
703 | /* | 704 | evidence, appSetup); |
704 | PolicyLevel sandboxPolicy = PolicyLevel.CreateAppDomainLevel(); | 705 | else |
705 | AllMembershipCondition sandboxMembershipCondition = new AllMembershipCondition(); | 706 | sandbox = AppDomain.CurrentDomain; |
706 | PermissionSet sandboxPermissionSet = sandboxPolicy.GetNamedPermissionSet("Internet"); | 707 | |
707 | PolicyStatement sandboxPolicyStatement = new PolicyStatement(sandboxPermissionSet); | 708 | //PolicyLevel sandboxPolicy = PolicyLevel.CreateAppDomainLevel(); |
708 | CodeGroup sandboxCodeGroup = new UnionCodeGroup(sandboxMembershipCondition, sandboxPolicyStatement); | 709 | //AllMembershipCondition sandboxMembershipCondition = new AllMembershipCondition(); |
709 | sandboxPolicy.RootCodeGroup = sandboxCodeGroup; | 710 | //PermissionSet sandboxPermissionSet = sandboxPolicy.GetNamedPermissionSet("Internet"); |
710 | sandbox.SetAppDomainPolicy(sandboxPolicy); | 711 | //PolicyStatement sandboxPolicyStatement = new PolicyStatement(sandboxPermissionSet); |
711 | */ | 712 | //CodeGroup sandboxCodeGroup = new UnionCodeGroup(sandboxMembershipCondition, sandboxPolicyStatement); |
713 | //sandboxPolicy.RootCodeGroup = sandboxCodeGroup; | ||
714 | //sandbox.SetAppDomainPolicy(sandboxPolicy); | ||
715 | |||
712 | m_AppDomains[appDomain] = sandbox; | 716 | m_AppDomains[appDomain] = sandbox; |
713 | 717 | ||
714 | m_AppDomains[appDomain].AssemblyResolve += | 718 | m_AppDomains[appDomain].AssemblyResolve += |
@@ -905,9 +909,10 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
905 | AppDomain domain = m_AppDomains[id]; | 909 | AppDomain domain = m_AppDomains[id]; |
906 | m_AppDomains.Remove(id); | 910 | m_AppDomains.Remove(id); |
907 | 911 | ||
908 | AppDomain.Unload(domain); | 912 | if (domain != AppDomain.CurrentDomain) |
913 | AppDomain.Unload(domain); | ||
909 | domain = null; | 914 | domain = null; |
910 | // m_log.DebugFormat("[XEngine] Unloaded app domain {0}", id.ToString()); | 915 | // m_log.DebugFormat("[XEngine] Unloaded app domain {0}", id.ToString()); |
911 | } | 916 | } |
912 | } | 917 | } |
913 | 918 | ||