From 01ceb4d17e80b794432062ff3bf3b85f884c9548 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Wed, 7 Feb 2018 19:52:18 +0000 Subject: [PATCH] try to fix xmr on multiregions per instance. Ugly spargetti ...; remove fixes for 2 llparcel functions that should not be needed; remove xmr own API, it has no business having one. --- .../XMREngine/MMRScriptInlines.cs | 56 +++--- .../ScriptEngine/XMREngine/XMREngine.cs | 177 ++++++++++++++++- .../ScriptEngine/XMREngine/XMRInstAbstract.cs | 50 ++--- .../ScriptEngine/XMREngine/XMRInstBackend.cs | 13 +- .../ScriptEngine/XMREngine/XMRInstCapture.cs | 183 +++++++---------- .../ScriptEngine/XMREngine/XMRInstCtor.cs | 82 +------- .../ScriptEngine/XMREngine/XMRScriptThread.cs | 184 ++---------------- .../XMREngine/XMRScriptUThread.cs | 34 +++- 8 files changed, 338 insertions(+), 441 deletions(-) diff --git a/OpenSim/Region/ScriptEngine/XMREngine/MMRScriptInlines.cs b/OpenSim/Region/ScriptEngine/XMREngine/MMRScriptInlines.cs index dc00001007..fcb4b66dc4 100644 --- a/OpenSim/Region/ScriptEngine/XMREngine/MMRScriptInlines.cs +++ b/OpenSim/Region/ScriptEngine/XMREngine/MMRScriptInlines.cs @@ -589,11 +589,11 @@ namespace OpenSim.Region.ScriptEngine.XMREngine * @brief Generate code for the usual ll...() functions. */ public class TokenDeclInline_BEApi : TokenDeclInline { - private static readonly MethodInfo fixLLParcelMediaQuery = ScriptCodeGen.GetStaticMethod - (typeof (XMRInstAbstract), "FixLLParcelMediaQuery", new Type[] { typeof (LSL_List) }); +// private static readonly MethodInfo fixLLParcelMediaQuery = ScriptCodeGen.GetStaticMethod +// (typeof (XMRInstAbstract), "FixLLParcelMediaQuery", new Type[] { typeof (LSL_List) }); - private static readonly MethodInfo fixLLParcelMediaCommandList = ScriptCodeGen.GetStaticMethod - (typeof (XMRInstAbstract), "FixLLParcelMediaCommandList", new Type[] { typeof (LSL_List) }); +// private static readonly MethodInfo fixLLParcelMediaCommandList = ScriptCodeGen.GetStaticMethod +// (typeof (XMRInstAbstract), "FixLLParcelMediaCommandList", new Type[] { typeof (LSL_List) }); public bool doCheckRun; private FieldInfo apiContextField; @@ -626,39 +626,41 @@ namespace OpenSim.Region.ScriptEngine.XMREngine */ public override void CodeGen (ScriptCodeGen scg, Token errorAt, CompValuTemp result, CompValu[] args) { - if (isTaggedCallsCheckRun) { // see if 'xmr' method that calls CheckRun() internally - new ScriptCodeGen.CallLabel (scg, errorAt); // if so, put a call label immediately before it - // .. so restoring the frame will jump immediately to the - // .. call without re-executing any code before this + if (isTaggedCallsCheckRun) + { // see if 'xmr' method that calls CheckRun() internally + new ScriptCodeGen.CallLabel (scg, errorAt); // if so, put a call label immediately before it + // .. so restoring the frame will jump immediately to the + // .. call without re-executing any code before this } - if (!methInfo.IsStatic) { + if (!methInfo.IsStatic) + { scg.PushXMRInst (); // XMRInstanceSuperType pointer - if (apiContextField != null) { + if (apiContextField != null) // 'this' pointer for API function scg.ilGen.Emit (errorAt, OpCodes.Ldfld, apiContextField); - // 'this' pointer for API function - } + } - for (int i = 0; i < args.Length; i ++) { // push arguments, boxing/unboxing as needed + for (int i = 0; i < args.Length; i ++) // push arguments, boxing/unboxing as needed args[i].PushVal (scg, errorAt, argDecl.types[i]); - } - if (methInfo.Name == "llParcelMediaQuery") { - scg.ilGen.Emit (errorAt, OpCodes.Call, fixLLParcelMediaQuery); - } - if (methInfo.Name == "llParcelMediaCommandList") { - scg.ilGen.Emit (errorAt, OpCodes.Call, fixLLParcelMediaCommandList); - } - if (methInfo.IsVirtual) { // call API function + + // this should not be needed +// if (methInfo.Name == "llParcelMediaQuery") { +// scg.ilGen.Emit (errorAt, OpCodes.Call, fixLLParcelMediaQuery); +// } + // this should not be needed +// if (methInfo.Name == "llParcelMediaCommandList") { +// scg.ilGen.Emit (errorAt, OpCodes.Call, fixLLParcelMediaCommandList); +// } + if (methInfo.IsVirtual) // call API function scg.ilGen.Emit (errorAt, OpCodes.Callvirt, methInfo); - } else { + else scg.ilGen.Emit (errorAt, OpCodes.Call, methInfo); - } + result.Pop (scg, errorAt, retType); // pop result, boxing/unboxing as needed - if (isTaggedCallsCheckRun) { + if (isTaggedCallsCheckRun) scg.openCallLabel = null; - } - if (doCheckRun) { + + if (doCheckRun) scg.EmitCallCheckRun (errorAt, false); // maybe call CheckRun() - } } } } diff --git a/OpenSim/Region/ScriptEngine/XMREngine/XMREngine.cs b/OpenSim/Region/ScriptEngine/XMREngine/XMREngine.cs index aa8573cbfe..7447f2f55e 100644 --- a/OpenSim/Region/ScriptEngine/XMREngine/XMREngine.cs +++ b/OpenSim/Region/ScriptEngine/XMREngine/XMREngine.cs @@ -99,7 +99,18 @@ namespace OpenSim.Region.ScriptEngine.XMREngine new Dictionary (); private int m_StackSize; private int m_HeapSize; + private XMRScriptThread[] m_ScriptThreads; + private int m_WakeUpOne = 0; + public object m_WakeUpLock = new object(); + private Dictionary m_AllThreads = new Dictionary (); + + private bool m_SuspendScriptThreadFlag = false; + /** + * @brief Something was just added to the Start or Yield queue so + * wake one of the XMRScriptThread instances to run it. + */ + private Thread m_SleepThread = null; private bool m_Exiting = false; @@ -165,6 +176,36 @@ namespace OpenSim.Region.ScriptEngine.XMREngine get { return scriptReferencedAssemblies; } } + public void WakeUpOne() + { + lock (m_WakeUpLock) + { + m_WakeUpOne++; + Monitor.Pulse(m_WakeUpLock); + } + } + + public void AddThread(Thread thd, XMRScriptThread xthd) + { + lock(m_AllThreads) + m_AllThreads.Add(thd, xthd); + } + + public void RemoveThread(Thread thd) + { + lock(m_AllThreads) + m_AllThreads.Remove(thd); + } + + public XMRScriptThread CurrentScriptThread () + { + XMRScriptThread st; + lock (m_AllThreads) + m_AllThreads.TryGetValue (Thread.CurrentThread, out st); + + return st; + } + public void Initialise(IConfigSource config) { TraceCalls("[XMREngine]: Initialize entry"); @@ -235,7 +276,10 @@ namespace OpenSim.Region.ScriptEngine.XMREngine } for (int i = 0; i < numThreadScriptWorkers; i ++) - m_ScriptThreads[i] = new XMRScriptThread(this, i); + { + m_ScriptThreads[i] = new XMRScriptThread(this, i);; + } + m_SleepThread = StartMyThread(RunSleepThread, "xmrengine sleep", ThreadPriority.Normal); @@ -678,6 +722,8 @@ namespace OpenSim.Region.ScriptEngine.XMREngine XMRScriptThread scriptThread = m_ScriptThreads[i]; if (scriptThread != null) { + scriptThread.WakeUpScriptThread(); + Monitor.PulseAll (m_WakeUpLock); scriptThread.Terminate(); m_ScriptThreads[i] = null; } @@ -722,7 +768,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine m_Scene.EventManager.TriggerEmptyScriptCompileQueue (0, ""); m_StartProcessing = true; for (int i = 0; i < numThreadScriptWorkers; i ++) { - XMRScriptThread.WakeUpOne(); + WakeUpOne(); } m_log.Debug ("[XMREngine]: StartProcessing return"); } @@ -832,15 +878,18 @@ namespace OpenSim.Region.ScriptEngine.XMREngine case "resume": m_log.Info ("[XMREngine]: resuming scripts"); + m_SuspendScriptThreadFlag = false; for (int i = 0; i < numThreadScriptWorkers; i ++) - m_ScriptThreads[i].ResumeThread(); - + m_ScriptThreads[i].WakeUpScriptThread(); + Monitor.PulseAll(m_WakeUpLock); break; case "suspend": m_log.Info ("[XMREngine]: suspending scripts"); + m_SuspendScriptThreadFlag = true; for (int i = 0; i < numThreadScriptWorkers; i ++) - m_ScriptThreads[i].SuspendThread(); + m_ScriptThreads[i].WakeUpScriptThread(); + Monitor.PulseAll(m_WakeUpLock); break; case "tracecalls": @@ -1545,7 +1594,14 @@ namespace OpenSim.Region.ScriptEngine.XMREngine if (inst.m_IState != XMRInstState.ONSTARTQ) throw new Exception("bad state"); m_StartQueue.InsertTail(inst); } - XMRScriptThread.WakeUpOne(); + WakeUpOne(); + } + + public void QueueToTrunk(ThreadStart thds) + { + lock (m_WakeUpLock) + m_ThunkQueue.Enqueue (thds); + WakeUpOne(); } /** @@ -1572,7 +1628,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine // Make sure the OS thread is running so it will see the script. - XMRScriptThread.WakeUpOne(); + WakeUpOne(); } /** @@ -1724,7 +1780,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine inst.m_IState = XMRInstState.ONYIELDQ; m_YieldQueue.InsertTail(inst); } - XMRScriptThread.WakeUpOne (); + WakeUpOne (); } } @@ -1934,12 +1990,113 @@ namespace OpenSim.Region.ScriptEngine.XMREngine public static void UpdateMyThread () { - Watchdog.UpdateThread (); + Watchdog.UpdateThread(); } public static void MyThreadExiting () { - Watchdog.RemoveThread (true); + Watchdog.RemoveThread(true); + } + + public void RunScriptThread(XMRScriptThread xthd) + { + XMRInstance inst; + while (!m_Exiting) + { + Watchdog.UpdateThread(); + + /* + * Handle 'xmr resume/suspend' commands. + */ + if (m_SuspendScriptThreadFlag) + { + lock (m_WakeUpLock) + { + while (m_SuspendScriptThreadFlag && + !m_Exiting && + (m_ThunkQueue.Count == 0)) + { + Monitor.Wait (m_WakeUpLock, Watchdog.DEFAULT_WATCHDOG_TIMEOUT_MS / 2); + XMREngine.UpdateMyThread (); + } + } + } + + /* + * Maybe there are some scripts waiting to be migrated in or out. + */ + ThreadStart thunk = null; + lock (m_WakeUpLock) + { + if (m_ThunkQueue.Count > 0) + thunk = m_ThunkQueue.Dequeue (); + } + if (thunk != null) + { + inst = (XMRInstance)thunk.Target; + thunk (); + if (m_Exiting || m_SuspendScriptThreadFlag) + continue; + } + + if (m_StartProcessing) + { + // If event just queued to any idle scripts + // start them right away. But only start so + // many so we can make some progress on yield + // queue. + + int numStarts; + for (numStarts = 5; -- numStarts >= 0;) + { + lock (m_StartQueue) + { + inst = m_StartQueue.RemoveHead(); + } + if (inst == null) break; + if (inst.m_IState != XMRInstState.ONSTARTQ) throw new Exception("bad state"); + xthd.RunInstance (inst); + if (m_Exiting || m_SuspendScriptThreadFlag) + continue; + } + + // If there is something to run, run it + // then rescan from the beginning in case + // a lot of things have changed meanwhile. + // + // These are considered lower priority than + // m_StartQueue as they have been taking at + // least one quantum of CPU time and event + // handlers are supposed to be quick. + + lock (m_YieldQueue) + { + inst = m_YieldQueue.RemoveHead(); + } + if (inst != null) + { + if (inst.m_IState != XMRInstState.ONYIELDQ) throw new Exception("bad state"); + xthd.RunInstance(inst); + numStarts = -1; + } + + // If we left something dangling in the m_StartQueue or m_YieldQueue, go back to check it. + if (m_Exiting || numStarts < 0) + continue; + } + + // Nothing to do, sleep. + lock (m_WakeUpLock) + { + if (!xthd.m_WakeUpThis && (m_WakeUpOne <= 0) && !m_Exiting) + Monitor.Wait(m_WakeUpLock, Watchdog.DEFAULT_WATCHDOG_TIMEOUT_MS / 2); + + xthd.m_WakeUpThis = false; + if ((m_WakeUpOne > 0) && (--m_WakeUpOne > 0)) + Monitor.Pulse (m_WakeUpLock); + } + } + Watchdog.RemoveThread(true); } } } diff --git a/OpenSim/Region/ScriptEngine/XMREngine/XMRInstAbstract.cs b/OpenSim/Region/ScriptEngine/XMREngine/XMRInstAbstract.cs index 82759eecbd..1ea05b6042 100644 --- a/OpenSim/Region/ScriptEngine/XMREngine/XMRInstAbstract.cs +++ b/OpenSim/Region/ScriptEngine/XMREngine/XMRInstAbstract.cs @@ -491,11 +491,9 @@ namespace OpenSim.Region.ScriptEngine.XMREngine { if (this.newStateCode < 0) { + // Process event given by 'stateCode' and 'eventCode'. + // The event handler should call CheckRun() as often as convenient. - /* - * Process event given by 'stateCode' and 'eventCode'. - * The event handler should call CheckRun() as often as convenient. - */ int newState = this.stateCode; seh = this.m_ObjCode.scriptEventHandlerTable[newState,(int)this.eventCode]; if (seh != null) @@ -512,25 +510,19 @@ namespace OpenSim.Region.ScriptEngine.XMREngine this.ehArgs = null; // we are done with them and no args for // exit_state()/enter_state() anyway - /* - * The usual case is no state change. - * Even a 'state ;' statement has no effect except to exit out. - * It does not execute the state_exit() or state_entry() handlers. - * See http://wiki.secondlife.com/wiki/State - */ + // The usual case is no state change. + // Even a 'state ;' statement has no effect except to exit out. + // It does not execute the state_exit() or state_entry() handlers. + // See http://wiki.secondlife.com/wiki/State if (newState == this.stateCode) break; - /* - * Save new state in a more permanent location in case we - * get serialized out while in the state_exit() handler. - */ + // Save new state in a more permanent location in case we + // get serialized out while in the state_exit() handler. this.newStateCode = newState; } - /* - * Call old state's state_exit() handler. - */ + // Call old state's state_exit() handler. this.eventCode = ScriptEventCode.state_exit; seh = this.m_ObjCode.scriptEventHandlerTable[this.stateCode,(int)ScriptEventCode.state_exit]; if (seh != null) @@ -545,27 +537,19 @@ namespace OpenSim.Region.ScriptEngine.XMREngine } } - /* - * Switch over to the new state's state_entry() handler. - */ + // Switch over to the new state's state_entry() handler. this.stateCode = this.newStateCode; this.eventCode = ScriptEventCode.state_entry; this.newStateCode = -1; - /* - * Now that the old state can't possibly start any more activity, - * cancel any listening handlers, etc, of the old state. - */ + // Now that the old state can't possibly start any more activity, + // cancel any listening handlers, etc, of the old state. this.StateChange (); - /* - * Loop back to execute new state's state_entry() handler. - */ + // Loop back to execute new state's state_entry() handler. } - /* - * Event no longer being processed. - */ + // Event no longer being processed. this.eventCode = ScriptEventCode.None; } @@ -642,6 +626,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine * @brief Convert all LSL_Integers in a list to System.Int32s, * as required by llParcelMediaQuery(). */ +/* public static LSL_List FixLLParcelMediaQuery (LSL_List oldlist) { object[] oldarray = oldlist.Data; @@ -655,11 +640,12 @@ namespace OpenSim.Region.ScriptEngine.XMREngine } return new LSL_List (newarray); } - +*/ /** * @brief Convert *SOME* LSL_Integers in a list to System.Int32s, * as required by llParcelMediaCommandList(). */ +/* public static LSL_List FixLLParcelMediaCommandList (LSL_List oldlist) { object[] oldarray = oldlist.Data; @@ -696,7 +682,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine } return new LSL_List (newarray); } - +*/ public static int xmrHashCode (int i) { return i.GetHashCode (); diff --git a/OpenSim/Region/ScriptEngine/XMREngine/XMRInstBackend.cs b/OpenSim/Region/ScriptEngine/XMREngine/XMRInstBackend.cs index edbd5ce9bc..a24036a546 100644 --- a/OpenSim/Region/ScriptEngine/XMREngine/XMRInstBackend.cs +++ b/OpenSim/Region/ScriptEngine/XMREngine/XMRInstBackend.cs @@ -32,11 +32,6 @@ using OpenMetaverse; using OpenSim.Framework; using OpenSim.Region.ScriptEngine.Shared; using OpenSim.Region.ScriptEngine.Shared.Api; -using OpenSim.Region.ScriptEngine.Shared.ScriptBase; -using OpenSim.Region.ScriptEngine.XMREngine; -using OpenSim.Region.Framework.Scenes; -using OpenSim.Region.Framework.Scenes.Scripting; -using OpenSim.Region.Framework.Interfaces; using log4net; using LSL_Float = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLFloat; @@ -88,6 +83,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine * -2: no av granted perms * -3: av not in region */ +/* engines should not have own API public int xmrSeatAvatar (bool owner) { // Get avatar to be seated and make sure they have given us ANIMATION permission @@ -118,7 +114,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine presence.HandleAgentRequestSit (null, UUID.Zero, m_host.UUID, OpenMetaverse.Vector3.Zero); return 0; } - +*/ /** * @brief llTeleportAgent() is broken in that if you pass it a landmark, * it still subjects the position to spawn points, as it always @@ -129,6 +125,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine * @param landmark = inventory name or UUID of a landmark object * @param lookat = looking direction after teleport */ +/* engines should not have own API public void xmrTeleportAgent2Landmark (string agent, string landmark, LSL_Vector lookat) { // find out about agent to be teleported @@ -172,13 +169,14 @@ namespace OpenSim.Region.ScriptEngine.XMREngine lookat, (uint)TeleportFlags.ViaLandmark); } - +*/ /** * @brief Allow any member of group given by config SetParcelMusicURLGroup to set music URL. * Code modelled after llSetParcelMusicURL(). * @param newurl = new URL to set (or "" to leave it alone) * @returns previous URL string */ +/* engines should not have own API public string xmrSetParcelMusicURLGroup (string newurl) { string groupname = m_ScriptEngine.Config.GetString ("SetParcelMusicURLGroup", ""); @@ -200,6 +198,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine if ((newurl != null) && (newurl != "")) land.SetMusicUrl (newurl); return oldurl; } +*/ } public partial class XMRInstance diff --git a/OpenSim/Region/ScriptEngine/XMREngine/XMRInstCapture.cs b/OpenSim/Region/ScriptEngine/XMREngine/XMRInstCapture.cs index 8950d634ec..ed331082e6 100644 --- a/OpenSim/Region/ScriptEngine/XMREngine/XMRInstCapture.cs +++ b/OpenSim/Region/ScriptEngine/XMREngine/XMRInstCapture.cs @@ -27,22 +27,10 @@ using System; using System.Threading; -using System.Reflection; -using System.Collections; -using System.Collections.Generic; -using System.Runtime.Remoting.Lifetime; -using System.Security.Policy; using System.IO; using System.Xml; -using System.Text; -using OpenMetaverse; -using OpenSim.Framework; -using OpenSim.Region.ScriptEngine.Interfaces; using OpenSim.Region.ScriptEngine.Shared; using OpenSim.Region.ScriptEngine.Shared.Api; -using OpenSim.Region.ScriptEngine.Shared.ScriptBase; -using OpenSim.Region.ScriptEngine.XMREngine; -using OpenSim.Region.Framework.Scenes; using log4net; using LSL_Float = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLFloat; @@ -78,9 +66,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine */ public XmlElement GetExecutionState(XmlDocument doc) { - /* - * When we're detaching an attachment, we need to wait here. - */ + // When we're detaching an attachment, we need to wait here. // Change this to a 5 second timeout. If things do mess up, // we don't want to be stuck forever. @@ -92,20 +78,16 @@ namespace OpenSim.Region.ScriptEngine.XMREngine scriptStateN.SetAttribute("Asset", m_Item.AssetID.ToString()); scriptStateN.SetAttribute ("SourceHash", m_ObjCode.sourceHash); - /* - * Make sure we aren't executing part of the script so it stays - * stable. Setting suspendOnCheckRun tells CheckRun() to suspend - * and return out so RunOne() will release the lock asap. - */ + // Make sure we aren't executing part of the script so it stays + // stable. Setting suspendOnCheckRun tells CheckRun() to suspend + // and return out so RunOne() will release the lock asap. suspendOnCheckRunHold = true; lock (m_RunLock) { m_RunOnePhase = "GetExecutionState enter"; CheckRunLockInvariants(true); - /* - * Get copy of script globals and stack in relocateable form. - */ + // Get copy of script globals and stack in relocateable form. MemoryStream snapshotStream = new MemoryStream(); MigrateOutEventHandler(snapshotStream); Byte[] snapshotBytes = snapshotStream.ToArray(); @@ -116,25 +98,19 @@ namespace OpenSim.Region.ScriptEngine.XMREngine scriptStateN.AppendChild(snapshotN); m_RunOnePhase = "GetExecutionState B"; CheckRunLockInvariants(true); - /* - * "Running" says whether or not we are accepting new events. - */ + // "Running" says whether or not we are accepting new events. XmlElement runningN = doc.CreateElement("", "Running", ""); runningN.AppendChild(doc.CreateTextNode(m_Running.ToString())); scriptStateN.AppendChild(runningN); m_RunOnePhase = "GetExecutionState C"; CheckRunLockInvariants(true); - /* - * "DoGblInit" says whether or not default:state_entry() will init global vars. - */ + // "DoGblInit" says whether or not default:state_entry() will init global vars. XmlElement doGblInitN = doc.CreateElement("", "DoGblInit", ""); doGblInitN.AppendChild(doc.CreateTextNode(doGblInit.ToString())); scriptStateN.AppendChild(doGblInitN); m_RunOnePhase = "GetExecutionState D"; CheckRunLockInvariants(true); - /* - * More misc data. - */ + // More misc data. XmlNode permissionsN = doc.CreateElement("", "Permissions", ""); scriptStateN.AppendChild(permissionsN); @@ -147,10 +123,8 @@ namespace OpenSim.Region.ScriptEngine.XMREngine permissionsN.Attributes.Append(maskA); m_RunOnePhase = "GetExecutionState E"; CheckRunLockInvariants(true); - /* - * "DetectParams" are returned by llDetected...() script functions - * for the currently active event, if any. - */ + // "DetectParams" are returned by llDetected...() script functions + // for the currently active event, if any. if (m_DetectParams != null) { XmlElement detParArrayN = doc.CreateElement("", "DetectArray", ""); @@ -159,16 +133,14 @@ namespace OpenSim.Region.ScriptEngine.XMREngine } m_RunOnePhase = "GetExecutionState F"; CheckRunLockInvariants(true); - /* - * Save any events we have in the queue. - * - * - * ... ... - * ... ... - * - * ... - * - */ + // Save any events we have in the queue. + // + // + // ... ... + // ... ... + // + // ... + // XmlElement queuedEventsN = doc.CreateElement("", "EventQueue", ""); lock (m_QueueLock) { @@ -184,31 +156,24 @@ namespace OpenSim.Region.ScriptEngine.XMREngine scriptStateN.AppendChild(queuedEventsN); m_RunOnePhase = "GetExecutionState G"; CheckRunLockInvariants(true); - /* - * "Plugins" indicate enabled timers and listens, etc. - */ + // "Plugins" indicate enabled timers and listens, etc. Object[] pluginData = - AsyncCommandManager.GetSerializationData(m_Engine, - m_ItemID); + AsyncCommandManager.GetSerializationData(m_Engine, m_ItemID); XmlNode plugins = doc.CreateElement("", "Plugins", ""); AppendXMLObjectArray(doc, plugins, pluginData, "plugin"); scriptStateN.AppendChild(plugins); m_RunOnePhase = "GetExecutionState H"; CheckRunLockInvariants(true); - /* - * Let script run again. - */ + // Let script run again. suspendOnCheckRunHold = false; m_RunOnePhase = "GetExecutionState leave"; CheckRunLockInvariants(true); } - /* - * scriptStateN represents the contents of the .state file so - * write the .state file while we are here. - */ + // scriptStateN represents the contents of the .state file so + // write the .state file while we are here. FileStream fs = File.Create(m_StateFileName); StreamWriter sw = new StreamWriter(fs); sw.Write(scriptStateN.OuterXml); @@ -233,32 +198,33 @@ namespace OpenSim.Region.ScriptEngine.XMREngine // do all the work in the MigrateOutEventHandlerThread() method below moehstream = stream; - XMRScriptThread cst = XMRScriptThread.CurrentScriptThread (); - if (cst != null) { + XMRScriptThread cst = m_Engine.CurrentScriptThread (); + if (cst != null) + { // we might be getting called inside some LSL Api function // so we are already in script thread and thus must do // migration directly MigrateOutEventHandlerThread (); - } else { - + } + else + { // some other thread, do migration via a script thread - lock (XMRScriptThread.m_WakeUpLock) { - m_Engine.m_ThunkQueue.Enqueue (this.MigrateOutEventHandlerThread); - } - XMRScriptThread.WakeUpOne (); + m_Engine.QueueToTrunk(this.MigrateOutEventHandlerThread); // wait for it to complete - lock (moehdone) { - while (moehstream != null) { + lock (moehdone) + { + while (moehstream != null) Monitor.Wait (moehdone); - } } } // maybe it threw up - if (moehexcep != null) throw moehexcep; + if (moehexcep != null) + throw moehexcep; } + private Exception moehexcep; private object moehdone = new object (); private Stream moehstream; @@ -266,64 +232,65 @@ namespace OpenSim.Region.ScriptEngine.XMREngine { Exception except; - try { - - /* - * Resume the microthread and it will throw a StackCaptureException() - * with the stack frames saved to this.stackFrames. - * Then write the saved stack frames to the output stream. - * - * There is a stack only if the event code is not None. - */ - if (this.eventCode != ScriptEventCode.None) { - + try + { + // Resume the microthread and it will throw a StackCaptureException() + // with the stack frames saved to this.stackFrames. + // Then write the saved stack frames to the output stream. + // + // There is a stack only if the event code is not None. + if (this.eventCode != ScriptEventCode.None) + { // tell microthread to continue // it should see captureStackFrames and throw StackCaptureException() // ...generating XMRStackFrames as it unwinds this.captureStackFrames = true; +// this.suspendOnCheckRunTemp = true; except = this.microthread.ResumeEx (); this.captureStackFrames = false; - if (except == null) { + + if (except == null) throw new Exception ("stack save did not complete"); - } - if (!(except is StackCaptureException)) { + + if (!(except is StackCaptureException)) throw except; - } } - /* - * Write script state out, frames and all, to the stream. - * Does not change script state. - */ + // Write script state out, frames and all, to the stream. + // Does not change script state. + moehstream.WriteByte (migrationVersion); moehstream.WriteByte ((byte)16); this.MigrateOut (new BinaryWriter (moehstream)); - /* - * Now restore script stack. - * Microthread will suspend inside CheckRun() when restore is complete. - */ - if (this.eventCode != ScriptEventCode.None) { + // Now restore script stack. + // Microthread will suspend inside CheckRun() when restore is complete. + if (this.eventCode != ScriptEventCode.None) + { this.stackFramesRestored = false; except = this.microthread.StartEx (); - if (except != null) { - throw except; - } - if (!this.stackFramesRestored) { - throw new Exception ("restore after save did not complete"); - } - } - } catch (Exception e) { - moehexcep = e; - } finally { - // make sure CheckRunLockInvariants() won't puque - if (this.microthread.Active () == 0) { - this.eventCode = ScriptEventCode.None; + if (except != null) + throw except; + + if (!this.stackFramesRestored) + throw new Exception ("restore after save did not complete"); + } + } + catch (Exception e) + { + moehexcep = e; + } + finally + { + // make sure CheckRunLockInvariants() won't puque + if (this.microthread.Active () == 0) + this.eventCode = ScriptEventCode.None; // wake the MigrateOutEventHandler() method above - lock (moehdone) { + lock (moehdone) + { moehstream = null; Monitor.Pulse (moehdone); } diff --git a/OpenSim/Region/ScriptEngine/XMREngine/XMRInstCtor.cs b/OpenSim/Region/ScriptEngine/XMREngine/XMRInstCtor.cs index 1cf1ad15e5..7ae8c47243 100644 --- a/OpenSim/Region/ScriptEngine/XMREngine/XMRInstCtor.cs +++ b/OpenSim/Region/ScriptEngine/XMREngine/XMRInstCtor.cs @@ -695,7 +695,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine // do all the work in the MigrateInEventHandlerThread() method below miehstream = stream; - XMRScriptThread cst = XMRScriptThread.CurrentScriptThread (); + XMRScriptThread cst = m_Engine.CurrentScriptThread (); if (cst != null) { // in case we are getting called inside some LSL Api function @@ -704,11 +704,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine else { // some other thread, do migration via a script thread - lock (XMRScriptThread.m_WakeUpLock) - { - m_Engine.m_ThunkQueue.Enqueue (this.MigrateInEventHandlerThread); - } - XMRScriptThread.WakeUpOne (); + m_Engine.QueueToTrunk(this.MigrateInEventHandlerThread); // wait for it to complete lock (miehdone) @@ -777,79 +773,5 @@ namespace OpenSim.Region.ScriptEngine.XMREngine } } } - - /** - * See if permitted by configuration file. - * See OSSL_Api.CheckThreatLevelTest(). - */ - public string CheckFetchbinaryAllowed () - { - string ownerPerm = m_Engine.Config.GetString ("Allow_fetchbinary", ""); - UUID ownerID = m_Item.OwnerID; - string[] ids = ownerPerm.Split (new char[] { ',' }); - foreach (string id in ids) - { - string curuc = id.Trim().ToUpperInvariant(); - - switch (curuc) - { - case "ESTATE_MANAGER": - if (m_Engine.m_Scene.RegionInfo.EstateSettings.IsEstateManagerOrOwner (ownerID) && - (m_Engine.m_Scene.RegionInfo.EstateSettings.EstateOwner != ownerID)) - return null; - - break; - - case "ESTATE_OWNER": - if (m_Engine.m_Scene.RegionInfo.EstateSettings.EstateOwner == ownerID) - return null; - - break; - - case "PARCEL_GROUP_MEMBER": - ILandObject land = m_Engine.m_Scene.LandChannel.GetLandObject (m_Part.AbsolutePosition); - if (land.LandData.GroupID == m_Item.GroupID && land.LandData.GroupID != UUID.Zero) - return null; - - break; - - case "PARCEL_OWNER": - ILandObject Oland = m_Engine.m_Scene.LandChannel.GetLandObject (m_Part.AbsolutePosition); - if (Oland.LandData.OwnerID == ownerID) - return null; - - break; - - case "TRUE": - return null; - - default: - UUID uuid; - if (UUID.TryParse (curuc, out uuid)) - if (uuid == ownerID) return null; - - break; - } - } - - string creatorPerm = m_Engine.Config.GetString ("Creators_fetchbinary", ""); - UUID creatorID = m_Item.CreatorID; - ids = creatorPerm.Split (new char[] { ',' }); - foreach (string id in ids) - { - string current = id.Trim (); - UUID uuid; - if (UUID.TryParse (current, out uuid)) - { - if (uuid != UUID.Zero) - { - if (creatorID == uuid) - return null; - } - } - } - - return "fetchbinary not enabled for owner " + ownerID + " creator " + creatorID; - } } } diff --git a/OpenSim/Region/ScriptEngine/XMREngine/XMRScriptThread.cs b/OpenSim/Region/ScriptEngine/XMREngine/XMRScriptThread.cs index 6470477579..710355643f 100644 --- a/OpenSim/Region/ScriptEngine/XMREngine/XMRScriptThread.cs +++ b/OpenSim/Region/ScriptEngine/XMREngine/XMRScriptThread.cs @@ -32,7 +32,6 @@ using System.Threading; namespace OpenSim.Region.ScriptEngine.XMREngine { - /** * @brief There are NUMSCRIPTHREADWKRS of these. * Each sits in a loop checking the Start and Yield queues for @@ -40,35 +39,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine */ public class XMRScriptThread { - private static int m_WakeUpOne = 0; - public static object m_WakeUpLock = new object(); - private static Dictionary m_AllThreads = new Dictionary (); - - /** - * @brief Something was just added to the Start or Yield queue so - * wake one of the XMRScriptThread instances to run it. - */ - public static void WakeUpOne() - { - lock (m_WakeUpLock) - { - m_WakeUpOne ++; - Monitor.Pulse (m_WakeUpLock); - } - } - - public static XMRScriptThread CurrentScriptThread () - { - XMRScriptThread st; - lock (m_AllThreads) { - m_AllThreads.TryGetValue (Thread.CurrentThread, out st); - } - return st; - } - - private bool m_Exiting = false; - private bool m_SuspendScriptThreadFlag = false; - private bool m_WakeUpThis = false; + public bool m_WakeUpThis = false; public DateTime m_LastRanAt = DateTime.MinValue; public int m_ScriptThreadTID = 0; public long m_ScriptExecTime = 0; @@ -80,164 +51,43 @@ namespace OpenSim.Region.ScriptEngine.XMREngine { engine = eng; if(i < 0) - thd = XMREngine.StartMyThread (RunScriptThread, "xmrengine script", ThreadPriority.Normal); + thd = XMREngine.StartMyThread(RunScriptThread, "xmrengine script", ThreadPriority.Normal); else - thd = XMREngine.StartMyThread (RunScriptThread, "xmrengineExec" + i.ToString(), ThreadPriority.Normal); - lock (m_AllThreads) - m_AllThreads.Add (thd, this); - } - - public void SuspendThread() - { - m_SuspendScriptThreadFlag = true; - WakeUpScriptThread(); - } - - public void ResumeThread() - { - m_SuspendScriptThreadFlag = false; - WakeUpScriptThread(); + thd = XMREngine.StartMyThread(RunScriptThread, "xmrengineExec" + i.ToString(), ThreadPriority.Normal); + engine.AddThread(thd, this); + m_ScriptThreadTID = thd.ManagedThreadId; } public void Terminate() { - m_Exiting = true; - WakeUpScriptThread(); + m_WakeUpThis = true; if(!thd.Join(250)) thd.Abort(); - lock (m_AllThreads) - m_AllThreads.Remove (thd); + + engine.RemoveThread(thd); thd = null; } - - public void TimeSlice() - { - XMRInstance instance = m_RunInstance; - if (instance != null) - instance.suspendOnCheckRunTemp = true; - } - + /** * @brief Wake up this XMRScriptThread instance. */ - private void WakeUpScriptThread() + public void WakeUpScriptThread() { - lock (m_WakeUpLock) - { m_WakeUpThis = true; - Monitor.PulseAll (m_WakeUpLock); - } - } - - /** - * @brief Thread that runs the scripts. - */ - private void RunScriptThread() - { - XMRInstance inst; - m_ScriptThreadTID = System.Threading.Thread.CurrentThread.ManagedThreadId; - - while (!m_Exiting) - { - XMREngine.UpdateMyThread (); - - /* - * Handle 'xmr resume/suspend' commands. - */ - if (m_SuspendScriptThreadFlag) - { - lock (m_WakeUpLock) { - while (m_SuspendScriptThreadFlag && - !m_Exiting && - (engine.m_ThunkQueue.Count == 0)) - { - Monitor.Wait (m_WakeUpLock, Watchdog.DEFAULT_WATCHDOG_TIMEOUT_MS / 2); - XMREngine.UpdateMyThread (); - } - } - } - - /* - * Maybe there are some scripts waiting to be migrated in or out. - */ - ThreadStart thunk = null; - lock (m_WakeUpLock) - { - if (engine.m_ThunkQueue.Count > 0) - thunk = engine.m_ThunkQueue.Dequeue (); - } - if (thunk != null) - { - inst = (XMRInstance)thunk.Target; - thunk (); - continue; - } - - if (engine.m_StartProcessing) - { - // If event just queued to any idle scripts - // start them right away. But only start so - // many so we can make some progress on yield - // queue. - - int numStarts; - for (numStarts = 5; -- numStarts >= 0;) - { - lock (engine.m_StartQueue) - { - inst = engine.m_StartQueue.RemoveHead(); - } - if (inst == null) break; - if (inst.m_IState != XMRInstState.ONSTARTQ) throw new Exception("bad state"); - RunInstance (inst); - } - - // If there is something to run, run it - // then rescan from the beginning in case - // a lot of things have changed meanwhile. - // - // These are considered lower priority than - // m_StartQueue as they have been taking at - // least one quantum of CPU time and event - // handlers are supposed to be quick. - - lock (engine.m_YieldQueue) - { - inst = engine.m_YieldQueue.RemoveHead(); - } - if (inst != null) - { - if (inst.m_IState != XMRInstState.ONYIELDQ) throw new Exception("bad state"); - RunInstance(inst); - numStarts = -1; - } - - // If we left something dangling in the m_StartQueue or m_YieldQueue, go back to check it. - if (numStarts < 0) - continue; - } - - // Nothing to do, sleep. - - lock (m_WakeUpLock) - { - if (!m_WakeUpThis && (m_WakeUpOne <= 0) && !m_Exiting) - Monitor.Wait(m_WakeUpLock, Watchdog.DEFAULT_WATCHDOG_TIMEOUT_MS / 2); - - m_WakeUpThis = false; - if ((m_WakeUpOne > 0) && (-- m_WakeUpOne > 0)) - Monitor.Pulse (m_WakeUpLock); - } - } - XMREngine.MyThreadExiting (); } /** * @brief A script instance was just removed from the Start or Yield Queue. * So run it for a little bit then stick in whatever queue it should go in. */ - private void RunInstance (XMRInstance inst) + + private void RunScriptThread() + { + engine.RunScriptThread(this); + } + + public void RunInstance (XMRInstance inst) { m_LastRanAt = DateTime.UtcNow; m_ScriptExecTime -= (long)(m_LastRanAt - DateTime.MinValue).TotalMilliseconds; diff --git a/OpenSim/Region/ScriptEngine/XMREngine/XMRScriptUThread.cs b/OpenSim/Region/ScriptEngine/XMREngine/XMRScriptUThread.cs index 74bba4f258..ca2806ecf5 100644 --- a/OpenSim/Region/ScriptEngine/XMREngine/XMRScriptUThread.cs +++ b/OpenSim/Region/ScriptEngine/XMREngine/XMRScriptUThread.cs @@ -57,21 +57,28 @@ namespace OpenSim.Region.ScriptEngine.XMREngine public Exception StartEx () { // We should only be called when no event handler running. - if (active != 0) throw new Exception ("active=" + active); + if (active != 0) + throw new Exception ("active=" + active); // Start script event handler from very beginning. active = 1; Exception except = null; instance.callMode = XMRInstance.CallMode_NORMAL; - try { + try + { instance.CallSEH (); // run script event handler active = 0; - } catch (StackHibernateException) { - if (instance.callMode != XMRInstance.CallMode_SAVE) { + } + catch (StackHibernateException) + { + if (instance.callMode != XMRInstance.CallMode_SAVE) + { throw new Exception ("callMode=" + instance.callMode); } active = -1; // it is hibernating, can be resumed - } catch (Exception e) { + } + catch (Exception e) + { active = 0; except = e; // threw exception, save for Start()/Resume() } @@ -88,21 +95,28 @@ namespace OpenSim.Region.ScriptEngine.XMREngine public Exception ResumeEx () { // We should only be called when script is hibernating. - if (active >= 0) throw new Exception ("active=" + active); + if (active >= 0) + throw new Exception ("active=" + active); // Resume script from captured stack. instance.callMode = XMRInstance.CallMode_RESTORE; instance.suspendOnCheckRunTemp = true; Exception except = null; - try { + try + { instance.CallSEH (); // run script event handler active = 0; - } catch (StackHibernateException) { - if (instance.callMode != XMRInstance.CallMode_SAVE) { + } + catch (StackHibernateException) + { + if (instance.callMode != XMRInstance.CallMode_SAVE) + { throw new Exception ("callMode=" + instance.callMode); } active = -1; - } catch (Exception e) { + } + catch (Exception e) + { active = 0; except = e; // threw exception, save for Start()/Resume() }