aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ScriptEngine/XEngine
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/ScriptEngine/XEngine')
-rw-r--r--OpenSim/Region/ScriptEngine/XEngine/Tests/XEngineTest.cs2
-rw-r--r--OpenSim/Region/ScriptEngine/XEngine/XEngine.cs142
2 files changed, 115 insertions, 29 deletions
diff --git a/OpenSim/Region/ScriptEngine/XEngine/Tests/XEngineTest.cs b/OpenSim/Region/ScriptEngine/XEngine/Tests/XEngineTest.cs
index f331658..5abfe9a 100644
--- a/OpenSim/Region/ScriptEngine/XEngine/Tests/XEngineTest.cs
+++ b/OpenSim/Region/ScriptEngine/XEngine/Tests/XEngineTest.cs
@@ -44,7 +44,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine.Tests
44 /// XEngine tests. 44 /// XEngine tests.
45 /// </summary> 45 /// </summary>
46 [TestFixture] 46 [TestFixture]
47 public class XEngineTest 47 public class XEngineTest : OpenSimTestCase
48 { 48 {
49 private TestScene m_scene; 49 private TestScene m_scene;
50 private XEngine m_xEngine; 50 private XEngine m_xEngine;
diff --git a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs
index 9f05666..05dd7ab 100644
--- a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs
+++ b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs
@@ -31,6 +31,7 @@ using System.Collections.Generic;
31using System.Diagnostics; //for [DebuggerNonUserCode] 31using System.Diagnostics; //for [DebuggerNonUserCode]
32using System.Globalization; 32using System.Globalization;
33using System.IO; 33using System.IO;
34using System.Linq;
34using System.Reflection; 35using System.Reflection;
35using System.Security; 36using System.Security;
36using System.Security.Policy; 37using System.Security.Policy;
@@ -107,6 +108,24 @@ namespace OpenSim.Region.ScriptEngine.XEngine
107 private IXmlRpcRouter m_XmlRpcRouter; 108 private IXmlRpcRouter m_XmlRpcRouter;
108 private int m_EventLimit; 109 private int m_EventLimit;
109 private bool m_KillTimedOutScripts; 110 private bool m_KillTimedOutScripts;
111
112 /// <summary>
113 /// Number of milliseconds we will wait for a script event to complete on script stop before we forcibly abort
114 /// its thread.
115 /// </summary>
116 /// <remarks>
117 /// It appears that if a script thread is aborted whilst it is holding ReaderWriterLockSlim (possibly the write
118 /// lock) then the lock is not properly released. This causes mono 2.6, 2.10 and possibly
119 /// later to crash, sometimes with symptoms such as a leap to 100% script usage and a vm thead dump showing
120 /// all threads waiting on release of ReaderWriterLockSlim write thread which none of the threads listed
121 /// actually hold.
122 ///
123 /// Pausing for event completion reduces the risk of this happening. However, it may be that aborting threads
124 /// is not a mono issue per se but rather a risky activity in itself in an AppDomain that is not immediately
125 /// shutting down.
126 /// </remarks>
127 private int m_WaitForEventCompletionOnScriptStop = 1000;
128
110 private string m_ScriptEnginesPath = null; 129 private string m_ScriptEnginesPath = null;
111 130
112 private ExpiringCache<UUID, bool> m_runFlags = new ExpiringCache<UUID, bool>(); 131 private ExpiringCache<UUID, bool> m_runFlags = new ExpiringCache<UUID, bool>();
@@ -316,6 +335,9 @@ namespace OpenSim.Region.ScriptEngine.XEngine
316 m_EventLimit = m_ScriptConfig.GetInt("EventLimit", 30); 335 m_EventLimit = m_ScriptConfig.GetInt("EventLimit", 30);
317 m_KillTimedOutScripts = m_ScriptConfig.GetBoolean("KillTimedOutScripts", false); 336 m_KillTimedOutScripts = m_ScriptConfig.GetBoolean("KillTimedOutScripts", false);
318 m_SaveTime = m_ScriptConfig.GetInt("SaveInterval", 120) * 1000; 337 m_SaveTime = m_ScriptConfig.GetInt("SaveInterval", 120) * 1000;
338 m_WaitForEventCompletionOnScriptStop
339 = m_ScriptConfig.GetInt("WaitForEventCompletionOnScriptStop", m_WaitForEventCompletionOnScriptStop);
340
319 m_ScriptEnginesPath = m_ScriptConfig.GetString("ScriptEnginesPath", "ScriptEngines"); 341 m_ScriptEnginesPath = m_ScriptConfig.GetString("ScriptEnginesPath", "ScriptEngines");
320 342
321 m_Prio = ThreadPriority.BelowNormal; 343 m_Prio = ThreadPriority.BelowNormal;
@@ -371,7 +393,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine
371 393
372 MainConsole.Instance.Commands.AddCommand( 394 MainConsole.Instance.Commands.AddCommand(
373 "Scripts", false, "scripts show", "scripts show [<script-item-uuid>]", "Show script information", 395 "Scripts", false, "scripts show", "scripts show [<script-item-uuid>]", "Show script information",
374 "Show information on all scripts known to the script engine." 396 "Show information on all scripts known to the script engine.\n"
375 + "If a <script-item-uuid> is given then only information on that script will be shown.", 397 + "If a <script-item-uuid> is given then only information on that script will be shown.",
376 HandleShowScripts); 398 HandleShowScripts);
377 399
@@ -390,22 +412,30 @@ namespace OpenSim.Region.ScriptEngine.XEngine
390 MainConsole.Instance.Commands.AddCommand( 412 MainConsole.Instance.Commands.AddCommand(
391 "Scripts", false, "scripts resume", "scripts resume [<script-item-uuid>]", "Resumes all suspended scripts", 413 "Scripts", false, "scripts resume", "scripts resume [<script-item-uuid>]", "Resumes all suspended scripts",
392 "Resumes all currently suspended scripts.\n" 414 "Resumes all currently suspended scripts.\n"
393 + "Resumed scripts will process all events accumulated whilst suspended." 415 + "Resumed scripts will process all events accumulated whilst suspended.\n"
394 + "If a <script-item-uuid> is given then only that script will be resumed. Otherwise, all suitable scripts are resumed.", 416 + "If a <script-item-uuid> is given then only that script will be resumed. Otherwise, all suitable scripts are resumed.",
395 (module, cmdparams) => HandleScriptsAction(cmdparams, HandleResumeScript)); 417 (module, cmdparams) => HandleScriptsAction(cmdparams, HandleResumeScript));
396 418
397 MainConsole.Instance.Commands.AddCommand( 419 MainConsole.Instance.Commands.AddCommand(
398 "Scripts", false, "scripts stop", "scripts stop [<script-item-uuid>]", "Stops all running scripts", 420 "Scripts", false, "scripts stop", "scripts stop [<script-item-uuid>]", "Stops all running scripts",
399 "Stops all running scripts." 421 "Stops all running scripts.\n"
400 + "If a <script-item-uuid> is given then only that script will be stopped. Otherwise, all suitable scripts are stopped.", 422 + "If a <script-item-uuid> is given then only that script will be stopped. Otherwise, all suitable scripts are stopped.",
401 (module, cmdparams) => HandleScriptsAction(cmdparams, HandleStopScript)); 423 (module, cmdparams) => HandleScriptsAction(cmdparams, HandleStopScript));
402 424
403 MainConsole.Instance.Commands.AddCommand( 425 MainConsole.Instance.Commands.AddCommand(
404 "Scripts", false, "scripts start", "scripts start [<script-item-uuid>]", "Starts all stopped scripts", 426 "Scripts", false, "scripts start", "scripts start [<script-item-uuid>]", "Starts all stopped scripts",
405 "Starts all stopped scripts." 427 "Starts all stopped scripts.\n"
406 + "If a <script-item-uuid> is given then only that script will be started. Otherwise, all suitable scripts are started.", 428 + "If a <script-item-uuid> is given then only that script will be started. Otherwise, all suitable scripts are started.",
407 (module, cmdparams) => HandleScriptsAction(cmdparams, HandleStartScript)); 429 (module, cmdparams) => HandleScriptsAction(cmdparams, HandleStartScript));
408 430
431 MainConsole.Instance.Commands.AddCommand(
432 "Scripts", false, "debug script log", "debug scripts log <item-id> <log-level>", "Extra debug logging for a script",
433 "Activates or deactivates extra debug logging for the given script.\n"
434 + "Level == 0, deactivate extra debug logging.\n"
435 + "Level >= 1, log state changes.\n"
436 + "Level >= 2, log event invocations.\n",
437 HandleDebugScriptLogCommand);
438
409// MainConsole.Instance.Commands.AddCommand( 439// MainConsole.Instance.Commands.AddCommand(
410// "Debug", false, "debug xengine", "debug xengine [<level>]", 440// "Debug", false, "debug xengine", "debug xengine [<level>]",
411// "Turn on detailed xengine debugging.", 441// "Turn on detailed xengine debugging.",
@@ -414,6 +444,41 @@ namespace OpenSim.Region.ScriptEngine.XEngine
414// HandleDebugLevelCommand); 444// HandleDebugLevelCommand);
415 } 445 }
416 446
447 private void HandleDebugScriptLogCommand(string module, string[] args)
448 {
449 if (!(MainConsole.Instance.ConsoleScene == null || MainConsole.Instance.ConsoleScene == m_Scene))
450 return;
451
452 if (args.Length != 5)
453 {
454 MainConsole.Instance.Output("Usage: debug script log <item-id> <log-level>");
455 return;
456 }
457
458 UUID itemId;
459
460 if (!ConsoleUtil.TryParseConsoleUuid(MainConsole.Instance, args[3], out itemId))
461 return;
462
463 int newLevel;
464
465 if (!ConsoleUtil.TryParseConsoleInt(MainConsole.Instance, args[4], out newLevel))
466 return;
467
468 IScriptInstance si;
469
470 lock (m_Scripts)
471 {
472 // XXX: We can't give the user feedback on a bad item id because this may apply to a different script
473 // engine
474 if (!m_Scripts.TryGetValue(itemId, out si))
475 return;
476 }
477
478 si.DebugLevel = newLevel;
479 MainConsole.Instance.OutputFormat("Set debug level of {0} {1} to {2}", si.ScriptName, si.ItemID, newLevel);
480 }
481
417 /// <summary> 482 /// <summary>
418 /// Change debug level 483 /// Change debug level
419 /// </summary> 484 /// </summary>
@@ -445,9 +510,21 @@ namespace OpenSim.Region.ScriptEngine.XEngine
445 /// </summary> 510 /// </summary>
446 /// <param name="cmdparams"></param> 511 /// <param name="cmdparams"></param>
447 /// <param name="instance"></param> 512 /// <param name="instance"></param>
448 /// <returns>true if we're okay to proceed, false if not.</returns> 513 /// <param name="comparer">Basis on which to sort output. Can be null if no sort needs to take place</param>
449 private void HandleScriptsAction(string[] cmdparams, Action<IScriptInstance> action) 514 private void HandleScriptsAction(string[] cmdparams, Action<IScriptInstance> action)
450 { 515 {
516 HandleScriptsAction<object>(cmdparams, action, null);
517 }
518
519 /// <summary>
520 /// Parse the raw item id into a script instance from the command params if it's present.
521 /// </summary>
522 /// <param name="cmdparams"></param>
523 /// <param name="instance"></param>
524 /// <param name="keySelector">Basis on which to sort output. Can be null if no sort needs to take place</param>
525 private void HandleScriptsAction<TKey>(
526 string[] cmdparams, Action<IScriptInstance> action, Func<IScriptInstance, TKey> keySelector)
527 {
451 if (!(MainConsole.Instance.ConsoleScene == null || MainConsole.Instance.ConsoleScene == m_Scene)) 528 if (!(MainConsole.Instance.ConsoleScene == null || MainConsole.Instance.ConsoleScene == m_Scene))
452 return; 529 return;
453 530
@@ -458,7 +535,12 @@ namespace OpenSim.Region.ScriptEngine.XEngine
458 535
459 if (cmdparams.Length == 2) 536 if (cmdparams.Length == 2)
460 { 537 {
461 foreach (IScriptInstance instance in m_Scripts.Values) 538 IEnumerable<IScriptInstance> scripts = m_Scripts.Values;
539
540 if (keySelector != null)
541 scripts = scripts.OrderBy<IScriptInstance, TKey>(keySelector);
542
543 foreach (IScriptInstance instance in scripts)
462 action(instance); 544 action(instance);
463 545
464 return; 546 return;
@@ -468,7 +550,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine
468 550
469 if (!UUID.TryParse(rawItemId, out itemId)) 551 if (!UUID.TryParse(rawItemId, out itemId))
470 { 552 {
471 MainConsole.Instance.OutputFormat("Error - {0} is not a valid UUID", rawItemId); 553 MainConsole.Instance.OutputFormat("ERROR: {0} is not a valid UUID", rawItemId);
472 return; 554 return;
473 } 555 }
474 556
@@ -505,9 +587,20 @@ namespace OpenSim.Region.ScriptEngine.XEngine
505 StringBuilder sb = new StringBuilder(); 587 StringBuilder sb = new StringBuilder();
506 sb.AppendFormat("Status of XEngine instance for {0}\n", m_Scene.RegionInfo.RegionName); 588 sb.AppendFormat("Status of XEngine instance for {0}\n", m_Scene.RegionInfo.RegionName);
507 589
590 long scriptsLoaded, eventsQueued = 0, eventsProcessed = 0;
591
508 lock (m_Scripts) 592 lock (m_Scripts)
509 sb.AppendFormat("Scripts loaded : {0}\n", m_Scripts.Count); 593 {
594 scriptsLoaded = m_Scripts.Count;
595
596 foreach (IScriptInstance si in m_Scripts.Values)
597 {
598 eventsQueued += si.EventsQueued;
599 eventsProcessed += si.EventsProcessed;
600 }
601 }
510 602
603 sb.AppendFormat("Scripts loaded : {0}\n", scriptsLoaded);
511 sb.AppendFormat("Unique scripts : {0}\n", m_uniqueScripts.Count); 604 sb.AppendFormat("Unique scripts : {0}\n", m_uniqueScripts.Count);
512 sb.AppendFormat("Scripts waiting for load : {0}\n", m_CompileQueue.Count); 605 sb.AppendFormat("Scripts waiting for load : {0}\n", m_CompileQueue.Count);
513 sb.AppendFormat("Max threads : {0}\n", m_ThreadPool.MaxThreads); 606 sb.AppendFormat("Max threads : {0}\n", m_ThreadPool.MaxThreads);
@@ -516,6 +609,8 @@ namespace OpenSim.Region.ScriptEngine.XEngine
516 sb.AppendFormat("In use threads : {0}\n", m_ThreadPool.InUseThreads); 609 sb.AppendFormat("In use threads : {0}\n", m_ThreadPool.InUseThreads);
517 sb.AppendFormat("Work items waiting : {0}\n", m_ThreadPool.WaitingCallbacks); 610 sb.AppendFormat("Work items waiting : {0}\n", m_ThreadPool.WaitingCallbacks);
518// sb.AppendFormat("Assemblies loaded : {0}\n", m_Assemblies.Count); 611// sb.AppendFormat("Assemblies loaded : {0}\n", m_Assemblies.Count);
612 sb.AppendFormat("Events queued : {0}\n", eventsQueued);
613 sb.AppendFormat("Events processed : {0}\n", eventsProcessed);
519 614
520 SensorRepeat sr = AsyncCommandManager.GetSensorRepeatPlugin(this); 615 SensorRepeat sr = AsyncCommandManager.GetSensorRepeatPlugin(this);
521 sb.AppendFormat("Sensors : {0}\n", sr != null ? sr.SensorsCount : 0); 616 sb.AppendFormat("Sensors : {0}\n", sr != null ? sr.SensorsCount : 0);
@@ -546,7 +641,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine
546 } 641 }
547 } 642 }
548 643
549 HandleScriptsAction(cmdparams, HandleShowScript); 644 HandleScriptsAction<long>(cmdparams, HandleShowScript, si => si.EventsProcessed);
550 } 645 }
551 646
552 private void HandleShowScript(IScriptInstance instance) 647 private void HandleShowScript(IScriptInstance instance)
@@ -576,11 +671,10 @@ namespace OpenSim.Region.ScriptEngine.XEngine
576 671
577 sb.AppendFormat("Script name : {0}\n", instance.ScriptName); 672 sb.AppendFormat("Script name : {0}\n", instance.ScriptName);
578 sb.AppendFormat("Status : {0}\n", status); 673 sb.AppendFormat("Status : {0}\n", status);
579 674 sb.AppendFormat("Queued events : {0}\n", instance.EventsQueued);
580 lock (eq) 675 sb.AppendFormat("Processed events : {0}\n", instance.EventsProcessed);
581 sb.AppendFormat("Queued events : {0}\n", eq.Count);
582
583 sb.AppendFormat("Item UUID : {0}\n", instance.ItemID); 676 sb.AppendFormat("Item UUID : {0}\n", instance.ItemID);
677 sb.AppendFormat("Asset UUID : {0}\n", instance.AssetID);
584 sb.AppendFormat("Containing part name: {0}\n", instance.PrimName); 678 sb.AppendFormat("Containing part name: {0}\n", instance.PrimName);
585 sb.AppendFormat("Containing part UUID: {0}\n", instance.ObjectID); 679 sb.AppendFormat("Containing part UUID: {0}\n", instance.ObjectID);
586 sb.AppendFormat("Position : {0}\n", sop.AbsolutePosition); 680 sb.AppendFormat("Position : {0}\n", sop.AbsolutePosition);
@@ -1089,8 +1183,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine
1089 1183
1090 string assembly = ""; 1184 string assembly = "";
1091 1185
1092 CultureInfo USCulture = new CultureInfo("en-US"); 1186 Culture.SetCurrentCulture();
1093 Thread.CurrentThread.CurrentCulture = USCulture;
1094 1187
1095 Dictionary<KeyValuePair<int, int>, KeyValuePair<int, int>> linemap; 1188 Dictionary<KeyValuePair<int, int>, KeyValuePair<int, int>> linemap;
1096 1189
@@ -1347,9 +1440,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine
1347 lockScriptsForWrite(false); 1440 lockScriptsForWrite(false);
1348 instance.ClearQueue(); 1441 instance.ClearQueue();
1349 1442
1350 // Give the script some time to finish processing its last event. Simply aborting the script thread can 1443 instance.Stop(m_WaitForEventCompletionOnScriptStop);
1351 // cause issues on mono 2.6, 2.10 and possibly later where locks are not released properly on abort.
1352 instance.Stop(1000);
1353 1444
1354// bool objectRemoved = false; 1445// bool objectRemoved = false;
1355 1446
@@ -1485,6 +1576,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine
1485 startInfo.StartSuspended = true; 1576 startInfo.StartSuspended = true;
1486 1577
1487 m_ThreadPool = new SmartThreadPool(startInfo); 1578 m_ThreadPool = new SmartThreadPool(startInfo);
1579 m_ThreadPool.Name = "XEngine";
1488 } 1580 }
1489 1581
1490 // 1582 //
@@ -1504,8 +1596,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine
1504 /// <returns></returns> 1596 /// <returns></returns>
1505 private object ProcessEventHandler(object parms) 1597 private object ProcessEventHandler(object parms)
1506 { 1598 {
1507 CultureInfo USCulture = new CultureInfo("en-US"); 1599 Culture.SetCurrentCulture();
1508 Thread.CurrentThread.CurrentCulture = USCulture;
1509 1600
1510 IScriptInstance instance = (ScriptInstance) parms; 1601 IScriptInstance instance = (ScriptInstance) parms;
1511 1602
@@ -1693,7 +1784,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine
1693 { 1784 {
1694 IScriptInstance instance = GetInstance(itemID); 1785 IScriptInstance instance = GetInstance(itemID);
1695 if (instance != null) 1786 if (instance != null)
1696 instance.ResetScript(); 1787 instance.ResetScript(m_WaitForEventCompletionOnScriptStop);
1697 } 1788 }
1698 1789
1699 public void StartScript(UUID itemID) 1790 public void StartScript(UUID itemID)
@@ -1708,16 +1799,11 @@ namespace OpenSim.Region.ScriptEngine.XEngine
1708 public void StopScript(UUID itemID) 1799 public void StopScript(UUID itemID)
1709 { 1800 {
1710 IScriptInstance instance = GetInstance(itemID); 1801 IScriptInstance instance = GetInstance(itemID);
1802
1711 if (instance != null) 1803 if (instance != null)
1712 { 1804 instance.Stop(m_WaitForEventCompletionOnScriptStop);
1713 // Give the script some time to finish processing its last event. Simply aborting the script thread can
1714 // cause issues on mono 2.6, 2.10 and possibly later where locks are not released properly on abort.
1715 instance.Stop(1000);
1716 }
1717 else 1805 else
1718 {
1719 m_runFlags.AddOrUpdate(itemID, false, 240); 1806 m_runFlags.AddOrUpdate(itemID, false, 240);
1720 }
1721 } 1807 }
1722 1808
1723 public DetectParams GetDetectParams(UUID itemID, int idx) 1809 public DetectParams GetDetectParams(UUID itemID, int idx)