From c8afc8523b9caf931afb3d5b3f9874b26b866a77 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Thu, 17 Jan 2013 23:39:09 +0000 Subject: [PATCH 01/17] Implement non-wait co-operative termination of scripts for XEngine in addition to termination on wait. This involves inserting opensim_reserved_CheckForCoopTermination() calls in lsl -> c# translation at any place where the script could be in a loop with no wait calls. These places are for, while, do-while, label, user function call and manual event function call. Call goes through to an XEngineScriptBase which extends ScriptBase. IEngine is extended to supply necessary engine-specific parent class references and constructor parameters to Compiler. Unfortunately, since XEngineScriptBase has to be passed WaitHandle in its constructor, older compiled scripts will fail to load with an error on the OpenSim console. Such scripts will need to be recompiled, either by removing all *.dll files from the bin/ScriptEngines/ or by setting DeleteScriptsOnStartup = true in [XEngine] for one run. Automatic recompilation may be implemented in a later commit. This feature should not yet be used, default remains termination with Thread.Abort() which will work as normal once scripts are recompiled. --- .../ScriptEngine/Interfaces/IScriptEngine.cs | 35 ++++- .../Shared/Api/Implementation/LSL_Api.cs | 12 +- .../Shared/CodeTools/CSCodeGenerator.cs | 133 ++++++++++++------ .../ScriptEngine/Shared/CodeTools/Compiler.cs | 66 ++++++--- .../Shared/Instance/ScriptInstance.cs | 24 +++- .../XEngine/Api/Runtime/XEngineScriptBase.cs | 61 ++++++++ .../Region/ScriptEngine/XEngine/XEngine.cs | 17 ++- prebuild.xml | 36 +++++ 8 files changed, 307 insertions(+), 77 deletions(-) create mode 100644 OpenSim/Region/ScriptEngine/XEngine/Api/Runtime/XEngineScriptBase.cs diff --git a/OpenSim/Region/ScriptEngine/Interfaces/IScriptEngine.cs b/OpenSim/Region/ScriptEngine/Interfaces/IScriptEngine.cs index 17c270810f..20dcac9855 100644 --- a/OpenSim/Region/ScriptEngine/Interfaces/IScriptEngine.cs +++ b/OpenSim/Region/ScriptEngine/Interfaces/IScriptEngine.cs @@ -25,16 +25,17 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -using log4net; using System; -using OpenSim.Region.ScriptEngine.Shared; +using System.Reflection; +using OpenSim.Framework; using OpenSim.Region.Framework.Scenes; using OpenSim.Region.Framework.Interfaces; -using OpenMetaverse; -using Nini.Config; using OpenSim.Region.ScriptEngine.Interfaces; +using OpenSim.Region.ScriptEngine.Shared; using Amib.Threading; -using OpenSim.Framework; +using log4net; +using Nini.Config; +using OpenMetaverse; namespace OpenSim.Region.ScriptEngine.Interfaces { @@ -76,6 +77,30 @@ namespace OpenSim.Region.ScriptEngine.Interfaces IConfigSource ConfigSource { get; } string ScriptEngineName { get; } string ScriptEnginePath { get; } + + /// + /// Return the name of the base class that will be used for all running scripts. + /// + string ScriptBaseClassName { get; } + + /// + /// Assemblies that need to be referenced when compiling scripts. + /// + /// + /// These are currently additional to those always referenced by the compiler, BUT THIS MAY CHANGE IN THE + /// FUTURE. + /// This can be null if there are no additional assemblies. + /// + string[] ScriptReferencedAssemblies { get; } + + /// + /// Parameters for the generated script's constructor. + /// + /// + /// Can be null if there are no parameters + /// + ParameterInfo[] ScriptBaseClassParameters { get; } + IScriptApi GetApi(UUID itemID, string name); } } diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index d47fd6b5ac..cee10a8e6e 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -192,7 +192,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { if (m_coopSleepHandle == null) System.Threading.Thread.Sleep(delay); - else if (m_coopSleepHandle.WaitOne(delay)) + else + CheckForCoopTermination(delay); + } + + /// + /// Check for co-operative termination. + /// + /// If called with 0, then just the check is performed with no wait. + protected virtual void CheckForCoopTermination(int delay) + { + if (m_coopSleepHandle.WaitOne(delay)) throw new ScriptCoopStopException(); } diff --git a/OpenSim/Region/ScriptEngine/Shared/CodeTools/CSCodeGenerator.cs b/OpenSim/Region/ScriptEngine/Shared/CodeTools/CSCodeGenerator.cs index 97dd0f6122..002f9b8a44 100644 --- a/OpenSim/Region/ScriptEngine/Shared/CodeTools/CSCodeGenerator.cs +++ b/OpenSim/Region/ScriptEngine/Shared/CodeTools/CSCodeGenerator.cs @@ -49,6 +49,18 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools private List m_warnings = new List(); private IScriptModuleComms m_comms = null; + private bool m_insertCoopTerminationChecks; + private static string m_coopTerminationCheck = "opensim_reserved_CheckForCoopTermination();"; + + /// + /// Keep a record of the previous node when we do the parsing. + /// + /// + /// We do this here because the parser generated by CSTools does not retain a reference to its parent node. + /// The previous node is required so we can correctly insert co-op termination checks when required. + /// +// private SYMBOL m_previousNode; + /// /// Creates an 'empty' CSCodeGenerator instance. /// @@ -58,9 +70,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools ResetCounters(); } - public CSCodeGenerator(IScriptModuleComms comms) + public CSCodeGenerator(IScriptModuleComms comms, bool insertCoopTerminationChecks) { m_comms = comms; + m_insertCoopTerminationChecks = insertCoopTerminationChecks; ResetCounters(); } @@ -155,7 +168,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools // here's the payload retstr += GenerateLine(); foreach (SYMBOL s in m_astRoot.kids) - retstr += GenerateNode(s); + retstr += GenerateNode(m_astRoot, s); // close braces! m_braceCount--; @@ -165,7 +178,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools // Removes all carriage return characters which may be generated in Windows platform. Is there // cleaner way of doing this? - retstr=retstr.Replace("\r", ""); + retstr = retstr.Replace("\r", ""); return retstr; } @@ -191,9 +204,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools /// Recursively called to generate each type of node. Will generate this /// node, then all it's children. /// + /// The parent node. /// The current node to generate code for. /// String containing C# code for SYMBOL s. - private string GenerateNode(SYMBOL s) + private string GenerateNode(SYMBOL previousSymbol, SYMBOL s) { string retstr = String.Empty; @@ -207,11 +221,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools else if (s is State) retstr += GenerateState((State) s); else if (s is CompoundStatement) - retstr += GenerateCompoundStatement((CompoundStatement) s); + retstr += GenerateCompoundStatement(previousSymbol, (CompoundStatement) s); else if (s is Declaration) retstr += GenerateDeclaration((Declaration) s); else if (s is Statement) - retstr += GenerateStatement((Statement) s); + retstr += GenerateStatement(previousSymbol, (Statement) s); else if (s is ReturnStatement) retstr += GenerateReturnStatement((ReturnStatement) s); else if (s is JumpLabel) @@ -261,7 +275,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools else { foreach (SYMBOL kid in s.kids) - retstr += GenerateNode(kid); + retstr += GenerateNode(s, kid); } return retstr; @@ -295,7 +309,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools retstr += GenerateLine(")"); foreach (SYMBOL kid in remainingKids) - retstr += GenerateNode(kid); + retstr += GenerateNode(gf, kid); return retstr; } @@ -312,7 +326,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools foreach (SYMBOL s in gv.kids) { retstr += Indent(); - retstr += GenerateNode(s); + retstr += GenerateNode(gv, s); retstr += GenerateLine(";"); } @@ -365,7 +379,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools retstr += GenerateLine(")"); foreach (SYMBOL kid in remainingKids) - retstr += GenerateNode(kid); + retstr += GenerateNode(se, kid); return retstr; } @@ -404,7 +418,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools foreach (SYMBOL s in al.kids) { - retstr += GenerateNode(s); + retstr += GenerateNode(al, s); if (0 < comma--) retstr += Generate(", "); } @@ -417,7 +431,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools /// /// The CompoundStatement node. /// String containing C# code for CompoundStatement cs. - private string GenerateCompoundStatement(CompoundStatement cs) + private string GenerateCompoundStatement(SYMBOL previousSymbol, CompoundStatement cs) { string retstr = String.Empty; @@ -425,8 +439,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools retstr += GenerateIndentedLine("{"); m_braceCount++; + if (m_insertCoopTerminationChecks) + { + // We have to check in event functions as well because the user can manually call these. + if (previousSymbol is GlobalFunctionDefinition + || previousSymbol is WhileStatement + || previousSymbol is DoWhileStatement + || previousSymbol is ForLoopStatement + || previousSymbol is StateEvent) + retstr += GenerateIndentedLine(m_coopTerminationCheck); + } + foreach (SYMBOL kid in cs.kids) - retstr += GenerateNode(kid); + retstr += GenerateNode(cs, kid); // closing brace m_braceCount--; @@ -450,13 +475,24 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools /// /// The Statement node. /// String containing C# code for Statement s. - private string GenerateStatement(Statement s) + private string GenerateStatement(SYMBOL previousSymbol, Statement s) { string retstr = String.Empty; bool printSemicolon = true; retstr += Indent(); + if (m_insertCoopTerminationChecks) + { + // We have to check in event functions as well because the user can manually call these. + if (previousSymbol is GlobalFunctionDefinition + || previousSymbol is WhileStatement + || previousSymbol is DoWhileStatement + || previousSymbol is ForLoop + || previousSymbol is StateEvent) + retstr += Generate(m_coopTerminationCheck); + } + if (0 < s.kids.Count) { // Jump label prints its own colon, we don't need a semicolon. @@ -466,7 +502,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools // (MONO) error. if (!(s.kids.Top is IdentExpression && 1 == s.kids.Count)) foreach (SYMBOL kid in s.kids) - retstr += GenerateNode(kid); + retstr += GenerateNode(s, kid); } if (printSemicolon) @@ -487,10 +523,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools List identifiers = new List(); checkForMultipleAssignments(identifiers, a); - retstr += GenerateNode((SYMBOL) a.kids.Pop()); + retstr += GenerateNode(a, (SYMBOL) a.kids.Pop()); retstr += Generate(String.Format(" {0} ", a.AssignmentType), a); foreach (SYMBOL kid in a.kids) - retstr += GenerateNode(kid); + retstr += GenerateNode(a, kid); return retstr; } @@ -563,7 +599,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools retstr += Generate("return ", rs); foreach (SYMBOL kid in rs.kids) - retstr += GenerateNode(kid); + retstr += GenerateNode(rs, kid); return retstr; } @@ -575,7 +611,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools /// String containing C# code for JumpLabel jl. private string GenerateJumpLabel(JumpLabel jl) { - return Generate(String.Format("{0}:", CheckName(jl.LabelName)), jl) + " NoOp();\n"; + string labelStatement; + + if (m_insertCoopTerminationChecks) + labelStatement = m_coopTerminationCheck + "\n"; + else + labelStatement = "NoOp();\n"; + + return Generate(String.Format("{0}: ", CheckName(jl.LabelName)), jl) + labelStatement; } /// @@ -598,14 +641,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools string retstr = String.Empty; retstr += GenerateIndented("if (", ifs); - retstr += GenerateNode((SYMBOL) ifs.kids.Pop()); + retstr += GenerateNode(ifs, (SYMBOL) ifs.kids.Pop()); retstr += GenerateLine(")"); // CompoundStatement handles indentation itself but we need to do it // otherwise. bool indentHere = ifs.kids.Top is Statement; if (indentHere) m_braceCount++; - retstr += GenerateNode((SYMBOL) ifs.kids.Pop()); + retstr += GenerateNode(ifs, (SYMBOL) ifs.kids.Pop()); if (indentHere) m_braceCount--; if (0 < ifs.kids.Count) // do it again for an else @@ -614,7 +657,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools indentHere = ifs.kids.Top is Statement; if (indentHere) m_braceCount++; - retstr += GenerateNode((SYMBOL) ifs.kids.Pop()); + retstr += GenerateNode(ifs, (SYMBOL) ifs.kids.Pop()); if (indentHere) m_braceCount--; } @@ -641,14 +684,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools string retstr = String.Empty; retstr += GenerateIndented("while (", ws); - retstr += GenerateNode((SYMBOL) ws.kids.Pop()); + retstr += GenerateNode(ws, (SYMBOL) ws.kids.Pop()); retstr += GenerateLine(")"); // CompoundStatement handles indentation itself but we need to do it // otherwise. bool indentHere = ws.kids.Top is Statement; if (indentHere) m_braceCount++; - retstr += GenerateNode((SYMBOL) ws.kids.Pop()); + retstr += GenerateNode(ws, (SYMBOL) ws.kids.Pop()); if (indentHere) m_braceCount--; return retstr; @@ -669,11 +712,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools // otherwise. bool indentHere = dws.kids.Top is Statement; if (indentHere) m_braceCount++; - retstr += GenerateNode((SYMBOL) dws.kids.Pop()); + retstr += GenerateNode(dws, (SYMBOL) dws.kids.Pop()); if (indentHere) m_braceCount--; retstr += GenerateIndented("while (", dws); - retstr += GenerateNode((SYMBOL) dws.kids.Pop()); + retstr += GenerateNode(dws, (SYMBOL) dws.kids.Pop()); retstr += GenerateLine(");"); return retstr; @@ -702,7 +745,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools retstr += Generate("; "); // for (x = 0; x < 10; x++) // ^^^^^^ - retstr += GenerateNode((SYMBOL) fl.kids.Pop()); + retstr += GenerateNode(fl, (SYMBOL) fl.kids.Pop()); retstr += Generate("; "); // for (x = 0; x < 10; x++) // ^^^ @@ -713,7 +756,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools // otherwise. bool indentHere = fl.kids.Top is Statement; if (indentHere) m_braceCount++; - retstr += GenerateNode((SYMBOL) fl.kids.Pop()); + retstr += GenerateNode(fl, (SYMBOL) fl.kids.Pop()); if (indentHere) m_braceCount--; return retstr; @@ -758,7 +801,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools while (s is ParenthesisExpression) s = (SYMBOL)s.kids.Pop(); - retstr += GenerateNode(s); + retstr += GenerateNode(fls, s); if (0 < comma--) retstr += Generate(", "); } @@ -779,20 +822,20 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools { // special case handling for logical and/or, see Mantis 3174 retstr += "((bool)("; - retstr += GenerateNode((SYMBOL)be.kids.Pop()); + retstr += GenerateNode(be, (SYMBOL)be.kids.Pop()); retstr += "))"; retstr += Generate(String.Format(" {0} ", be.ExpressionSymbol.Substring(0,1)), be); retstr += "((bool)("; foreach (SYMBOL kid in be.kids) - retstr += GenerateNode(kid); + retstr += GenerateNode(be, kid); retstr += "))"; } else { - retstr += GenerateNode((SYMBOL)be.kids.Pop()); + retstr += GenerateNode(be, (SYMBOL)be.kids.Pop()); retstr += Generate(String.Format(" {0} ", be.ExpressionSymbol), be); foreach (SYMBOL kid in be.kids) - retstr += GenerateNode(kid); + retstr += GenerateNode(be, kid); } return retstr; @@ -808,7 +851,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools string retstr = String.Empty; retstr += Generate(ue.UnarySymbol, ue); - retstr += GenerateNode((SYMBOL) ue.kids.Pop()); + retstr += GenerateNode(ue, (SYMBOL) ue.kids.Pop()); return retstr; } @@ -824,7 +867,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools retstr += Generate("("); foreach (SYMBOL kid in pe.kids) - retstr += GenerateNode(kid); + retstr += GenerateNode(pe, kid); retstr += Generate(")"); return retstr; @@ -861,7 +904,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools // we wrap all typecasted statements in parentheses retstr += Generate(String.Format("({0}) (", te.TypecastType), te); - retstr += GenerateNode((SYMBOL) te.kids.Pop()); + retstr += GenerateNode(te, (SYMBOL) te.kids.Pop()); retstr += Generate(")"); return retstr; @@ -931,7 +974,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools } foreach (SYMBOL kid in fc.kids) - retstr += GenerateNode(kid); + retstr += GenerateNode(fc, kid); retstr += Generate(")"); @@ -980,11 +1023,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools string retstr = String.Empty; retstr += Generate(String.Format("new {0}(", vc.Type), vc); - retstr += GenerateNode((SYMBOL) vc.kids.Pop()); + retstr += GenerateNode(vc, (SYMBOL) vc.kids.Pop()); retstr += Generate(", "); - retstr += GenerateNode((SYMBOL) vc.kids.Pop()); + retstr += GenerateNode(vc, (SYMBOL) vc.kids.Pop()); retstr += Generate(", "); - retstr += GenerateNode((SYMBOL) vc.kids.Pop()); + retstr += GenerateNode(vc, (SYMBOL) vc.kids.Pop()); retstr += Generate(")"); return retstr; @@ -1000,13 +1043,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools string retstr = String.Empty; retstr += Generate(String.Format("new {0}(", rc.Type), rc); - retstr += GenerateNode((SYMBOL) rc.kids.Pop()); + retstr += GenerateNode(rc, (SYMBOL) rc.kids.Pop()); retstr += Generate(", "); - retstr += GenerateNode((SYMBOL) rc.kids.Pop()); + retstr += GenerateNode(rc, (SYMBOL) rc.kids.Pop()); retstr += Generate(", "); - retstr += GenerateNode((SYMBOL) rc.kids.Pop()); + retstr += GenerateNode(rc, (SYMBOL) rc.kids.Pop()); retstr += Generate(", "); - retstr += GenerateNode((SYMBOL) rc.kids.Pop()); + retstr += GenerateNode(rc, (SYMBOL) rc.kids.Pop()); retstr += Generate(")"); return retstr; @@ -1024,7 +1067,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools retstr += Generate(String.Format("new {0}(", lc.Type), lc); foreach (SYMBOL kid in lc.kids) - retstr += GenerateNode(kid); + retstr += GenerateNode(lc, kid); retstr += Generate(")"); diff --git a/OpenSim/Region/ScriptEngine/Shared/CodeTools/Compiler.cs b/OpenSim/Region/ScriptEngine/Shared/CodeTools/Compiler.cs index 03be2abf07..7432202ad9 100644 --- a/OpenSim/Region/ScriptEngine/Shared/CodeTools/Compiler.cs +++ b/OpenSim/Region/ScriptEngine/Shared/CodeTools/Compiler.cs @@ -31,6 +31,7 @@ using System.Collections.Generic; using System.Globalization; using System.Reflection; using System.IO; +using System.Linq; using System.Text; using Microsoft.CSharp; //using Microsoft.JScript; @@ -72,6 +73,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools private bool CompileWithDebugInformation; private Dictionary AllowedCompilers = new Dictionary(StringComparer.CurrentCultureIgnoreCase); private Dictionary LanguageMapping = new Dictionary(StringComparer.CurrentCultureIgnoreCase); + private bool m_insertCoopTerminationCalls; private string FilePrefix; private string ScriptEnginesPath = null; @@ -95,20 +97,22 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools private Dictionary, KeyValuePair>> m_lineMaps = new Dictionary, KeyValuePair>>(); + public bool in_startup = true; + public Compiler(IScriptEngine scriptEngine) { - m_scriptEngine = scriptEngine;; + m_scriptEngine = scriptEngine; ScriptEnginesPath = scriptEngine.ScriptEnginePath; ReadConfig(); } - public bool in_startup = true; public void ReadConfig() { // Get some config WriteScriptSourceToDebugFile = m_scriptEngine.Config.GetBoolean("WriteScriptSourceToDebugFile", false); CompileWithDebugInformation = m_scriptEngine.Config.GetBoolean("CompileWithDebugInformation", true); bool DeleteScriptsOnStartup = m_scriptEngine.Config.GetBoolean("DeleteScriptsOnStartup", true); + m_insertCoopTerminationCalls = m_scriptEngine.Config.GetString("ScriptStopStrategy", "abort") == "co-op"; // Get file prefix from scriptengine name and make it file system safe: FilePrefix = "CommonCompiler"; @@ -386,7 +390,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools if (language == enumCompileType.lsl) { // Its LSL, convert it to C# - LSL_Converter = (ICodeConverter)new CSCodeGenerator(comms); + LSL_Converter = (ICodeConverter)new CSCodeGenerator(comms, m_insertCoopTerminationCalls); compileScript = LSL_Converter.Convert(Script); // copy converter warnings into our warnings. @@ -411,16 +415,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools { case enumCompileType.cs: case enumCompileType.lsl: - compileScript = CreateCSCompilerScript(compileScript); + compileScript = CreateCSCompilerScript( + compileScript, m_scriptEngine.ScriptBaseClassName, m_scriptEngine.ScriptBaseClassParameters); break; case enumCompileType.vb: - compileScript = CreateVBCompilerScript(compileScript); + compileScript = CreateVBCompilerScript(compileScript, m_scriptEngine.ScriptBaseClassName); break; // case enumCompileType.js: -// compileScript = CreateJSCompilerScript(compileScript); +// compileScript = CreateJSCompilerScript(compileScript, m_scriptEngine.ScriptBaseClassName); // break; case enumCompileType.yp: - compileScript = CreateYPCompilerScript(compileScript); + compileScript = CreateYPCompilerScript(compileScript, m_scriptEngine.ScriptBaseClassName); break; } @@ -451,43 +456,59 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools // return compileScript; // } - private static string CreateCSCompilerScript(string compileScript) + private static string CreateCSCompilerScript( + string compileScript, string baseClassName, ParameterInfo[] constructorParameters) { - compileScript = String.Empty + - "using OpenSim.Region.ScriptEngine.Shared; using System.Collections.Generic;\r\n" + - String.Empty + "namespace SecondLife { " + - String.Empty + "public class Script : OpenSim.Region.ScriptEngine.Shared.ScriptBase.ScriptBaseClass { \r\n" + - @"public Script() { } " + - compileScript + - "} }\r\n"; + compileScript = string.Format( +@"using OpenSim.Region.ScriptEngine.Shared; +using System.Collections.Generic; + +namespace SecondLife +{{ + public class Script : {0} + {{ + public Script({1}) : base({2}) {{}} +{3} + }} +}}", + baseClassName, + constructorParameters != null + ? string.Join(", ", Array.ConvertAll(constructorParameters, pi => pi.ToString())) + : "", + constructorParameters != null + ? string.Join(", ", Array.ConvertAll(constructorParameters, pi => pi.Name)) + : "", + compileScript); + return compileScript; } - private static string CreateYPCompilerScript(string compileScript) + private static string CreateYPCompilerScript(string compileScript, string baseClassName) { compileScript = String.Empty + "using OpenSim.Region.ScriptEngine.Shared.YieldProlog; " + "using OpenSim.Region.ScriptEngine.Shared; using System.Collections.Generic;\r\n" + String.Empty + "namespace SecondLife { " + - String.Empty + "public class Script : OpenSim.Region.ScriptEngine.Shared.ScriptBase.ScriptBaseClass { \r\n" + + String.Empty + "public class Script : " + baseClassName + " { \r\n" + //@"public Script() { } " + @"static OpenSim.Region.ScriptEngine.Shared.YieldProlog.YP YP=null; " + @"public Script() { YP= new OpenSim.Region.ScriptEngine.Shared.YieldProlog.YP(); } " + - compileScript + "} }\r\n"; + return compileScript; } - private static string CreateVBCompilerScript(string compileScript) + private static string CreateVBCompilerScript(string compileScript, string baseClassName) { compileScript = String.Empty + "Imports OpenSim.Region.ScriptEngine.Shared: Imports System.Collections.Generic: " + String.Empty + "NameSpace SecondLife:" + - String.Empty + "Public Class Script: Inherits OpenSim.Region.ScriptEngine.Shared.ScriptBase.ScriptBaseClass: " + + String.Empty + "Public Class Script: Inherits " + baseClassName + "\r\nPublic Sub New()\r\nEnd Sub: " + compileScript + ":End Class :End Namespace\r\n"; + return compileScript; } @@ -549,6 +570,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools parameters.ReferencedAssemblies.Add(Path.Combine(rootPath, "OpenMetaverseTypes.dll")); + if (m_scriptEngine.ScriptReferencedAssemblies != null) + Array.ForEach( + m_scriptEngine.ScriptReferencedAssemblies, + a => parameters.ReferencedAssemblies.Add(Path.Combine(rootPath, a))); + if (lang == enumCompileType.yp) { parameters.ReferencedAssemblies.Add(Path.Combine(rootPath, diff --git a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs index 75aea2b0b1..e6ec0e1867 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs @@ -267,13 +267,27 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance try { if (dom != System.AppDomain.CurrentDomain) - m_Script = (IScript)dom.CreateInstanceAndUnwrap( + m_Script + = (IScript)dom.CreateInstanceAndUnwrap( Path.GetFileNameWithoutExtension(assembly), - "SecondLife.Script"); + "SecondLife.Script", + false, + BindingFlags.Default, + null, + new object[] { m_coopSleepHandle }, + null, + null, + null); else - m_Script = (IScript)Assembly.Load( - Path.GetFileNameWithoutExtension(assembly)).CreateInstance( - "SecondLife.Script"); + m_Script + = (IScript)Assembly.Load(Path.GetFileNameWithoutExtension(assembly)).CreateInstance( + "SecondLife.Script", + false, + BindingFlags.Default, + null, + new object[] { m_coopSleepHandle }, + null, + null); //ILease lease = (ILease)RemotingServices.GetLifetimeService(m_Script as ScriptBaseClass); //RemotingServices.GetLifetimeService(m_Script as ScriptBaseClass); diff --git a/OpenSim/Region/ScriptEngine/XEngine/Api/Runtime/XEngineScriptBase.cs b/OpenSim/Region/ScriptEngine/XEngine/Api/Runtime/XEngineScriptBase.cs new file mode 100644 index 0000000000..f4211c8286 --- /dev/null +++ b/OpenSim/Region/ScriptEngine/XEngine/Api/Runtime/XEngineScriptBase.cs @@ -0,0 +1,61 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Runtime.Remoting; +using System.Runtime.Remoting.Lifetime; +using System.Security.Permissions; +using System.Threading; +using System.Reflection; +using System.Collections; +using System.Collections.Generic; +using OpenSim.Region.ScriptEngine.Interfaces; +using OpenSim.Region.ScriptEngine.Shared; +using OpenSim.Region.ScriptEngine.Shared.ScriptBase; + +namespace OpenSim.Region.ScriptEngine.XEngine.ScriptBase +{ + public class XEngineScriptBase : ScriptBaseClass + { + /// + /// Used for script sleeps when we are using co-operative script termination. + /// + /// null if co-operative script termination is not active + WaitHandle m_coopSleepHandle; + + public XEngineScriptBase(WaitHandle coopSleepHandle) : base() + { + m_coopSleepHandle = coopSleepHandle; + } + + public void opensim_reserved_CheckForCoopTermination() + { + if (m_coopSleepHandle != null && m_coopSleepHandle.WaitOne(0)) + throw new ScriptCoopStopException(); + } + } +} \ No newline at end of file diff --git a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs index a17a0188bb..8a0259079b 100644 --- a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs +++ b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs @@ -53,6 +53,7 @@ using OpenSim.Region.ScriptEngine.Shared.Instance; using OpenSim.Region.ScriptEngine.Shared.Api; using OpenSim.Region.ScriptEngine.Shared.Api.Plugins; using OpenSim.Region.ScriptEngine.Interfaces; +using OpenSim.Region.ScriptEngine.XEngine.ScriptBase; using Timer = OpenSim.Region.ScriptEngine.Shared.Api.Plugins.Timer; using ScriptCompileQueue = OpenSim.Framework.LocklessQueue; @@ -176,6 +177,12 @@ namespace OpenSim.Region.ScriptEngine.XEngine get { return "XEngine"; } } + public string ScriptBaseClassName { get; private set; } + + public ParameterInfo[] ScriptBaseClassParameters { get; private set; } + + public string[] ScriptReferencedAssemblies { get; private set; } + public Scene World { get { return m_Scene; } @@ -230,6 +237,12 @@ namespace OpenSim.Region.ScriptEngine.XEngine m_ScriptConfig = configSource.Configs["XEngine"]; m_ConfigSource = configSource; + + ScriptBaseClassName = typeof(XEngineScriptBase).FullName; + ScriptBaseClassParameters = typeof(XEngineScriptBase).GetConstructor(new Type[] { typeof(WaitHandle) }).GetParameters(); + ScriptReferencedAssemblies = new string[] { Path.GetFileName(typeof(XEngineScriptBase).Assembly.Location) }; + + Console.WriteLine("ASSEMBLY NAME: {0}", ScriptReferencedAssemblies[0]); } public void AddRegion(Scene scene) @@ -1179,7 +1192,9 @@ namespace OpenSim.Region.ScriptEngine.XEngine } catch (Exception e) { -// m_log.ErrorFormat("[XEngine]: Exception when rezzing script {0}{1}", e.Message, e.StackTrace); +// m_log.ErrorFormat( +// "[XEngine]: Exception when rezzing script with item ID {0}, {1}{2}", +// itemID, e.Message, e.StackTrace); // try // { diff --git a/prebuild.xml b/prebuild.xml index abf8f364d7..4019e0bf33 100644 --- a/prebuild.xml +++ b/prebuild.xml @@ -2423,6 +2423,40 @@ + + + + ../../../../../../bin/ + + + + + ../../../../../../bin/ + + + + ../../../../../../bin/ + + + + + + + + + + + + + + + + + + + + + @@ -2453,6 +2487,7 @@ + @@ -2460,6 +2495,7 @@ + From 49d674c74d6390b33e3d5d655df70eb7adda6065 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Tue, 22 Jan 2013 00:35:56 +0000 Subject: [PATCH 02/17] refactor: rename XEngineTest to more descriptive XEngineBasicTests --- .../XEngine/Tests/{XEngineTest.cs => XEngineBasicTests.cs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename OpenSim/Region/ScriptEngine/XEngine/Tests/{XEngineTest.cs => XEngineBasicTests.cs} (100%) diff --git a/OpenSim/Region/ScriptEngine/XEngine/Tests/XEngineTest.cs b/OpenSim/Region/ScriptEngine/XEngine/Tests/XEngineBasicTests.cs similarity index 100% rename from OpenSim/Region/ScriptEngine/XEngine/Tests/XEngineTest.cs rename to OpenSim/Region/ScriptEngine/XEngine/Tests/XEngineBasicTests.cs From cd446c32d6d4c6453dbc85c5d8ac75c65a6db979 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Tue, 22 Jan 2013 00:59:46 +0000 Subject: [PATCH 03/17] Add regression test TestStopOnLongForLoop() --- .../Instance/Tests/CoopTerminationTests.cs | 59 +++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/OpenSim/Region/ScriptEngine/Shared/Instance/Tests/CoopTerminationTests.cs b/OpenSim/Region/ScriptEngine/Shared/Instance/Tests/CoopTerminationTests.cs index 8c3e9e0b47..c23d7a6501 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Instance/Tests/CoopTerminationTests.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Instance/Tests/CoopTerminationTests.cs @@ -146,6 +146,65 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance.Tests Assert.That(running, Is.False); } + [Test] + public void TestStopOnLongForLoop() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + UUID userId = TestHelpers.ParseTail(0x1); +// UUID objectId = TestHelpers.ParseTail(0x100); +// UUID itemId = TestHelpers.ParseTail(0x3); + string itemName = "TestStopOnLongForLoop() Item"; + + SceneObjectGroup so = SceneHelpers.CreateSceneObject(1, userId, "TestStopOnLongForLoop", 0x100); + m_scene.AddNewSceneObject(so, true); + + InventoryItemBase itemTemplate = new InventoryItemBase(); +// itemTemplate.ID = itemId; + itemTemplate.Name = itemName; + itemTemplate.Folder = so.UUID; + itemTemplate.InvType = (int)InventoryType.LSL; + + m_scene.EventManager.OnChatFromWorld += OnChatFromWorld; + + SceneObjectPart partWhereRezzed = m_scene.RezNewScript(userId, itemTemplate, +@"default +{ + state_entry() + { + llSay(0, ""Thin Lizzy""); + integer i = 0; + for (i = 0; i < 2147483647; i++) + llSay(0, ""Iter "" + (string)i); + } +}"); + + TaskInventoryItem rezzedItem = partWhereRezzed.Inventory.GetInventoryItem(itemName); + + // Wait for the script to start the event before we try stopping it. + m_chatEvent.WaitOne(60000); + + Console.WriteLine("Script started with message [{0}]", m_osChatMessageReceived.Message); + + // FIXME: This is a very poor way of trying to avoid a low-probability race condition where the script + // executes llSay() but has not started the sleep before we try to stop it. + Thread.Sleep(1000); + + // We need a way of carrying on if StopScript() fail, since it won't return if the script isn't actually + // stopped. This kind of multi-threading is far from ideal in a regression test. + new Thread(() => { m_xEngine.StopScript(rezzedItem.ItemID); m_stoppedEvent.Set(); }).Start(); + + if (!m_stoppedEvent.WaitOne(30000)) + Assert.Fail("Script did not co-operatively stop."); + + bool running; + TaskInventoryItem scriptItem = partWhereRezzed.Inventory.GetInventoryItem(itemName); + Assert.That( + SceneObjectPartInventory.TryGetScriptInstanceRunning(m_scene, scriptItem, out running), Is.True); + Assert.That(running, Is.False); + } + private void OnChatFromWorld(object sender, OSChatMessage oscm) { // Console.WriteLine("Got chat [{0}]", oscm.Message); From 1730de14a4cfd78d6d87f12b5b1dcd268aba7fbd Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Tue, 22 Jan 2013 01:00:53 +0000 Subject: [PATCH 04/17] minor: comment out Console.WriteLine debugging message in XEngine --- OpenSim/Region/ScriptEngine/XEngine/XEngine.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs index 8a0259079b..c1f9271f46 100644 --- a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs +++ b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs @@ -242,7 +242,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine ScriptBaseClassParameters = typeof(XEngineScriptBase).GetConstructor(new Type[] { typeof(WaitHandle) }).GetParameters(); ScriptReferencedAssemblies = new string[] { Path.GetFileName(typeof(XEngineScriptBase).Assembly.Location) }; - Console.WriteLine("ASSEMBLY NAME: {0}", ScriptReferencedAssemblies[0]); +// Console.WriteLine("ASSEMBLY NAME: {0}", ScriptReferencedAssemblies[0]); } public void AddRegion(Scene scene) From 419f8e0f76ba765044d2ac29e03ee714356f42e3 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Tue, 22 Jan 2013 01:08:24 +0000 Subject: [PATCH 05/17] Increase WaitForEventCompletionOnScriptStop to 120 secs to show that the co-op setting is active in its regression tests. --- .../Shared/Instance/Tests/CoopTerminationTests.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/OpenSim/Region/ScriptEngine/Shared/Instance/Tests/CoopTerminationTests.cs b/OpenSim/Region/ScriptEngine/Shared/Instance/Tests/CoopTerminationTests.cs index c23d7a6501..53b992d7f3 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Instance/Tests/CoopTerminationTests.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Instance/Tests/CoopTerminationTests.cs @@ -77,6 +77,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance.Tests xEngineConfig.Set("ScriptStopStrategy", "co-op"); + // This is not currently used at all for co-op termination. Bumping up to demonstrate that co-op termination + // has an effect - without it tests will fail due to a 120 second wait for the event to finish. + xEngineConfig.Set("WaitForEventCompletionOnScriptStop", 120000); + m_scene = new SceneHelpers().SetupScene("My Test", UUID.Random(), 1000, 1000, configSource); SceneHelpers.SetupSceneModules(m_scene, configSource, m_xEngine); m_scene.StartScripts(); From a558f9797d3a2af00f6472adfc46ad5363d9bc1b Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Tue, 22 Jan 2013 01:13:45 +0000 Subject: [PATCH 06/17] factor out common code in existing co-op termination regression tests --- .../Instance/Tests/CoopTerminationTests.cs | 89 ++++++------------- 1 file changed, 29 insertions(+), 60 deletions(-) diff --git a/OpenSim/Region/ScriptEngine/Shared/Instance/Tests/CoopTerminationTests.cs b/OpenSim/Region/ScriptEngine/Shared/Instance/Tests/CoopTerminationTests.cs index 53b992d7f3..952ae401ad 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Instance/Tests/CoopTerminationTests.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Instance/Tests/CoopTerminationTests.cs @@ -99,23 +99,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance.Tests TestHelpers.InMethod(); // TestHelpers.EnableLogging(); - UUID userId = TestHelpers.ParseTail(0x1); -// UUID objectId = TestHelpers.ParseTail(0x100); -// UUID itemId = TestHelpers.ParseTail(0x3); - string itemName = "TestStopOnObjectDerezLongSleep() Item"; - - SceneObjectGroup so = SceneHelpers.CreateSceneObject(1, userId, "TestStopOnObjectDerezLongSleep", 0x100); - m_scene.AddNewSceneObject(so, true); - - InventoryItemBase itemTemplate = new InventoryItemBase(); -// itemTemplate.ID = itemId; - itemTemplate.Name = itemName; - itemTemplate.Folder = so.UUID; - itemTemplate.InvType = (int)InventoryType.LSL; - - m_scene.EventManager.OnChatFromWorld += OnChatFromWorld; - - SceneObjectPart partWhereRezzed = m_scene.RezNewScript(userId, itemTemplate, + string script = @"default { state_entry() @@ -123,31 +107,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance.Tests llSay(0, ""Thin Lizzy""); llSleep(60); } -}"); +}"; - TaskInventoryItem rezzedItem = partWhereRezzed.Inventory.GetInventoryItem(itemName); - - // Wait for the script to start the event before we try stopping it. - m_chatEvent.WaitOne(60000); - - Console.WriteLine("Script started with message [{0}]", m_osChatMessageReceived.Message); - - // FIXME: This is a very poor way of trying to avoid a low-probability race condition where the script - // executes llSay() but has not started the sleep before we try to stop it. - Thread.Sleep(1000); - - // We need a way of carrying on if StopScript() fail, since it won't return if the script isn't actually - // stopped. This kind of multi-threading is far from ideal in a regression test. - new Thread(() => { m_xEngine.StopScript(rezzedItem.ItemID); m_stoppedEvent.Set(); }).Start(); - - if (!m_stoppedEvent.WaitOne(30000)) - Assert.Fail("Script did not co-operatively stop."); - - bool running; - TaskInventoryItem scriptItem = partWhereRezzed.Inventory.GetInventoryItem(itemName); - Assert.That( - SceneObjectPartInventory.TryGetScriptInstanceRunning(m_scene, scriptItem, out running), Is.True); - Assert.That(running, Is.False); + TestStop(script); } [Test] @@ -156,23 +118,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance.Tests TestHelpers.InMethod(); // TestHelpers.EnableLogging(); - UUID userId = TestHelpers.ParseTail(0x1); -// UUID objectId = TestHelpers.ParseTail(0x100); -// UUID itemId = TestHelpers.ParseTail(0x3); - string itemName = "TestStopOnLongForLoop() Item"; - - SceneObjectGroup so = SceneHelpers.CreateSceneObject(1, userId, "TestStopOnLongForLoop", 0x100); - m_scene.AddNewSceneObject(so, true); - - InventoryItemBase itemTemplate = new InventoryItemBase(); -// itemTemplate.ID = itemId; - itemTemplate.Name = itemName; - itemTemplate.Folder = so.UUID; - itemTemplate.InvType = (int)InventoryType.LSL; - - m_scene.EventManager.OnChatFromWorld += OnChatFromWorld; - - SceneObjectPart partWhereRezzed = m_scene.RezNewScript(userId, itemTemplate, + string script = @"default { state_entry() @@ -182,7 +128,30 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance.Tests for (i = 0; i < 2147483647; i++) llSay(0, ""Iter "" + (string)i); } -}"); +}"; + + TestStop(script); + } + + private void TestStop(string script) + { + UUID userId = TestHelpers.ParseTail(0x1); +// UUID objectId = TestHelpers.ParseTail(0x100); +// UUID itemId = TestHelpers.ParseTail(0x3); + string itemName = "TestStop() Item"; + + SceneObjectGroup so = SceneHelpers.CreateSceneObject(1, userId, "TestStop", 0x100); + m_scene.AddNewSceneObject(so, true); + + InventoryItemBase itemTemplate = new InventoryItemBase(); +// itemTemplate.ID = itemId; + itemTemplate.Name = itemName; + itemTemplate.Folder = so.UUID; + itemTemplate.InvType = (int)InventoryType.LSL; + + m_scene.EventManager.OnChatFromWorld += OnChatFromWorld; + + SceneObjectPart partWhereRezzed = m_scene.RezNewScript(userId, itemTemplate, script); TaskInventoryItem rezzedItem = partWhereRezzed.Inventory.GetInventoryItem(itemName); @@ -192,7 +161,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance.Tests Console.WriteLine("Script started with message [{0}]", m_osChatMessageReceived.Message); // FIXME: This is a very poor way of trying to avoid a low-probability race condition where the script - // executes llSay() but has not started the sleep before we try to stop it. + // executes llSay() but has not started the next statement before we try to stop it. Thread.Sleep(1000); // We need a way of carrying on if StopScript() fail, since it won't return if the script isn't actually From c6ba27d096a3008bc0128aebddf4d2e9708d2498 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Tue, 22 Jan 2013 01:23:10 +0000 Subject: [PATCH 07/17] Fix bug in generating termination checks in compound statement for loop. Add regression test for this case. --- .../Shared/CodeTools/CSCodeGenerator.cs | 2 +- .../Instance/Tests/CoopTerminationTests.cs | 28 +++++++++++++++++-- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/OpenSim/Region/ScriptEngine/Shared/CodeTools/CSCodeGenerator.cs b/OpenSim/Region/ScriptEngine/Shared/CodeTools/CSCodeGenerator.cs index 002f9b8a44..985e598184 100644 --- a/OpenSim/Region/ScriptEngine/Shared/CodeTools/CSCodeGenerator.cs +++ b/OpenSim/Region/ScriptEngine/Shared/CodeTools/CSCodeGenerator.cs @@ -445,7 +445,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools if (previousSymbol is GlobalFunctionDefinition || previousSymbol is WhileStatement || previousSymbol is DoWhileStatement - || previousSymbol is ForLoopStatement + || previousSymbol is ForLoop || previousSymbol is StateEvent) retstr += GenerateIndentedLine(m_coopTerminationCheck); } diff --git a/OpenSim/Region/ScriptEngine/Shared/Instance/Tests/CoopTerminationTests.cs b/OpenSim/Region/ScriptEngine/Shared/Instance/Tests/CoopTerminationTests.cs index 952ae401ad..c83a6bac20 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Instance/Tests/CoopTerminationTests.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Instance/Tests/CoopTerminationTests.cs @@ -76,12 +76,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance.Tests xEngineConfig.Set("AppDomainLoading", "false"); xEngineConfig.Set("ScriptStopStrategy", "co-op"); + xEngineConfig.Set("WriteScriptSourceToDebugFile", true); // This is not currently used at all for co-op termination. Bumping up to demonstrate that co-op termination // has an effect - without it tests will fail due to a 120 second wait for the event to finish. xEngineConfig.Set("WaitForEventCompletionOnScriptStop", 120000); - m_scene = new SceneHelpers().SetupScene("My Test", UUID.Random(), 1000, 1000, configSource); + m_scene = new SceneHelpers().SetupScene("My Test", TestHelpers.ParseTail(0x9999), 1000, 1000, configSource); SceneHelpers.SetupSceneModules(m_scene, configSource, m_xEngine); m_scene.StartScripts(); } @@ -113,7 +114,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance.Tests } [Test] - public void TestStopOnLongForLoop() + public void TestStopOnLongSingleStatementForLoop() { TestHelpers.InMethod(); // TestHelpers.EnableLogging(); @@ -133,6 +134,29 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance.Tests TestStop(script); } + [Test] + public void TestStopOnLongCompoundStatementForLoop() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + string script = +@"default +{ + state_entry() + { + llSay(0, ""Thin Lizzy""); + integer i = 0; + for (i = 0; i < 2147483647; i++) + { + llSay(0, ""Iter "" + (string)i); + } + } +}"; + + TestStop(script); + } + private void TestStop(string script) { UUID userId = TestHelpers.ParseTail(0x1); From fbdfe43d75cb99066ce5fcfa803b135aff6e1fe0 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Tue, 22 Jan 2013 01:40:18 +0000 Subject: [PATCH 08/17] Add single and comound while loop co-op termination test --- .../Instance/Tests/CoopTerminationTests.cs | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/OpenSim/Region/ScriptEngine/Shared/Instance/Tests/CoopTerminationTests.cs b/OpenSim/Region/ScriptEngine/Shared/Instance/Tests/CoopTerminationTests.cs index c83a6bac20..87951f9d54 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Instance/Tests/CoopTerminationTests.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Instance/Tests/CoopTerminationTests.cs @@ -157,6 +157,50 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance.Tests TestStop(script); } + [Test] + public void TestStopOnLongSingleStatementWhileLoop() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + string script = +@"default +{ + state_entry() + { + llSay(0, ""Thin Lizzy""); + + while (1 == 1) + llSay(0, ""Iter "" + (string)i); + } +}"; + + TestStop(script); + } + + [Test] + public void TestStopOnLongCompoundStatementWhileLoop() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + string script = +@"default +{ + state_entry() + { + llSay(0, ""Thin Lizzy""); + + while (1 == 1) + { + llSay(0, ""Iter "" + (string)i); + } + } +}"; + + TestStop(script); + } + private void TestStop(string script) { UUID userId = TestHelpers.ParseTail(0x1); From cf0b5e4f279e36e506c46a8c1d980f015fe5cfb2 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Tue, 22 Jan 2013 01:53:10 +0000 Subject: [PATCH 09/17] Add do-while co-op termination test Minor changes to scripts in other tests. --- .../Instance/Tests/CoopTerminationTests.cs | 32 +++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/OpenSim/Region/ScriptEngine/Shared/Instance/Tests/CoopTerminationTests.cs b/OpenSim/Region/ScriptEngine/Shared/Instance/Tests/CoopTerminationTests.cs index 87951f9d54..33d217562c 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Instance/Tests/CoopTerminationTests.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Instance/Tests/CoopTerminationTests.cs @@ -124,8 +124,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance.Tests { state_entry() { - llSay(0, ""Thin Lizzy""); integer i = 0; + llSay(0, ""Thin Lizzy""); + for (i = 0; i < 2147483647; i++) llSay(0, ""Iter "" + (string)i); } @@ -145,8 +146,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance.Tests { state_entry() { - llSay(0, ""Thin Lizzy""); integer i = 0; + llSay(0, ""Thin Lizzy""); + for (i = 0; i < 2147483647; i++) { llSay(0, ""Iter "" + (string)i); @@ -168,6 +170,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance.Tests { state_entry() { + integer i = 0; llSay(0, ""Thin Lizzy""); while (1 == 1) @@ -189,6 +192,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance.Tests { state_entry() { + integer i = 0; llSay(0, ""Thin Lizzy""); while (1 == 1) @@ -201,6 +205,30 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance.Tests TestStop(script); } + [Test] + public void TestStopOnLongDoWhileLoop() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + string script = +@"default +{ + state_entry() + { + integer i = 0; + llSay(0, ""Thin Lizzy""); + + do + { + llSay(0, ""Iter "" + (string)i); + } while (1 == 1) + } +}"; + + TestStop(script); + } + private void TestStop(string script) { UUID userId = TestHelpers.ParseTail(0x1); From b93e8020e25ab22973e5ef25cc563ee39a9c3f66 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Tue, 22 Jan 2013 02:16:10 +0000 Subject: [PATCH 10/17] Add regression test for co-op stop of an infinite jump loop Also fixes bug in do-while test Improves detection of failure due to invalid script in test Sets up xengine anew for each test rather than once for the while testsuite to improve isolation between tests. Stop listening for chat after the first 'script is running' chat is received to reduce test run time. --- .../Instance/Tests/CoopTerminationTests.cs | 49 ++++++++++++++++--- 1 file changed, 41 insertions(+), 8 deletions(-) diff --git a/OpenSim/Region/ScriptEngine/Shared/Instance/Tests/CoopTerminationTests.cs b/OpenSim/Region/ScriptEngine/Shared/Instance/Tests/CoopTerminationTests.cs index 33d217562c..3365c92b0b 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Instance/Tests/CoopTerminationTests.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Instance/Tests/CoopTerminationTests.cs @@ -50,14 +50,18 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance.Tests private TestScene m_scene; private OpenSim.Region.ScriptEngine.XEngine.XEngine m_xEngine; - private AutoResetEvent m_chatEvent = new AutoResetEvent(false); - private AutoResetEvent m_stoppedEvent = new AutoResetEvent(false); + private AutoResetEvent m_chatEvent; + private AutoResetEvent m_stoppedEvent; private OSChatMessage m_osChatMessageReceived; - [TestFixtureSetUp] + [SetUp] public void Init() { + m_osChatMessageReceived = null; + m_chatEvent = new AutoResetEvent(false); + m_stoppedEvent = new AutoResetEvent(false); + //AppDomain.CurrentDomain.SetData("APPBASE", Environment.CurrentDirectory + "/bin"); // Console.WriteLine(AppDomain.CurrentDomain.BaseDirectory); m_xEngine = new OpenSim.Region.ScriptEngine.XEngine.XEngine(); @@ -76,8 +80,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance.Tests xEngineConfig.Set("AppDomainLoading", "false"); xEngineConfig.Set("ScriptStopStrategy", "co-op"); + + // This is really just set for debugging the test. xEngineConfig.Set("WriteScriptSourceToDebugFile", true); + // Set to false if we need to debug test so the old scripts don't get wiped before each separate test +// xEngineConfig.Set("DeleteScriptsOnStartup", false); + // This is not currently used at all for co-op termination. Bumping up to demonstrate that co-op termination // has an effect - without it tests will fail due to a 120 second wait for the event to finish. xEngineConfig.Set("WaitForEventCompletionOnScriptStop", 120000); @@ -174,7 +183,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance.Tests llSay(0, ""Thin Lizzy""); while (1 == 1) - llSay(0, ""Iter "" + (string)i); + llSay(0, ""Iter "" + (string)i++); } }"; @@ -197,7 +206,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance.Tests while (1 == 1) { - llSay(0, ""Iter "" + (string)i); + llSay(0, ""Iter "" + (string)i++); } } }"; @@ -221,8 +230,31 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance.Tests do { - llSay(0, ""Iter "" + (string)i); - } while (1 == 1) + llSay(0, ""Iter "" + (string)i++); +} while (1 == 1); + } +}"; + + TestStop(script); + } + + [Test] + public void TestStopOnInfiniteJumpLoop() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + string script = +@"default +{ + state_entry() + { + integer i = 0; + llSay(0, ""Thin Lizzy""); + + @p1; + llSay(0, ""Iter "" + (string)i++); + jump p1; } }"; @@ -276,7 +308,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance.Tests private void OnChatFromWorld(object sender, OSChatMessage oscm) { -// Console.WriteLine("Got chat [{0}]", oscm.Message); + m_scene.EventManager.OnChatFromWorld -= OnChatFromWorld; + Console.WriteLine("Got chat [{0}]", oscm.Message); m_osChatMessageReceived = oscm; m_chatEvent.Set(); From 679dc811dda95bd3d037e9bd691a9cd10fbf032a Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Tue, 22 Jan 2013 02:22:58 +0000 Subject: [PATCH 11/17] Add regression test for co-op termination on infinite user function call regression. Such a script would probably run out of stack pretty quickly anyway. --- .../Instance/Tests/CoopTerminationTests.cs | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/OpenSim/Region/ScriptEngine/Shared/Instance/Tests/CoopTerminationTests.cs b/OpenSim/Region/ScriptEngine/Shared/Instance/Tests/CoopTerminationTests.cs index 3365c92b0b..149a27bd38 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Instance/Tests/CoopTerminationTests.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Instance/Tests/CoopTerminationTests.cs @@ -261,6 +261,36 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance.Tests TestStop(script); } + [Test] + public void TestStopOnInfiniteUserFunctionCallLoop() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + string script = +@" +integer i = 0; + +ufn1() +{ + llSay(0, ""Iter ufn1() "" + (string)i++); + ufn1(); +} + +default +{ + state_entry() + { + integer i = 0; + llSay(0, ""Thin Lizzy""); + + ufn1(); + } +}"; + + TestStop(script); + } + private void TestStop(string script) { UUID userId = TestHelpers.ParseTail(0x1); From 0727784186ec906804e0b6d3cdc17877f1da9e06 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Tue, 22 Jan 2013 02:26:04 +0000 Subject: [PATCH 12/17] Set script delay factor to 0 in co-op termination tests This is to ensure loops aren't actually terminating from a wait on an LSL function. This was not the case with any of the existing tests. --- .../ScriptEngine/Shared/Instance/Tests/CoopTerminationTests.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/OpenSim/Region/ScriptEngine/Shared/Instance/Tests/CoopTerminationTests.cs b/OpenSim/Region/ScriptEngine/Shared/Instance/Tests/CoopTerminationTests.cs index 149a27bd38..019375df47 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Instance/Tests/CoopTerminationTests.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Instance/Tests/CoopTerminationTests.cs @@ -81,6 +81,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance.Tests xEngineConfig.Set("ScriptStopStrategy", "co-op"); + // Make sure loops aren't actually being terminated by a script delay wait. + xEngineConfig.Set("ScriptDelayFactor", 0); + // This is really just set for debugging the test. xEngineConfig.Set("WriteScriptSourceToDebugFile", true); From 9a4914e58cace98228e12e4d2e44064cc1db20bf Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Tue, 22 Jan 2013 02:32:40 +0000 Subject: [PATCH 13/17] Add co-op termination regression test for infinite recursive manual call on event function. Such code would normally terminate quickly with a stack overflow exception anyway. --- .../Instance/Tests/CoopTerminationTests.cs | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/OpenSim/Region/ScriptEngine/Shared/Instance/Tests/CoopTerminationTests.cs b/OpenSim/Region/ScriptEngine/Shared/Instance/Tests/CoopTerminationTests.cs index 019375df47..bd882f9dec 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Instance/Tests/CoopTerminationTests.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Instance/Tests/CoopTerminationTests.cs @@ -294,6 +294,28 @@ default TestStop(script); } + [Test] + public void TestStopOnInfiniteManualEventCallLoop() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + string script = +@"default +{ + state_entry() + { + integer i = 0; + llSay(0, ""Thin Lizzy""); + + llSay(0, ""Iter"" + (string)i++); + default_event_state_entry(); + } +}"; + + TestStop(script); + } + private void TestStop(string script) { UUID userId = TestHelpers.ParseTail(0x1); From cf168194e5968c1fab33266bdbb57465f303860b Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Wed, 23 Jan 2013 02:28:27 +0000 Subject: [PATCH 14/17] If ScriptStopStrategy hasn't been set to co-op in [XEngine] config, then continue to generate C# that is functionality identical to historical generation This is to eliminate disruption until co-op termination has been well-tested. In non co-op mode, XEngine will continue to load DLLs of the existing Script class and the new XEngineScript class. Moving to co-op mode still requires existing script DLL deletion to force recompilation, either manually or by setting DeleteScriptsOnStartup = true for one run. This change also means that scripts which fail to initialize do not still show up as running scripts. --- .../ScriptEngine/Interfaces/IScriptEngine.cs | 8 ++++ .../ScriptEngine/Shared/CodeTools/Compiler.cs | 30 +++++++----- .../Shared/Instance/ScriptInstance.cs | 48 +++++++++++++++---- .../Instance/Tests/CoopTerminationTests.cs | 2 +- .../Region/ScriptEngine/XEngine/XEngine.cs | 26 +++++++--- prebuild.xml | 1 + 6 files changed, 88 insertions(+), 27 deletions(-) diff --git a/OpenSim/Region/ScriptEngine/Interfaces/IScriptEngine.cs b/OpenSim/Region/ScriptEngine/Interfaces/IScriptEngine.cs index 20dcac9855..b8fdd01d37 100644 --- a/OpenSim/Region/ScriptEngine/Interfaces/IScriptEngine.cs +++ b/OpenSim/Region/ScriptEngine/Interfaces/IScriptEngine.cs @@ -78,6 +78,14 @@ namespace OpenSim.Region.ScriptEngine.Interfaces string ScriptEngineName { get; } string ScriptEnginePath { get; } + /// + /// Return the name of the class that will be used for all running scripts. + /// + /// + /// Each class goes in its own assembly so we don't need to otherwise distinguish the class name. + /// + string ScriptClassName { get; } + /// /// Return the name of the base class that will be used for all running scripts. /// diff --git a/OpenSim/Region/ScriptEngine/Shared/CodeTools/Compiler.cs b/OpenSim/Region/ScriptEngine/Shared/CodeTools/Compiler.cs index 7432202ad9..002e8529da 100644 --- a/OpenSim/Region/ScriptEngine/Shared/CodeTools/Compiler.cs +++ b/OpenSim/Region/ScriptEngine/Shared/CodeTools/Compiler.cs @@ -416,16 +416,21 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools case enumCompileType.cs: case enumCompileType.lsl: compileScript = CreateCSCompilerScript( - compileScript, m_scriptEngine.ScriptBaseClassName, m_scriptEngine.ScriptBaseClassParameters); + compileScript, + m_scriptEngine.ScriptClassName, + m_scriptEngine.ScriptBaseClassName, + m_scriptEngine.ScriptBaseClassParameters); break; case enumCompileType.vb: - compileScript = CreateVBCompilerScript(compileScript, m_scriptEngine.ScriptBaseClassName); + compileScript = CreateVBCompilerScript( + compileScript, m_scriptEngine.ScriptClassName, m_scriptEngine.ScriptBaseClassName); break; // case enumCompileType.js: // compileScript = CreateJSCompilerScript(compileScript, m_scriptEngine.ScriptBaseClassName); // break; case enumCompileType.yp: - compileScript = CreateYPCompilerScript(compileScript, m_scriptEngine.ScriptBaseClassName); + compileScript = CreateYPCompilerScript( + compileScript, m_scriptEngine.ScriptClassName,m_scriptEngine.ScriptBaseClassName); break; } @@ -457,7 +462,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools // } private static string CreateCSCompilerScript( - string compileScript, string baseClassName, ParameterInfo[] constructorParameters) + string compileScript, string className, string baseClassName, ParameterInfo[] constructorParameters) { compileScript = string.Format( @"using OpenSim.Region.ScriptEngine.Shared; @@ -465,12 +470,13 @@ using System.Collections.Generic; namespace SecondLife {{ - public class Script : {0} + public class {0} : {1} {{ - public Script({1}) : base({2}) {{}} -{3} + public {0}({2}) : base({3}) {{}} +{4} }} }}", + className, baseClassName, constructorParameters != null ? string.Join(", ", Array.ConvertAll(constructorParameters, pi => pi.ToString())) @@ -483,28 +489,28 @@ namespace SecondLife return compileScript; } - private static string CreateYPCompilerScript(string compileScript, string baseClassName) + private static string CreateYPCompilerScript(string compileScript, string className, string baseClassName) { compileScript = String.Empty + "using OpenSim.Region.ScriptEngine.Shared.YieldProlog; " + "using OpenSim.Region.ScriptEngine.Shared; using System.Collections.Generic;\r\n" + String.Empty + "namespace SecondLife { " + - String.Empty + "public class Script : " + baseClassName + " { \r\n" + + String.Empty + "public class " + className + " : " + baseClassName + " { \r\n" + //@"public Script() { } " + @"static OpenSim.Region.ScriptEngine.Shared.YieldProlog.YP YP=null; " + - @"public Script() { YP= new OpenSim.Region.ScriptEngine.Shared.YieldProlog.YP(); } " + + @"public " + className + "() { YP= new OpenSim.Region.ScriptEngine.Shared.YieldProlog.YP(); } " + compileScript + "} }\r\n"; return compileScript; } - private static string CreateVBCompilerScript(string compileScript, string baseClassName) + private static string CreateVBCompilerScript(string compileScript, string className, string baseClassName) { compileScript = String.Empty + "Imports OpenSim.Region.ScriptEngine.Shared: Imports System.Collections.Generic: " + String.Empty + "NameSpace SecondLife:" + - String.Empty + "Public Class Script: Inherits " + baseClassName + + String.Empty + "Public Class " + className + ": Inherits " + baseClassName + "\r\nPublic Sub New()\r\nEnd Sub: " + compileScript + ":End Class :End Namespace\r\n"; diff --git a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs index e6ec0e1867..4cfcb750a5 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs @@ -251,7 +251,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance /// /// /// - public void Load(AppDomain dom, string assembly, StateSource stateSource) + /// false if load failed, true if suceeded + public bool Load(AppDomain dom, string assembly, StateSource stateSource) { m_Assembly = assembly; m_stateSource = stateSource; @@ -266,26 +267,53 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance try { + object[] constructorParams; + + Assembly scriptAssembly = dom.Load(Path.GetFileNameWithoutExtension(assembly)); + Type scriptType = scriptAssembly.GetType("SecondLife.XEngineScript"); + + if (scriptType != null) + { + constructorParams = new object[] { m_coopSleepHandle }; + } + else if (!m_coopTermination) + { + scriptType = scriptAssembly.GetType("SecondLife.Script"); + constructorParams = null; + } + else + { + m_log.ErrorFormat( + "[SCRIPT INSTANCE]: You must remove all existing script DLLs before using enabling co-op termination" + + ", either by setting DeleteScriptsOnStartup = true in [XEngine] for one run" + + " or by deleting all *.dll* files in the relevant bin/ScriptEngines// directory"); + + return false; + } + +// m_log.DebugFormat( +// "[SCRIPT INSTANCE]: Looking to load {0} from assembly {1} in {2}", +// scriptType.FullName, Path.GetFileNameWithoutExtension(assembly), Engine.World.Name); + if (dom != System.AppDomain.CurrentDomain) m_Script = (IScript)dom.CreateInstanceAndUnwrap( Path.GetFileNameWithoutExtension(assembly), - "SecondLife.Script", + scriptType.FullName, false, BindingFlags.Default, null, - new object[] { m_coopSleepHandle }, - null, + constructorParams, null, null); else m_Script - = (IScript)Assembly.Load(Path.GetFileNameWithoutExtension(assembly)).CreateInstance( - "SecondLife.Script", + = (IScript)scriptAssembly.CreateInstance( + scriptType.FullName, false, BindingFlags.Default, null, - new object[] { m_coopSleepHandle }, + constructorParams, null, null); @@ -298,6 +326,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance m_log.ErrorFormat( "[SCRIPT INSTANCE]: Error loading assembly {0}. Exception {1}{2}", assembly, e.Message, e.StackTrace); + + return false; } try @@ -318,7 +348,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance "[SCRIPT INSTANCE]: Error loading script instance from assembly {0}. Exception {1}{2}", assembly, e.Message, e.StackTrace); - return; + return false; } m_SaveState = true; @@ -390,6 +420,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance // presence.ControllingClient.SendAgentAlertMessage("Compile successful", false); // } + + return true; } public void Init() diff --git a/OpenSim/Region/ScriptEngine/Shared/Instance/Tests/CoopTerminationTests.cs b/OpenSim/Region/ScriptEngine/Shared/Instance/Tests/CoopTerminationTests.cs index bd882f9dec..52d75a0d31 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Instance/Tests/CoopTerminationTests.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Instance/Tests/CoopTerminationTests.cs @@ -245,7 +245,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance.Tests public void TestStopOnInfiniteJumpLoop() { TestHelpers.InMethod(); -// TestHelpers.EnableLogging(); + TestHelpers.EnableLogging(); string script = @"default diff --git a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs index c1f9271f46..604924bd0e 100644 --- a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs +++ b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs @@ -46,13 +46,14 @@ using OpenSim.Framework; using OpenSim.Framework.Console; using OpenSim.Region.Framework.Scenes; using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.ScriptEngine.Interfaces; using OpenSim.Region.ScriptEngine.Shared; using OpenSim.Region.ScriptEngine.Shared.ScriptBase; using OpenSim.Region.ScriptEngine.Shared.CodeTools; using OpenSim.Region.ScriptEngine.Shared.Instance; using OpenSim.Region.ScriptEngine.Shared.Api; using OpenSim.Region.ScriptEngine.Shared.Api.Plugins; -using OpenSim.Region.ScriptEngine.Interfaces; +using OpenSim.Region.ScriptEngine.Shared.ScriptBase; using OpenSim.Region.ScriptEngine.XEngine.ScriptBase; using Timer = OpenSim.Region.ScriptEngine.Shared.Api.Plugins.Timer; @@ -177,6 +178,8 @@ namespace OpenSim.Region.ScriptEngine.XEngine get { return "XEngine"; } } + public string ScriptClassName { get; private set; } + public string ScriptBaseClassName { get; private set; } public ParameterInfo[] ScriptBaseClassParameters { get; private set; } @@ -238,9 +241,18 @@ namespace OpenSim.Region.ScriptEngine.XEngine m_ScriptConfig = configSource.Configs["XEngine"]; m_ConfigSource = configSource; - ScriptBaseClassName = typeof(XEngineScriptBase).FullName; - ScriptBaseClassParameters = typeof(XEngineScriptBase).GetConstructor(new Type[] { typeof(WaitHandle) }).GetParameters(); - ScriptReferencedAssemblies = new string[] { Path.GetFileName(typeof(XEngineScriptBase).Assembly.Location) }; + if (m_ScriptConfig.GetString("ScriptStopStrategy", "abort") == "co-op") + { + ScriptClassName = "XEngineScript"; + ScriptBaseClassName = typeof(XEngineScriptBase).FullName; + ScriptBaseClassParameters = typeof(XEngineScriptBase).GetConstructor(new Type[] { typeof(WaitHandle) }).GetParameters(); + ScriptReferencedAssemblies = new string[] { Path.GetFileName(typeof(XEngineScriptBase).Assembly.Location) }; + } + else + { + ScriptClassName = "Script"; + ScriptBaseClassName = typeof(ScriptBaseClass).FullName; + } // Console.WriteLine("ASSEMBLY NAME: {0}", ScriptReferencedAssemblies[0]); } @@ -1122,7 +1134,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine } m_log.DebugFormat( - "[XEngine] Loading script {0}.{1}, item UUID {2}, prim UUID {3} @ {4}.{5}", + "[XEngine]: Loading script {0}.{1}, item UUID {2}, prim UUID {3} @ {4}.{5}", part.ParentGroup.RootPart.Name, item.Name, itemID, part.UUID, part.ParentGroup.RootPart.AbsolutePosition, part.ParentGroup.Scene.RegionInfo.RegionName); @@ -1143,6 +1155,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine lock (m_AddingAssemblies) { m_Compiler.PerformScriptCompile(script, assetID.ToString(), item.OwnerID, out assembly, out linemap); + if (!m_AddingAssemblies.ContainsKey(assembly)) { m_AddingAssemblies[assembly] = 1; } else { @@ -1303,7 +1316,8 @@ namespace OpenSim.Region.ScriptEngine.XEngine startParam, postOnRez, m_MaxScriptQueue); - instance.Load(m_AppDomains[appDomain], assembly, stateSource); + if (!instance.Load(m_AppDomains[appDomain], assembly, stateSource)) + return false; // if (DebugLevel >= 1) // m_log.DebugFormat( diff --git a/prebuild.xml b/prebuild.xml index 4019e0bf33..e891433cf6 100644 --- a/prebuild.xml +++ b/prebuild.xml @@ -2487,6 +2487,7 @@ + From 72dd3633eeb74c64620ffedb1618e732cbbca641 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Wed, 23 Jan 2013 23:34:15 +0000 Subject: [PATCH 15/17] Improve logging by making it clearer which script is failing if an assembly fails to load. Moves the noise co-op start/stop debug log messages to only display if xengine debug level >= 1 Logs which stop strategy is being used (abort or co-op) Adjusts some other logging to remove not very useful stuff --- .../Shared/Instance/ScriptInstance.cs | 42 ++++++++++--------- .../ScriptEngine/XEngine/EventManager.cs | 4 +- .../Region/ScriptEngine/XEngine/XEngine.cs | 13 +++--- 3 files changed, 31 insertions(+), 28 deletions(-) diff --git a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs index 4cfcb750a5..5bc585e15f 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs @@ -284,9 +284,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance else { m_log.ErrorFormat( - "[SCRIPT INSTANCE]: You must remove all existing script DLLs before using enabling co-op termination" + "[SCRIPT INSTANCE]: Not starting script {0} (id {1}) in part {2} (id {3}) in object {4} in {5}. You must remove all existing {6}* script DLL files before using enabling co-op termination" + ", either by setting DeleteScriptsOnStartup = true in [XEngine] for one run" - + " or by deleting all *.dll* files in the relevant bin/ScriptEngines// directory"); + + " or by deleting these files manually.", + ScriptTask.Name, ScriptTask.ItemID, Part.Name, Part.UUID, Part.ParentGroup.Name, Engine.World.Name, assembly); return false; } @@ -324,8 +325,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance catch (Exception e) { m_log.ErrorFormat( - "[SCRIPT INSTANCE]: Error loading assembly {0}. Exception {1}{2}", - assembly, e.Message, e.StackTrace); + "[SCRIPT INSTANCE]: Not starting script {0} (id {1}) in part {2} (id {3}) in object {4} in {5}. Error loading assembly {6}. Exception {7}{8}", + ScriptTask.Name, ScriptTask.ItemID, Part.Name, Part.UUID, Part.ParentGroup.Name, Engine.World.Name, assembly, e.Message, e.StackTrace); return false; } @@ -345,8 +346,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance catch (Exception e) { m_log.ErrorFormat( - "[SCRIPT INSTANCE]: Error loading script instance from assembly {0}. Exception {1}{2}", - assembly, e.Message, e.StackTrace); + "[SCRIPT INSTANCE]: Not starting script {0} (id {1}) in part {2} (id {3}) in object {4} in {5}. Error initializing script instance. Exception {6}{7}", + ScriptTask.Name, ScriptTask.ItemID, Part.Name, Part.UUID, Part.ParentGroup.Name, Engine.World.Name, e.Message, e.StackTrace); return false; } @@ -401,15 +402,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance else { m_log.WarnFormat( - "[SCRIPT INSTANCE]: Unable to load script state file {0} for script {1} {2} in {3} {4} (assembly {5}). Memory limit exceeded", - savedState, ScriptName, ItemID, PrimName, ObjectID, assembly); + "[SCRIPT INSTANCE]: Not starting script {0} (id {1}) in part {2} (id {3}) in object {4} in {5}. Unable to load script state file {6}. Memory limit exceeded.", + ScriptTask.Name, ScriptTask.ItemID, Part.Name, Part.UUID, Part.ParentGroup.Name, Engine.World.Name, savedState); } } catch (Exception e) { m_log.ErrorFormat( - "[SCRIPT INSTANCE]: Unable to load script state file {0} for script {1} {2} in {3} {4} (assembly {5}). XML is {6}. Exception {7}{8}", - savedState, ScriptName, ItemID, PrimName, ObjectID, assembly, xml, e.Message, e.StackTrace); + "[SCRIPT INSTANCE]: Not starting script {0} (id {1}) in part {2} (id {3}) in object {4} in {5}. Unable to load script state file {6}. XML is {7}. Exception {8}{9}", + ScriptTask.Name, ScriptTask.ItemID, Part.Name, Part.UUID, Part.ParentGroup.Name, Engine.World.Name, savedState, xml, e.Message, e.StackTrace); } } // else @@ -598,9 +599,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance } else { - m_log.DebugFormat( - "[SCRIPT INSTANCE]: Co-operatively stopping script {0} {1} in {2} {3}", - ScriptName, ItemID, PrimName, ObjectID); + if (DebugLevel >= 1) + m_log.DebugFormat( + "[SCRIPT INSTANCE]: Co-operatively stopping script {0} {1} in {2} {3}", + ScriptName, ItemID, PrimName, ObjectID); // This will terminate the event on next handle check by the script. m_coopSleepHandle.Set(); @@ -609,9 +611,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance // checking is implemented. May want to allow a shorter timeout option later. if (workItem.Wait(TimeSpan.MaxValue)) { - m_log.DebugFormat( - "[SCRIPT INSTANCE]: Co-operatively stopped script {0} {1} in {2} {3}", - ScriptName, ItemID, PrimName, ObjectID); + if (DebugLevel >= 1) + m_log.DebugFormat( + "[SCRIPT INSTANCE]: Co-operatively stopped script {0} {1} in {2} {3}", + ScriptName, ItemID, PrimName, ObjectID); return true; } @@ -922,9 +925,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance } else if ((e is TargetInvocationException) && (e.InnerException is ScriptCoopStopException)) { - m_log.DebugFormat( - "[SCRIPT INSTANCE]: Script {0}.{1} in event {2}, state {3} stopped co-operatively.", - PrimName, ScriptName, data.EventName, State); + if (DebugLevel >= 1) + m_log.DebugFormat( + "[SCRIPT INSTANCE]: Script {0}.{1} in event {2}, state {3} stopped co-operatively.", + PrimName, ScriptName, data.EventName, State); } } } diff --git a/OpenSim/Region/ScriptEngine/XEngine/EventManager.cs b/OpenSim/Region/ScriptEngine/XEngine/EventManager.cs index 9405075e51..afde685d68 100644 --- a/OpenSim/Region/ScriptEngine/XEngine/EventManager.cs +++ b/OpenSim/Region/ScriptEngine/XEngine/EventManager.cs @@ -52,7 +52,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine { myScriptEngine = _ScriptEngine; - m_log.Info("[XEngine] Hooking up to server events"); +// m_log.Info("[XEngine] Hooking up to server events"); myScriptEngine.World.EventManager.OnAttach += attach; myScriptEngine.World.EventManager.OnObjectGrab += touch_start; myScriptEngine.World.EventManager.OnObjectGrabbing += touch; @@ -69,7 +69,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine myScriptEngine.World.EventManager.OnScriptLandColliderStart += land_collision_start; myScriptEngine.World.EventManager.OnScriptLandColliding += land_collision; myScriptEngine.World.EventManager.OnScriptLandColliderEnd += land_collision_end; - IMoneyModule money=myScriptEngine.World.RequestModuleInterface(); + IMoneyModule money = myScriptEngine.World.RequestModuleInterface(); if (money != null) { money.OnObjectPaid+=HandleObjectPaid; diff --git a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs index 604924bd0e..ad79a9b6dd 100644 --- a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs +++ b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs @@ -241,7 +241,11 @@ namespace OpenSim.Region.ScriptEngine.XEngine m_ScriptConfig = configSource.Configs["XEngine"]; m_ConfigSource = configSource; - if (m_ScriptConfig.GetString("ScriptStopStrategy", "abort") == "co-op") + string rawScriptStopStrategy = m_ScriptConfig.GetString("ScriptStopStrategy", "abort"); + + m_log.InfoFormat("[XEngine]: Script stop strategy is {0}", rawScriptStopStrategy); + + if (rawScriptStopStrategy == "co-op") { ScriptClassName = "XEngineScript"; ScriptBaseClassName = typeof(XEngineScriptBase).FullName; @@ -261,15 +265,10 @@ namespace OpenSim.Region.ScriptEngine.XEngine { if (m_ScriptConfig == null) return; + m_ScriptFailCount = 0; m_ScriptErrorMessage = String.Empty; - if (m_ScriptConfig == null) - { -// m_log.ErrorFormat("[XEngine] No script configuration found. Scripts disabled"); - return; - } - m_Enabled = m_ScriptConfig.GetBoolean("Enabled", true); if (!m_Enabled) From 8a22ac3f94a3b8275d794721e0daca5c58e952a2 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Wed, 23 Jan 2013 23:38:08 +0000 Subject: [PATCH 16/17] Pass narrower WaitHandle rather than EventWaitHandle as co-op termination wait handle to script APIs. APIs don't need to reference any methods on EventWaitHandle --- OpenSim/Region/ScriptEngine/Interfaces/IScriptApi.cs | 2 +- .../Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs | 4 ++-- .../Region/ScriptEngine/Shared/Api/Implementation/LS_Api.cs | 2 +- .../Region/ScriptEngine/Shared/Api/Implementation/MOD_Api.cs | 2 +- .../Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/OpenSim/Region/ScriptEngine/Interfaces/IScriptApi.cs b/OpenSim/Region/ScriptEngine/Interfaces/IScriptApi.cs index d2323f56d1..30e99b0d74 100644 --- a/OpenSim/Region/ScriptEngine/Interfaces/IScriptApi.cs +++ b/OpenSim/Region/ScriptEngine/Interfaces/IScriptApi.cs @@ -46,6 +46,6 @@ namespace OpenSim.Region.ScriptEngine.Interfaces /// /param> /// /param> void Initialize( - IScriptEngine scriptEngine, SceneObjectPart host, TaskInventoryItem item, EventWaitHandle coopSleepHandle); + IScriptEngine scriptEngine, SceneObjectPart host, TaskInventoryItem item, WaitHandle coopSleepHandle); } } \ No newline at end of file diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index cee10a8e6e..89ea4e93e3 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -91,7 +91,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api /// Used for script sleeps when we are using co-operative script termination. /// /// null if co-operative script termination is not active - EventWaitHandle m_coopSleepHandle; + WaitHandle m_coopSleepHandle; /// /// The item that hosts this script @@ -118,7 +118,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api protected ISoundModule m_SoundModule = null; public void Initialize( - IScriptEngine scriptEngine, SceneObjectPart host, TaskInventoryItem item, EventWaitHandle coopSleepHandle) + IScriptEngine scriptEngine, SceneObjectPart host, TaskInventoryItem item, WaitHandle coopSleepHandle) { m_ScriptEngine = scriptEngine; m_host = host; diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LS_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LS_Api.cs index a08ccc889e..1d6cb6d4dc 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LS_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LS_Api.cs @@ -63,7 +63,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api internal IScriptModuleComms m_comms = null; public void Initialize( - IScriptEngine scriptEngine, SceneObjectPart host, TaskInventoryItem item, EventWaitHandle coopSleepHandle) + IScriptEngine scriptEngine, SceneObjectPart host, TaskInventoryItem item, WaitHandle coopSleepHandle) { m_ScriptEngine = scriptEngine; m_host = host; diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/MOD_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/MOD_Api.cs index 981499ea92..90456721c0 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/MOD_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/MOD_Api.cs @@ -63,7 +63,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api internal IScriptModuleComms m_comms = null; public void Initialize( - IScriptEngine scriptEngine, SceneObjectPart host, TaskInventoryItem item, EventWaitHandle coopSleepHandle) + IScriptEngine scriptEngine, SceneObjectPart host, TaskInventoryItem item, WaitHandle coopSleepHandle) { m_ScriptEngine = scriptEngine; m_host = host; diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs index 25635ff767..f2f8fd65ab 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs @@ -143,7 +143,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api protected IUrlModule m_UrlModule = null; public void Initialize( - IScriptEngine scriptEngine, SceneObjectPart host, TaskInventoryItem item, EventWaitHandle coopSleepHandle) + IScriptEngine scriptEngine, SceneObjectPart host, TaskInventoryItem item, WaitHandle coopSleepHandle) { m_ScriptEngine = scriptEngine; m_host = host; From c51cae8fe81e26e7bb1cb5de1e3fdc505c01fb0a Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Wed, 23 Jan 2013 23:57:09 +0000 Subject: [PATCH 17/17] Add information on ScriptStopStrategy to [XEngine] in OpenSimDefaults.ini and OpenSim.ini.example. Default remains abort. This setting controls whether scripts are stopped by aborting their threads externally (abort) or by co-operative checks from the compiled script (co-op) co-op should be more stable but this option is experimental. If moving from co-op to abort, existing script DLLs will need to be recompiled. This currently can only be done manually, either by setting DeleteScriptsOnStartup = true for one run or by deleting the script DLL* files in bin/ScriptEngines// One can move from co-op back to abort without recompilation, but reverting back to co-op again will need script recompile --- bin/OpenSim.ini.example | 24 +++++++++++++++++------- bin/OpenSimDefaults.ini | 20 ++++++++++++++------ 2 files changed, 31 insertions(+), 13 deletions(-) diff --git a/bin/OpenSim.ini.example b/bin/OpenSim.ini.example index 658b993488..0fe44e954d 100644 --- a/bin/OpenSim.ini.example +++ b/bin/OpenSim.ini.example @@ -749,13 +749,6 @@ ;; The trade-off may be increased memory usage by the script engine. ; ThreadStackSize = 262144 - ;# {DeleteScriptsOnStartup} {} {Delete previously compiled script DLLs on startup?} (true false) true - ;; Controls whether previously compiled scripts DLLs are deleted on sim restart. If you set this to false - ;; then startup will be considerably faster since scripts won't need to be recompiled. However, then it becomes your responsibility to delete the - ;; compiled scripts if you're recompiling OpenSim from source code and internal interfaces used - ;; by scripts have changed. - ; DeleteScriptsOnStartup = true - ;; Set this to true (the default) to load each script into a separate ;; AppDomain. ;; @@ -768,6 +761,23 @@ ;; Some Windows users have also reported script loading problems when AppDomainLoading = false ; AppDomainLoading = true + ;; Controls whether scripts are stopped by aborting their threads externally (abort) or by co-operative checks from the compiled script (co-op) + ;; co-op will be more stable but this option is currently experimental. + ;; If moving from co-op to abort, existing script DLLs will need to be recompiled. + ;; This currently can only be done manually, either by setting DeleteScriptsOnStartup = true for one run + ;; or by deleting the script DLL* files in bin/ScriptEngines// + ;; One can move from co-op back to abort without recompilation, but reverting back to co-op again will need script recompile + ;; Current valid values are "abort" and "co-op" + ; ScriptStopStrategy = abort + + + ;# {DeleteScriptsOnStartup} {} {Delete previously compiled script DLLs on startup?} (true false) true + ;; Controls whether previously compiled scripts DLLs are deleted on sim restart. If you set this to false + ;; then startup will be considerably faster since scripts won't need to be recompiled. However, then it becomes your responsibility to delete the + ;; compiled scripts if you're recompiling OpenSim from source code and internal interfaces used + ;; by scripts have changed. + ; DeleteScriptsOnStartup = true + ;# {DefaultCompileLanguage} {Enabled:true} {Default script language?} {lsl vb cs} lsl ;; Default language for scripts ; DefaultCompileLanguage = "lsl" diff --git a/bin/OpenSimDefaults.ini b/bin/OpenSimDefaults.ini index 45c3d401c9..391fb0cab2 100644 --- a/bin/OpenSimDefaults.ini +++ b/bin/OpenSimDefaults.ini @@ -1290,6 +1290,20 @@ ; script assemblies AppDomainLoading = true + ; Controls whether previously compiled scripts DLLs are deleted on sim restart. If you set this to false + ; then startup will be considerably faster since scripts won't need to be recompiled. However, then it becomes your responsibility to delete the + ; compiled scripts if you're recompiling OpenSim from source code and internal interfaces used + ; by scripts have changed. + ; DeleteScriptsOnStartup = false + + ; Controls whether scripts are stopped by aborting their threads externally (abort) or by co-operative checks from the compiled script (co-op) + ; co-op will be more stable but this option is currently experimental. + ; If moving from co-op to abort, existing script DLLs will need to be recompiled. + ; This currently can only be done manually, either by setting DeleteScriptsOnStartup = true for one run + ; or by deleting the script DLL* files in bin/ScriptEngines// + ; One can move from co-op back to abort without recompilation, but reverting back to co-op again will need script recompile + ScriptStopStrategy = abort + ; Rate to poll for asynchronous command replies (ms) ; currently unused ;AsyncLLCommandLoopms = 50 @@ -1391,12 +1405,6 @@ ;; Path to script assemblies ; ScriptEnginesPath = "ScriptEngines" - ; Controls whether previously compiled scripts DLLs are deleted on sim restart. If you set this to false - ; then startup will be considerably faster since scripts won't need to be recompiled. However, then it becomes your responsibility to delete the - ; compiled scripts if you're recompiling OpenSim from source code and internal interfaces used - ; by scripts have changed. - ; DeleteScriptsOnStartup = false - [Concierge] ; Enable concierge module