From 83e2fee71be695b78438e0c9dc50b649a539d0e3 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Fri, 2 Feb 2018 12:49:40 +0000 Subject: add experimental script engine XMRengine donated by mrieker (DreamNation) And our Melanie. ***DANGER*** ***TESTONLY*** ***disable HG*** dont leave running when not looking... tp/crossing to Xengine will reset scripts. i do see a few issues but should be testable, so we can decide if we should invest more on it. --- .../ScriptEngine/XMREngine/XMRScriptThread.cs | 262 +++++++++++++++++++++ 1 file changed, 262 insertions(+) create mode 100644 OpenSim/Region/ScriptEngine/XMREngine/XMRScriptThread.cs (limited to 'OpenSim/Region/ScriptEngine/XMREngine/XMRScriptThread.cs') diff --git a/OpenSim/Region/ScriptEngine/XMREngine/XMRScriptThread.cs b/OpenSim/Region/ScriptEngine/XMREngine/XMRScriptThread.cs new file mode 100644 index 0000000..933b478 --- /dev/null +++ b/OpenSim/Region/ScriptEngine/XMREngine/XMRScriptThread.cs @@ -0,0 +1,262 @@ +/* + * 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 Mono.Tasklets; +using OpenSim.Framework.Monitoring; +using System; +using System.Collections.Generic; +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 + * a script to run and calls the script as a microthread. + */ + 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; + private bool m_Continuations = false; + public DateTime m_LastRanAt = DateTime.MinValue; + public int m_ScriptThreadTID = 0; + public long m_ScriptExecTime = 0; + private Thread thd; + private XMREngine engine; + public XMRInstance m_RunInstance = null; + + public XMRScriptThread(XMREngine eng) + { + engine = eng; + m_Continuations = engine.uThreadCtor.DeclaringType == typeof (ScriptUThread_Con); + thd = XMREngine.StartMyThread (RunScriptThread, "xmrengine script", ThreadPriority.BelowNormal); + lock (m_AllThreads) { + m_AllThreads.Add (thd, this); + } + } + + public void SuspendThread() + { + m_SuspendScriptThreadFlag = true; + WakeUpScriptThread(); + } + + public void ResumeThread() + { + m_SuspendScriptThreadFlag = false; + WakeUpScriptThread(); + } + + public void Terminate() + { + m_Exiting = true; + WakeUpScriptThread(); + thd.Join(); + lock (m_AllThreads) { + m_AllThreads.Remove (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() + { + lock (m_WakeUpLock) { + m_WakeUpThis = true; + Monitor.PulseAll (m_WakeUpLock); + } + } + + /** + * @brief Thread that runs the scripts. + */ + private void RunScriptThread() + { + XMRInstance inst; + Mono.Tasklets.Continuation engstack = null; + if (m_Continuations) { + engstack = new Mono.Tasklets.Continuation (); + engstack.Mark (); + } + 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; + if (m_Continuations && (inst.scrstack == null)) { + inst.engstack = engstack; + inst.scrstack = new Mono.Tasklets.Continuation (); + inst.scrstack.Mark (); + } + 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"); + if (m_Continuations && (inst.scrstack == null)) { + inst.engstack = engstack; + inst.scrstack = new Mono.Tasklets.Continuation (); + inst.scrstack.Mark (); + } + 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) + { + m_LastRanAt = DateTime.UtcNow; + m_ScriptExecTime -= (long)(m_LastRanAt - DateTime.MinValue).TotalMilliseconds; + inst.m_IState = XMRInstState.RUNNING; + m_RunInstance = inst; + XMRInstState newIState = inst.RunOne(); + m_RunInstance = null; + engine.HandleNewIState(inst, newIState); + m_ScriptExecTime += (long)(DateTime.UtcNow - DateTime.MinValue).TotalMilliseconds; + } + } +} -- cgit v1.1