/* * 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.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; using LSL_Integer = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLInteger; using LSL_Key = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString; using LSL_List = OpenSim.Region.ScriptEngine.Shared.LSL_Types.list; using LSL_Rotation = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion; using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString; using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3; // This class exists in the main app domain // namespace OpenSim.Region.ScriptEngine.XMREngine { /** * @brief Which queue it is in as far as running is concerned, * ie, m_StartQueue, m_YieldQueue, m_SleepQueue, etc. * Allowed transitions: * Starts in CONSTRUCT when constructed * CONSTRUCT->ONSTARTQ : only by thread that constructed and compiled it * IDLE->ONSTARTQ,RESETTING : by any thread but must have m_QueueLock when transitioning * ONSTARTQ->RUNNING,RESETTING : only by thread that removed it from m_StartQueue * ONYIELDQ->RUNNING,RESETTING : only by thread that removed it from m_YieldQueue * ONSLEEPQ->REMDFROMSLPQ : by any thread but must have m_SleepQueue when transitioning * REMDFROMSLPQ->ONYIELDQ,RESETTING : only by thread that removed it from m_SleepQueue * RUNNING->whatever1 : only by thread that transitioned it to RUNNING * whatever1 = IDLE,ONSLEEPQ,ONYIELDQ,ONSTARTQ,SUSPENDED,FINISHED * FINSHED->whatever2 : only by thread that transitioned it to FINISHED * whatever2 = IDLE,ONSTARTQ,DISPOSED * SUSPENDED->ONSTARTQ : by any thread (NOT YET IMPLEMENTED, should be under some kind of lock?) * RESETTING->ONSTARTQ : only by the thread that transitioned it to RESETTING */ public enum XMRInstState { CONSTRUCT, // it is being constructed IDLE, // nothing happening (finished last event and m_EventQueue is empty) ONSTARTQ, // inserted on m_Engine.m_StartQueue RUNNING, // currently being executed by RunOne() ONSLEEPQ, // inserted on m_Engine.m_SleepQueue REMDFROMSLPQ, // removed from m_SleepQueue but not yet on m_YieldQueue ONYIELDQ, // inserted on m_Engine.m_YieldQueue FINISHED, // just finished handling an event SUSPENDED, // m_SuspendCount > 0 RESETTING, // being reset via external call DISPOSED // has been disposed } public partial class XMRInstance : XMRInstAbstract, IDisposable { /******************************************************************\ * This module contains the instance variables for XMRInstance. * \******************************************************************/ public const int MAXEVENTQUEUE = 64; public static readonly DetectParams[] zeroDetectParams = new DetectParams[0]; public static readonly object[] zeroObjectArray = new object[0]; public static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); // For a given m_Item.AssetID, do we have the compiled object code and where // is it? public static object m_CompileLock = new object(); private static Dictionary m_CompiledScriptObjCode = new Dictionary(); public XMRInstance m_NextInst; // used by XMRInstQueue public XMRInstance m_PrevInst; public XMRInstState m_IState; public bool m_ForceRecomp = false; public SceneObjectPart m_Part = null; public uint m_LocalID = 0; public TaskInventoryItem m_Item = null; public UUID m_ItemID; public UUID m_PartUUID; private string m_CameFrom; private string m_ScriptObjCodeKey; private XMREngine m_Engine = null; private string m_ScriptBasePath; private string m_StateFileName; public string m_SourceCode; public bool m_PostOnRez; private DetectParams[] m_DetectParams = null; public int m_StartParam = 0; public StateSource m_StateSource; public string m_DescName; private bool[] m_HaveEventHandlers; public int m_StackSize; public int m_HeapSize; private ArrayList m_CompilerErrors; private DateTime m_LastRanAt = DateTime.MinValue; private string m_RunOnePhase = "hasn't run"; private string m_CheckRunPhase = "hasn't checked"; public int m_InstEHEvent = 0; // number of events dequeued (StartEventHandler called) public int m_InstEHSlice = 0; // number of times handler timesliced (ResumeEx called) public double m_CPUTime = 0; // accumulated CPU time (milliseconds) public double m_SliceStart = 0; // when did current exec start // If code needs to have both m_QueueLock and m_RunLock, // be sure to lock m_RunLock first then m_QueueLock, as // that is the order used in RunOne(). // These locks are currently separated to allow the script // to call API routines that queue events back to the script. // If we just had one lock, then the queuing would deadlock. // guards m_DetachQuantum, m_EventQueue, m_EventCounts, m_Running, m_Suspended public Object m_QueueLock = new Object(); // true iff allowed to accept new events public bool m_Running = true; // queue of events that haven't been acted upon yet public LinkedList m_EventQueue = new LinkedList (); // number of events of each code currently in m_EventQueue. private int[] m_EventCounts = new int[(int)ScriptEventCode.Size]; // locked whilst running on the microthread stack (or about to run on it or just ran on it) private Object m_RunLock = new Object(); // script won't step while > 0. bus-atomic updates only. private int m_SuspendCount = 0; // don't run any of script until this time // or until one of these events are queued public DateTime m_SleepUntil = DateTime.MinValue; public int m_SleepEventMask1 = 0; public int m_SleepEventMask2 = 0; private XMRLSL_Api m_XMRLSLApi; /* * We will use this microthread to run the scripts event handlers. */ private IScriptUThread microthread; /* * Set to perform migration. */ public bool stackFramesRestored; // set true by CheckRun() when stack has been // restored and is about to suspend the microthread public bool captureStackFrames; // set true to tell CheckRun() to throw a // StackCaptureException() causing it to capture a // snapshot of the script's stack /* * Makes sure migration data version is same on both ends. */ public static byte migrationVersion = 10; // Incremented each time script gets reset. public int m_ResetCount = 0; // Scripts start suspended now. This means that event queues will // accept events, but will not actually run them until the core // tells it it's OK. This is needed to prevent loss of link messages // in complex objects, where no event can be allowed to run until // all possible link message receivers' queues are established. // Guarded by m_QueueLock. public bool m_Suspended = true; // We really don't want to save state for a script that hasn't had // a chance to run, because it's state will be blank. That would // cause attachment state loss. public bool m_HasRun = false; // When llDie is executed within the attach(NULL_KEY) event of // a script being detached to inventory, the DeleteSceneObject call // it causes will delete the script instances before their state can // be saved. Therefore, the instance needs to know that it's being // detached to inventory, rather than to ground. // Also, the attach(NULL_KEY) event needs to run with priority, and // it also needs to have a limited quantum. // If this is nonzero, we're detaching to inventory. // Guarded by m_QueueLock. private int m_DetachQuantum = 0; // Finally, we need to wait until the quantum is done, or the script // suspends itself. This should be efficient, so we use an event // for it instead of spinning busy. // It's born ready, but will be reset when the detach is posted. // It will then be set again on suspend/completion private ManualResetEvent m_DetachReady = new ManualResetEvent(true); } }