예제 #1
0
        /*
         * Start event handler.
         *
         * Input:
         *  eventCode = code of event to be processed
         *  ehArgs    = arguments for the event handler
         *
         * Caution:
         *  It is up to the caller to make sure ehArgs[] is correct for
         *  the particular event handler being called.  The first thing
         *  a script event handler method does is to unmarshall the args
         *  from ehArgs[] and will throw an array bounds or cast exception
         *  if it can't.
         */
        private Exception StartEventHandler(ScriptEventCode eventCode, object[] ehArgs)
        {
            // We use this.eventCode == ScriptEventCode.None to indicate we are idle.
            // So trying to execute ScriptEventCode.None might make a mess.
            if (eventCode == ScriptEventCode.None)
            {
                return(new Exception("Can't process ScriptEventCode.None"));
            }

            // Silly to even try if there is no handler defined for this event.
            if (((int)eventCode >= 0) && (m_ObjCode.scriptEventHandlerTable[this.stateCode, (int)eventCode] == null))
            {
                return(null);
            }

            // The microthread shouldn't be processing any event code.
            // These are assert checks so we throw them directly as exceptions.
            if (this.eventCode != ScriptEventCode.None)
            {
                throw new Exception("still processing event " + this.eventCode.ToString());
            }

            // Save eventCode so we know what event handler to run in the microthread.
            // And it also marks us busy so we can't be started again and this event lost.
            this.eventCode = eventCode;
            this.ehArgs    = ehArgs;

            // This calls ScriptUThread.Main() directly, and returns when Main() [indirectly]
            // calls Suspend() or when Main() returns, whichever occurs first.
            // Setting stackFrames = null means run the event handler from the beginning
            // without doing any stack frame restores first.
            this.stackFrames = null;
            return(StartEx());
        }
예제 #2
0
        public void CheckRunLockInvariants(bool throwIt)
        {
            /*
             * If not executing any event handler, there shouldn't be any saved stack frames.
             * If executing an event handler, there should be some saved stack frames.
             */
            bool            active = (stackFrames != null);
            ScriptEventCode ec     = this.eventCode;

            if (((ec == ScriptEventCode.None) && active) ||
                ((ec != ScriptEventCode.None) && !active))
            {
                m_log.Error("CheckRunLockInvariants: script=" + m_DescName);
                m_log.Error("CheckRunLockInvariants: eventcode=" + ec.ToString() + ", active=" + active.ToString());
                m_log.Error("CheckRunLockInvariants: m_RunOnePhase=" + m_RunOnePhase);
                m_log.Error("CheckRunLockInvariants: lastec=" + lastEventCode + ", lastAct=" + lastActive + ", lastPhase=" + lastRunPhase);
                if (throwIt)
                {
                    throw new Exception("CheckRunLockInvariants: eventcode=" + ec.ToString() + ", active=" + active.ToString());
                }
            }
            lastEventCode = ec;
            lastActive    = active;
            lastRunPhase  = m_RunOnePhase;
        }
예제 #3
0
        /**
         * @brief Enqueue an event
         * @param ev = as returned by xmrEventDequeue saying which event type to queue
         *             and what argument list to pass to it.  The llDetect...() parameters
         *             are as currently set for the script (use xmrEventLoadDets to set how
         *             you want them to be different).
         */
        public override void xmrEventEnqueue(LSL_List ev)
        {
            object[]        data = ev.Data;
            ScriptEventCode evc  = (ScriptEventCode)ListInt(data[0]);

            int nargs = data.Length - 1;

            object[] args = new object[nargs];
            Array.Copy(data, 1, args, 0, nargs);

            PostEvent(new EventParams(evc.ToString(), args, m_DetectParams));
        }
        /**
         * @brief There was an exception whilst starting/running a script event handler.
         *        Maybe we handle it directly or just print an error message.
         */
        private void HandleScriptException(Exception e)
        {
            // The script threw some kind of exception that was not caught at
            // script level, so the script is no longer running an event handler.

            ScriptEventCode curevent = eventCode;

            eventCode   = ScriptEventCode.None;
            stackFrames = null;

            if (m_Part == null || m_Part.Inventory == null)
            {
                //we are gone and don't know it still
                m_SleepUntil = DateTime.MaxValue;
                return;
            }

            if (e is ScriptDeleteException)
            {
                // Script did something like llRemoveInventory(llGetScriptName());
                // ... to delete itself from the object.
                m_SleepUntil = DateTime.MaxValue;
                Verbose("[YEngine]: script self-delete {0}", m_ItemID);
                m_Part.Inventory.RemoveInventoryItem(m_ItemID);
            }
            else if (e is ScriptDieException)
            {
                // Script did an llDie()
                m_RunOnePhase = "dying...";
                m_SleepUntil  = DateTime.MaxValue;
                m_Engine.World.DeleteSceneObject(m_Part.ParentGroup, false);
            }
            else if (e is ScriptResetException)
            {
                // Script did an llResetScript().
                m_RunOnePhase = "resetting...";
                ResetLocked("HandleScriptResetException");
            }
            else if (e is ScriptException)
            {
                // Some general script error.
                SendScriptErrorMessage(e, curevent);
            }
            else
            {
                // Some general script error.
                SendErrorMessage(e);
            }
        }
예제 #5
0
        private void SendScriptErrorMessage(Exception e, ScriptEventCode ev)
        {
            StringBuilder msg = new StringBuilder();

            msg.Append("YEngine: ");
            if (e.Message != null)
            {
                msg.Append(e.Message);
            }

            msg.Append(" (script: ");
            msg.Append(m_Item.Name);
            msg.Append(" event: ");
            msg.Append(ev.ToString());
            msg.Append(" primID: ");
            msg.Append(m_Part.UUID.ToString());
            msg.Append(" at: <");
            Vector3 pos = m_Part.AbsolutePosition;

            msg.Append((int)Math.Floor(pos.X));
            msg.Append(',');
            msg.Append((int)Math.Floor(pos.Y));
            msg.Append(',');
            msg.Append((int)Math.Floor(pos.Z));
            msg.Append(">) Script must be Reset to re-enable.\n");

            string msgst = msg.ToString();

            if (msgst.Length > 1000)
            {
                msgst = msgst.Substring(0, 1000);
            }

            m_Engine.World.SimChat(Utils.StringToBytes(msgst),
                                   ChatTypeEnum.DebugChannel, 2147483647,
                                   m_Part.AbsolutePosition,
                                   m_Part.Name, m_Part.UUID, false);
            m_log.Debug(string.Format(
                            "[SCRIPT ERROR]: {0} (at event {1}, part {2} {3} at {4} in {5}",
                            (e.Message == null)? "" : e.Message,
                            ev.ToString(),
                            m_Part.Name,
                            m_Part.UUID,
                            m_Part.AbsolutePosition,
                            m_Part.ParentGroup.Scene.Name));

            m_SleepUntil = DateTime.MaxValue;
        }
예제 #6
0
        private void processXstate(XmlDocument doc)
        {
            XmlNodeList rootL = doc.GetElementsByTagName("ScriptState");

            if (rootL.Count != 1)
            {
                throw new Exception("Xstate <ScriptState> missing");
            }

            XmlNode rootNode = rootL[0];

            if (rootNode == null)
            {
                throw new Exception("Xstate root missing");
            }

            string stateName = "";
            bool   running   = false;

            UUID   permsGranter  = UUID.Zero;
            int    permsMask     = 0;
            double minEventDelay = 0.0;

            Object[] pluginData = new Object[0];

            LinkedList <EventParams> eventQueue = new LinkedList <EventParams>();

            Dictionary <string, int> intNames      = new Dictionary <string, int>();
            Dictionary <string, int> doubleNames   = new Dictionary <string, int>();
            Dictionary <string, int> stringNames   = new Dictionary <string, int>();
            Dictionary <string, int> vectorNames   = new Dictionary <string, int>();
            Dictionary <string, int> rotationNames = new Dictionary <string, int>();
            Dictionary <string, int> listNames     = new Dictionary <string, int>();

            int nn = m_ObjCode.globalVarNames.Count;

            int[]          ints      = null;
            double[]       doubles   = null;
            string[]       strings   = null;
            LSL_Vector[]   vectors   = null;
            LSL_Rotation[] rotations = null;
            LSL_List[]     lists     = null;

            if (nn > 0)
            {
                if (m_ObjCode.globalVarNames.ContainsKey("iarIntegers"))
                {
                    getvarNames(m_ObjCode.globalVarNames["iarIntegers"], intNames);
                    ints = new int[m_ObjCode.globalVarNames["iarIntegers"].Count];
                }
                if (m_ObjCode.globalVarNames.ContainsKey("iarFloats"))
                {
                    getvarNames(m_ObjCode.globalVarNames["iarFloats"], doubleNames);
                    doubles = new double[m_ObjCode.globalVarNames["iarFloats"].Count];
                }
                if (m_ObjCode.globalVarNames.ContainsKey("iarVectors"))
                {
                    getvarNames(m_ObjCode.globalVarNames["iarVectors"], vectorNames);
                    vectors = new LSL_Vector[m_ObjCode.globalVarNames["iarVectors"].Count];
                }
                if (m_ObjCode.globalVarNames.ContainsKey("iarRotations"))
                {
                    getvarNames(m_ObjCode.globalVarNames["iarRotations"], rotationNames);
                    rotations = new LSL_Rotation[m_ObjCode.globalVarNames["iarRotations"].Count];
                }
                if (m_ObjCode.globalVarNames.ContainsKey("iarStrings"))
                {
                    getvarNames(m_ObjCode.globalVarNames["iarStrings"], stringNames);
                    strings = new string[m_ObjCode.globalVarNames["iarStrings"].Count];
                }
                if (m_ObjCode.globalVarNames.ContainsKey("iarLists"))
                {
                    getvarNames(m_ObjCode.globalVarNames["iarLists"], listNames);
                    lists = new LSL_List[m_ObjCode.globalVarNames["iarLists"].Count];
                }
            }

            int heapsz = 0;

            try
            {
                XmlNodeList partL = rootNode.ChildNodes;
                foreach (XmlNode part in partL)
                {
                    switch (part.Name)
                    {
                    case "State":
                        stateName = part.InnerText;
                        break;

                    case "Running":
                        running = bool.Parse(part.InnerText);
                        break;

                    case "Variables":
                        int         indx;
                        XmlNodeList varL = part.ChildNodes;
                        foreach (XmlNode var in varL)
                        {
                            string varName;
                            object o     = ReadXTypedValue(var, out varName);
                            Type   otype = o.GetType();
                            if (otype == typeof(LSL_Integer))
                            {
                                if (intNames.TryGetValue(varName, out indx))
                                {
                                    ints[indx] = ((LSL_Integer)o);
                                }
                                continue;
                            }
                            if (otype == typeof(LSL_Float))
                            {
                                if (doubleNames.TryGetValue(varName, out indx))
                                {
                                    doubles[indx] = ((LSL_Float)o);
                                }
                                continue;
                            }
                            if (otype == typeof(LSL_String))
                            {
                                if (stringNames.TryGetValue(varName, out indx))
                                {
                                    strings[indx] = ((LSL_String)o);
                                    heapsz       += ((LSL_String)o).Length;
                                }
                                continue;
                            }
                            if (otype == typeof(LSL_Rotation))
                            {
                                if (rotationNames.TryGetValue(varName, out indx))
                                {
                                    rotations[indx] = ((LSL_Rotation)o);
                                }
                                continue;
                            }
                            if (otype == typeof(LSL_Vector))
                            {
                                if (vectorNames.TryGetValue(varName, out indx))
                                {
                                    vectors[indx] = ((LSL_Vector)o);
                                }
                                continue;
                            }
                            if (otype == typeof(LSL_Key))
                            {
                                if (stringNames.TryGetValue(varName, out indx))
                                {
                                    strings[indx] = ((LSL_Key)o);
                                    heapsz       += ((LSL_String)o).Length;
                                }
                                continue;
                            }
                            if (otype == typeof(UUID))
                            {
                                if (stringNames.TryGetValue(varName, out indx))
                                {
                                    LSL_String id = ((UUID)o).ToString();
                                    strings[indx] = (id);
                                    heapsz       += id.Length;
                                }
                                continue;
                            }
                            if (otype == typeof(LSL_List))
                            {
                                if (listNames.TryGetValue(varName, out indx))
                                {
                                    LSL_List lo = (LSL_List)o;
                                    lists[indx] = (lo);
                                    heapsz     += lo.Size;
                                }
                                continue;
                            }
                        }
                        break;

                    case "Queue":
                        XmlNodeList itemL = part.ChildNodes;
                        foreach (XmlNode item in itemL)
                        {
                            List <Object>       parms    = new List <Object>();
                            List <DetectParams> detected = new List <DetectParams>();

                            string      eventName = item.Attributes.GetNamedItem("event").Value;
                            XmlNodeList eventL    = item.ChildNodes;
                            foreach (XmlNode evt in eventL)
                            {
                                switch (evt.Name)
                                {
                                case "Params":
                                    XmlNodeList prms = evt.ChildNodes;
                                    foreach (XmlNode pm in prms)
                                    {
                                        parms.Add(ReadXTypedValue(pm));
                                    }

                                    break;

                                case "Detected":
                                    XmlNodeList detL = evt.ChildNodes;
                                    foreach (XmlNode det in detL)
                                    {
                                        string     vect = det.Attributes.GetNamedItem("pos").Value;
                                        LSL_Vector v    = new LSL_Vector(vect);

                                        int          d_linkNum  = 0;
                                        UUID         d_group    = UUID.Zero;
                                        string       d_name     = String.Empty;
                                        UUID         d_owner    = UUID.Zero;
                                        LSL_Vector   d_position = new LSL_Vector();
                                        LSL_Rotation d_rotation = new LSL_Rotation();
                                        int          d_type     = 0;
                                        LSL_Vector   d_velocity = new LSL_Vector();

                                        try
                                        {
                                            string tmp;

                                            tmp = det.Attributes.GetNamedItem("linkNum").Value;
                                            int.TryParse(tmp, out d_linkNum);

                                            tmp = det.Attributes.GetNamedItem("group").Value;
                                            UUID.TryParse(tmp, out d_group);

                                            d_name = det.Attributes.GetNamedItem("name").Value;

                                            tmp = det.Attributes.GetNamedItem("owner").Value;
                                            UUID.TryParse(tmp, out d_owner);

                                            tmp        = det.Attributes.GetNamedItem("position").Value;
                                            d_position = new LSL_Types.Vector3(tmp);

                                            tmp        = det.Attributes.GetNamedItem("rotation").Value;
                                            d_rotation = new LSL_Rotation(tmp);

                                            tmp = det.Attributes.GetNamedItem("type").Value;
                                            int.TryParse(tmp, out d_type);

                                            tmp        = det.Attributes.GetNamedItem("velocity").Value;
                                            d_velocity = new LSL_Vector(tmp);
                                        }
                                        catch (Exception)         // Old version XML
                                        {
                                        }

                                        UUID uuid = new UUID();
                                        UUID.TryParse(det.InnerText, out uuid);

                                        DetectParams d = new DetectParams();
                                        d.Key       = uuid;
                                        d.OffsetPos = v;
                                        d.LinkNum   = d_linkNum;
                                        d.Group     = d_group;
                                        d.Name      = d_name;
                                        d.Owner     = d_owner;
                                        d.Position  = d_position;
                                        d.Rotation  = d_rotation;
                                        d.Type      = d_type;
                                        d.Velocity  = d_velocity;

                                        detected.Add(d);
                                    }
                                    break;
                                }
                            }
                            EventParams ep = new EventParams(
                                eventName, parms.ToArray(),
                                detected.ToArray());
                            eventQueue.AddLast(ep);
                        }
                        break;

                    case "Plugins":
                        List <Object> olist  = new List <Object>();
                        XmlNodeList   itemLP = part.ChildNodes;
                        foreach (XmlNode item in itemLP)
                        {
                            olist.Add(ReadXTypedValue(item));
                        }
                        pluginData = olist.ToArray();
                        break;

                    case "Permissions":
                        string tmpPerm;
                        int    mask = 0;
                        tmpPerm = part.Attributes.GetNamedItem("mask").Value;
                        if (tmpPerm != null)
                        {
                            int.TryParse(tmpPerm, out mask);
                            if (mask != 0)
                            {
                                tmpPerm = part.Attributes.GetNamedItem("granter").Value;
                                if (tmpPerm != null)
                                {
                                    UUID granter = new UUID();
                                    UUID.TryParse(tmpPerm, out granter);
                                    if (granter != UUID.Zero)
                                    {
                                        permsMask    = mask;
                                        permsGranter = granter;
                                    }
                                }
                            }
                        }
                        break;

                    case "MinEventDelay":
                        double.TryParse(part.InnerText, out minEventDelay);
                        break;
                    }
                }
            }
            catch
            {
                throw new Exception("Xstate fail decode");
            }

            int k = 0;

            stateCode = 0;
            foreach (string sn in m_ObjCode.stateNames)
            {
                if (stateName == sn)
                {
                    stateCode = k;
                    break;
                }
                k++;
            }
            eventCode = ScriptEventCode.None;
            m_Running = running;
            doGblInit = false;

            m_Item.PermsGranter = permsGranter;
            m_Item.PermsMask    = permsMask;
            m_Part.Inventory.UpdateInventoryItem(m_Item, false, false);

            lock (m_RunLock)
            {
                glblVars.iarIntegers  = ints;
                glblVars.iarFloats    = doubles;
                glblVars.iarVectors   = vectors;
                glblVars.iarRotations = rotations;
                glblVars.iarStrings   = strings;
                glblVars.iarLists     = lists;

                AddHeapUse(heapsz);
                CheckRunLockInvariants(true);
            }

            lock (m_QueueLock)
            {
                m_DetectParams = null;
                foreach (EventParams evt in m_EventQueue)
                {
                    eventQueue.AddLast(evt);
                }

                m_EventQueue = eventQueue;
                for (int i = m_EventCounts.Length; --i >= 0;)
                {
                    m_EventCounts[i] = 0;
                }
                foreach (EventParams evt in m_EventQueue)
                {
                    ScriptEventCode eventCode = (ScriptEventCode)Enum.Parse(typeof(ScriptEventCode),
                                                                            evt.EventName);
                    m_EventCounts[(int)eventCode]++;
                }
            }

            AsyncCommandManager.CreateFromData(m_Engine,
                                               m_LocalID, m_ItemID, m_Part.UUID, pluginData);
        }
예제 #7
0
        /**
         * @brief Load script state from the given XML doc into the script memory
         *  <ScriptState Engine="YEngine" Asset=...>
         *      <Running>...</Running>
         *      <DoGblInit>...</DoGblInit>
         *      <Permissions granted=... mask=... />
         *      RestoreDetectParams()
         *      <Plugins>
         *          ExtractXMLObjectArray("plugin")
         *      </Plugins>
         *      <Snapshot>
         *          MigrateInEventHandler()
         *      </Snapshot>
         *  </ScriptState>
         */
        private void LoadScriptState(XmlDocument doc)
        {
            // Everything we know is enclosed in <ScriptState>...</ScriptState>
            XmlElement scriptStateN = (XmlElement)doc.SelectSingleNode("ScriptState");

            if (scriptStateN == null)
            {
                throw new Exception("no <ScriptState> tag");
            }

            XmlElement XvariablesN = null;
            string     sen         = scriptStateN.GetAttribute("Engine");

            if ((sen == null) || (sen != m_Engine.ScriptEngineName))
            {
                XvariablesN = (XmlElement)scriptStateN.SelectSingleNode("Variables");
                if (XvariablesN == null)
                {
                    throw new Exception("<ScriptState> missing Engine=\"YEngine\" attribute");
                }
                processXstate(doc);
                return;
            }

            // AssetID is unique for the script source text so make sure the
            // state file was written for that source file
            string assetID = scriptStateN.GetAttribute("Asset");

            if (assetID != m_Item.AssetID.ToString())
            {
                throw new Exception("<ScriptState> assetID mismatch");
            }

            // Also match the sourceHash in case script was
            // loaded via 'xmroption fetchsource' and has changed
            string sourceHash = scriptStateN.GetAttribute("SourceHash");

            if ((sourceHash == null) || (sourceHash != m_ObjCode.sourceHash))
            {
                throw new Exception("<ScriptState> SourceHash mismatch");
            }

            // Get various attributes
            XmlElement runningN = (XmlElement)scriptStateN.SelectSingleNode("Running");

            m_Running = bool.Parse(runningN.InnerText);

            XmlElement doGblInitN = (XmlElement)scriptStateN.SelectSingleNode("DoGblInit");

            doGblInit = bool.Parse(doGblInitN.InnerText);

            XmlElement permissionsN = (XmlElement)scriptStateN.SelectSingleNode("Permissions");

            m_Item.PermsGranter = new UUID(permissionsN.GetAttribute("granter"));
            m_Item.PermsMask    = Convert.ToInt32(permissionsN.GetAttribute("mask"));
            m_Part.Inventory.UpdateInventoryItem(m_Item, false, false);

            // get values used by stuff like llDetectedGrab, etc.
            DetectParams[] detParams = RestoreDetectParams(scriptStateN.SelectSingleNode("DetectArray"));

            // Restore queued events
            LinkedList <EventParams> eventQueue = RestoreEventQueue(scriptStateN.SelectSingleNode("EventQueue"));

            // Restore timers and listeners
            XmlElement pluginN = (XmlElement)scriptStateN.SelectSingleNode("Plugins");

            Object[] pluginData = ExtractXMLObjectArray(pluginN, "plugin");

            // Script's global variables and stack contents
            XmlElement snapshotN = (XmlElement)scriptStateN.SelectSingleNode("Snapshot");

            Byte[]       data = Convert.FromBase64String(snapshotN.InnerText);
            MemoryStream ms   = new MemoryStream();

            ms.Write(data, 0, data.Length);
            ms.Seek(0, SeekOrigin.Begin);
            MigrateInEventHandler(ms);
            ms.Close();

            // Restore event queues, preserving any events that queued
            // whilst we were restoring the state
            lock (m_QueueLock)
            {
                m_DetectParams = detParams;
                foreach (EventParams evt in m_EventQueue)
                {
                    eventQueue.AddLast(evt);
                }

                m_EventQueue = eventQueue;
                for (int i = m_EventCounts.Length; --i >= 0;)
                {
                    m_EventCounts[i] = 0;
                }
                foreach (EventParams evt in m_EventQueue)
                {
                    ScriptEventCode eventCode = (ScriptEventCode)Enum.Parse(typeof(ScriptEventCode),
                                                                            evt.EventName);
                    m_EventCounts[(int)eventCode]++;
                }
            }

            // Requeue timer and listeners (possibly queuing new events)
            AsyncCommandManager.CreateFromData(m_Engine,
                                               m_LocalID, m_ItemID, m_Part.UUID,
                                               pluginData);
        }
예제 #8
0
        /************************************************************************************\
        * This module contains these externally useful methods:                            *
        *   PostEvent() - queues an event to script and wakes script thread to process it  *
        *   RunOne() - runs script for a time slice or until it volunteers to give up cpu  *
        *   CallSEH() - runs in the microthread to call the event handler                  *
        \************************************************************************************/

        /**
         * @brief This can be called in any thread (including the script thread itself)
         *        to queue event to script for processing.
         */
        public void PostEvent(EventParams evt)
        {
            ScriptEventCode evc = (ScriptEventCode)Enum.Parse(typeof(ScriptEventCode),
                                                              evt.EventName);

            // Put event on end of event queue.
            bool startIt = false;
            bool wakeIt  = false;

            lock (m_QueueLock)
            {
                bool construct = (m_IState == XMRInstState.CONSTRUCT);

                // Ignore event if we don't even have such an handler in any state.
                // We can't be state-specific here because state might be different
                // by the time this event is dequeued and delivered to the script.
                if (!construct &&                      // make sure m_HaveEventHandlers is filled in
                    ((uint)evc < (uint)m_HaveEventHandlers.Length) &&
                    !m_HaveEventHandlers[(int)evc])    // don't bother if we don't have such a handler in any state
                {
                    return;
                }

                // Not running means we ignore any incoming events.
                // But queue if still constructing because m_Running is not yet valid.
                if (!m_Running && !construct)
                {
                    return;
                }

                // Only so many of each event type allowed to queue.
                if ((uint)evc < (uint)m_EventCounts.Length)
                {
                    if (evc == ScriptEventCode.timer)
                    {
                        if (m_EventCounts[(int)evc] >= 1)
                        {
                            return;
                        }
                    }
                    else if (m_EventCounts[(int)evc] >= MAXEVENTQUEUE)
                    {
                        return;
                    }

                    m_EventCounts[(int)evc]++;
                }

                // Put event on end of instance's event queue.
                LinkedListNode <EventParams> lln = new LinkedListNode <EventParams>(evt);
                switch (evc)
                {
                // These need to go first.  The only time we manually
                // queue them is for the default state_entry() and we
                // need to make sure they go before any attach() events
                // so the heapLimit value gets properly initialized.
                case ScriptEventCode.state_entry:
                    m_EventQueue.AddFirst(lln);
                    break;

                // The attach event sneaks to the front of the queue.
                // This is needed for quantum limiting to work because
                // we want the attach(NULL_KEY) event to come in front
                // of all others so the m_DetachQuantum won't run out
                // before attach(NULL_KEY) is executed.
                case ScriptEventCode.attach:
                    if (evt.Params[0].ToString() == UUID.Zero.ToString())
                    {
                        LinkedListNode <EventParams> lln2 = null;
                        for (lln2 = m_EventQueue.First; lln2 != null; lln2 = lln2.Next)
                        {
                            EventParams     evt2 = lln2.Value;
                            ScriptEventCode evc2 = (ScriptEventCode)Enum.Parse(typeof(ScriptEventCode),
                                                                               evt2.EventName);
                            if ((evc2 != ScriptEventCode.state_entry) &&
                                (evc2 != ScriptEventCode.attach))
                            {
                                break;
                            }
                        }
                        if (lln2 == null)
                        {
                            m_EventQueue.AddLast(lln);
                        }
                        else
                        {
                            m_EventQueue.AddBefore(lln2, lln);
                        }

                        // If we're detaching, limit the qantum. This will also
                        // cause the script to self-suspend after running this
                        // event
                        m_DetachReady.Reset();
                        m_DetachQuantum = 100;
                    }
                    else
                    {
                        m_EventQueue.AddLast(lln);
                    }

                    break;

                // All others just go on end in the order queued.
                default:
                    m_EventQueue.AddLast(lln);
                    break;
                }

                // If instance is idle (ie, not running or waiting to run),
                // flag it to be on m_StartQueue as we are about to do so.
                // Flag it now before unlocking so another thread won't try
                // to do the same thing right now.
                // Dont' flag it if it's still suspended!
                if ((m_IState == XMRInstState.IDLE) && !m_Suspended)
                {
                    m_IState = XMRInstState.ONSTARTQ;
                    startIt  = true;
                }

                // If instance is sleeping (ie, possibly in xmrEventDequeue),
                // wake it up if event is in the mask.
                if ((m_SleepUntil > DateTime.UtcNow) && !m_Suspended)
                {
                    int evc1 = (int)evc;
                    int evc2 = evc1 - 32;
                    if ((((uint)evc1 < (uint)32) && (((m_SleepEventMask1 >> evc1) & 1) != 0)) ||
                        (((uint)evc2 < (uint)32) && (((m_SleepEventMask2 >> evc2) & 1) != 0)))
                    {
                        wakeIt = true;
                    }
                }
            }

            // If transitioned from IDLE->ONSTARTQ, actually go insert it
            // on m_StartQueue and give the RunScriptThread() a wake-up.
            if (startIt)
            {
                m_Engine.QueueToStart(this);
            }

            // Likewise, if the event mask triggered a wake, wake it up.
            if (wakeIt)
            {
                m_SleepUntil = DateTime.MinValue;
                m_Engine.WakeFromSleep(this);
            }
        }
예제 #9
0
        // This is called in the script thread to step script until it calls
        // CheckRun().  It returns what the instance's next state should be,
        // ONSLEEPQ, ONYIELDQ, SUSPENDED or FINISHED.
        public XMRInstState RunOne()
        {
            DateTime now = DateTime.UtcNow;

            m_SliceStart = Util.GetTimeStampMS();

            // If script has called llSleep(), don't do any more until time is up.
            m_RunOnePhase = "check m_SleepUntil";
            if (m_SleepUntil > now)
            {
                m_RunOnePhase = "return is sleeping";
                return(XMRInstState.ONSLEEPQ);
            }

            // Also, someone may have called Suspend().
            m_RunOnePhase = "check m_SuspendCount";
            if (m_SuspendCount > 0)
            {
                m_RunOnePhase = "return is suspended";
                return(XMRInstState.SUSPENDED);
            }

            // Make sure we aren't being migrated in or out and prevent that
            // whilst we are in here.  If migration has it locked, don't call
            // back right away, delay a bit so we don't get in infinite loop.
            m_RunOnePhase = "lock m_RunLock";
            if (!Monitor.TryEnter(m_RunLock))
            {
                m_SleepUntil  = now.AddMilliseconds(3);
                m_RunOnePhase = "return was locked";
                return(XMRInstState.ONSLEEPQ);
            }
            try
            {
                m_RunOnePhase = "check entry invariants";
                CheckRunLockInvariants(true);
                Exception e = null;

                // Maybe it has been Disposed()
                if (m_Part == null)
                {
                    m_RunOnePhase = "runone saw it disposed";
                    return(XMRInstState.DISPOSED);
                }

                // Do some more of the last event if it didn't finish.
                if (this.eventCode != ScriptEventCode.None)
                {
                    lock (m_QueueLock)
                    {
                        if (m_DetachQuantum > 0 && --m_DetachQuantum == 0)
                        {
                            m_Suspended = true;
                            m_DetachReady.Set();
                            m_RunOnePhase = "detach quantum went zero";
                            CheckRunLockInvariants(true);
                            return(XMRInstState.FINISHED);
                        }
                    }

                    m_RunOnePhase = "resume old event handler";
                    m_LastRanAt   = now;
                    m_InstEHSlice++;
                    callMode = CallMode_NORMAL;
                    e        = ResumeEx();
                }

                // Otherwise, maybe we can dequeue a new event and start
                // processing it.
                else
                {
                    m_RunOnePhase = "lock event queue";
                    EventParams     evt = null;
                    ScriptEventCode evc = ScriptEventCode.None;

                    lock (m_QueueLock)
                    {
                        // We can't get here unless the script has been resumed
                        // after creation, then suspended again, and then had
                        // an event posted to it. We just pretend there is no
                        // event int he queue and let the normal mechanics
                        // carry out the suspension. A Resume will handle the
                        // restarting gracefully. This is taking the easy way
                        // out and may be improved in the future.

                        if (m_Suspended)
                        {
                            m_RunOnePhase = "m_Suspended is set";
                            CheckRunLockInvariants(true);
                            return(XMRInstState.FINISHED);
                        }

                        m_RunOnePhase = "dequeue event";
                        if (m_EventQueue.First != null)
                        {
                            evt = m_EventQueue.First.Value;
                            if (m_DetachQuantum > 0)
                            {
                                evc = (ScriptEventCode)Enum.Parse(typeof(ScriptEventCode),
                                                                  evt.EventName);
                                if (evc != ScriptEventCode.attach)
                                {
                                    // This is the case where the attach event
                                    // has completed and another event is queued
                                    // Stop it from running and suspend
                                    m_Suspended = true;
                                    m_DetachReady.Set();
                                    m_DetachQuantum = 0;
                                    m_RunOnePhase   = "nothing to do #3";
                                    CheckRunLockInvariants(true);
                                    return(XMRInstState.FINISHED);
                                }
                            }
                            m_EventQueue.RemoveFirst();
                            evc = (ScriptEventCode)Enum.Parse(typeof(ScriptEventCode),
                                                              evt.EventName);
                            if ((int)evc >= 0)
                            {
                                m_EventCounts[(int)evc]--;
                            }
                        }

                        // If there is no event to dequeue, don't run this script
                        // until another event gets queued.
                        if (evt == null)
                        {
                            if (m_DetachQuantum > 0)
                            {
                                // This will happen if the attach event has run
                                // and exited with time slice left.
                                m_Suspended = true;
                                m_DetachReady.Set();
                                m_DetachQuantum = 0;
                            }
                            m_RunOnePhase = "nothing to do #4";
                            CheckRunLockInvariants(true);
                            return(XMRInstState.FINISHED);
                        }
                    }

                    // Dequeued an event, so start it going until it either
                    // finishes or it calls CheckRun().
                    m_RunOnePhase  = "start event handler";
                    m_DetectParams = evt.DetectParams;
                    m_LastRanAt    = now;
                    m_InstEHEvent++;
                    e = StartEventHandler(evc, evt.Params);
                }
                m_RunOnePhase = "done running";
                m_CPUTime    += DateTime.UtcNow.Subtract(now).TotalMilliseconds;

                // Maybe it puqued.
                if (e != null)
                {
                    m_RunOnePhase = "handling exception " + e.Message;
                    HandleScriptException(e);
                    m_RunOnePhase = "return had exception " + e.Message;
                    CheckRunLockInvariants(true);
                    return(XMRInstState.FINISHED);
                }

                // If event handler completed, get rid of detect params.
                if (this.eventCode == ScriptEventCode.None)
                {
                    m_DetectParams = null;
                }
            }
            finally
            {
                m_RunOnePhase += "; checking exit invariants and unlocking";
                CheckRunLockInvariants(false);
                Monitor.Exit(m_RunLock);
            }

            // Cycle script through the yield queue and call it back asap.
            m_RunOnePhase = "last return";
            return(XMRInstState.ONYIELDQ);
        }
예제 #10
0
        public override LSL_List xmrEventDequeue(double timeout, int returnMask1, int returnMask2,
                                                 int backgroundMask1, int backgroundMask2)
        {
            DateTime    sleepUntil = DateTime.UtcNow + TimeSpan.FromMilliseconds(timeout * 1000.0);
            EventParams evt = null;
            int         callNo, evc2;
            int         evc1                 = 0;
            int         mask1                = returnMask1 | backgroundMask1; // codes 00..31
            int         mask2                = returnMask2 | backgroundMask2; // codes 32..63
            LinkedListNode <EventParams> lln = null;

            object[]        sv;
            ScriptEventCode evc = ScriptEventCode.None;

            callNo = -1;
            try
            {
                if (callMode == CallMode_NORMAL)
                {
                    goto findevent;
                }

                // Stack frame is being restored as saved via CheckRun...().
                // Restore necessary values then jump to __call<n> label to resume processing.
                sv          = RestoreStackFrame("xmrEventDequeue", out callNo);
                sleepUntil  = DateTime.Parse((string)sv[0]);
                returnMask1 = (int)sv[1];
                returnMask2 = (int)sv[2];
                mask1       = (int)sv[3];
                mask2       = (int)sv[4];
                switch (callNo)
                {
                case 0:
                    goto __call0;

                case 1:
                {
                    evc1 = (int)sv[5];
                    evc  = (ScriptEventCode)(int)sv[6];
                    DetectParams[] detprms = ObjArrToDetPrms((object[])sv[7]);
                    object[]       ehargs  = (object[])sv[8];
                    evt = new EventParams(evc.ToString(), ehargs, detprms);
                    goto __call1;
                }
                }
                throw new ScriptBadCallNoException(callNo);

                // Find first event that matches either the return or background masks.
findevent:
                Monitor.Enter(m_QueueLock);
                for (lln = m_EventQueue.First; lln != null; lln = lln.Next)
                {
                    evt  = lln.Value;
                    evc  = (ScriptEventCode)Enum.Parse(typeof(ScriptEventCode), evt.EventName);
                    evc1 = (int)evc;
                    evc2 = evc1 - 32;
                    if ((((uint)evc1 < (uint)32) && (((mask1 >> evc1) & 1) != 0)) ||
                        (((uint)evc2 < (uint)32) && (((mask2 >> evc2) & 1) != 0)))
                    {
                        goto remfromq;
                    }
                }

                // Nothing found, sleep while one comes in.
                m_SleepUntil      = sleepUntil;
                m_SleepEventMask1 = mask1;
                m_SleepEventMask2 = mask2;
                Monitor.Exit(m_QueueLock);
                suspendOnCheckRunTemp = true;
                callNo = 0;
__call0:
                CheckRunQuick();
                goto checktmo;

                // Found one, remove it from queue.
remfromq:
                m_EventQueue.Remove(lln);
                if ((uint)evc1 < (uint)m_EventCounts.Length)
                {
                    m_EventCounts[evc1]--;
                }

                Monitor.Exit(m_QueueLock);
                m_InstEHEvent++;

                // See if returnable or background event.
                if ((((uint)evc1 < (uint)32) && (((returnMask1 >> evc1) & 1) != 0)) ||
                    (((uint)evc2 < (uint)32) && (((returnMask2 >> evc2) & 1) != 0)))
                {
                    // Returnable event, return its parameters in a list.
                    // Also set the detect parameters to what the event has.
                    int      plen  = evt.Params.Length;
                    object[] plist = new object[plen + 1];
                    plist[0] = (LSL_Integer)evc1;
                    for (int i = 0; i < plen;)
                    {
                        object ob = evt.Params[i];
                        if (ob is int)
                        {
                            ob = (LSL_Integer)(int)ob;
                        }
                        else if (ob is double)
                        {
                            ob = (LSL_Float)(double)ob;
                        }
                        else if (ob is string)
                        {
                            ob = (LSL_String)(string)ob;
                        }
                        plist[++i] = ob;
                    }
                    m_DetectParams = evt.DetectParams;
                    return(new LSL_List(plist));
                }

                // It is a background event, simply call its event handler,
                // then check event queue again.
                callNo = 1;
__call1:
                ScriptEventHandler seh = m_ObjCode.scriptEventHandlerTable[stateCode, evc1];
                if (seh == null)
                {
                    goto checktmo;
                }

                DetectParams[]  saveDetParams = this.m_DetectParams;
                object[]        saveEHArgs    = this.ehArgs;
                ScriptEventCode saveEventCode = this.eventCode;

                this.m_DetectParams = evt.DetectParams;
                this.ehArgs         = evt.Params;
                this.eventCode      = evc;

                try
                {
                    seh(this);
                }
                finally
                {
                    this.m_DetectParams = saveDetParams;
                    this.ehArgs         = saveEHArgs;
                    this.eventCode      = saveEventCode;
                }

                // Keep waiting until we find a returnable event or timeout.
checktmo:
                if (DateTime.UtcNow < sleepUntil)
                {
                    goto findevent;
                }

                // We timed out, return an empty list.
                return(emptyList);
            }
            finally
            {
                if (callMode != CallMode_NORMAL)
                {
                    // Stack frame is being saved by CheckRun...().
                    // Save everything we need at the __call<n> labels so we can restore it
                    // when we need to.
                    sv    = CaptureStackFrame("xmrEventDequeue", callNo, 9);
                    sv[0] = sleepUntil.ToString();                  // needed at __call0,__call1
                    sv[1] = returnMask1;                            // needed at __call0,__call1
                    sv[2] = returnMask2;                            // needed at __call0,__call1
                    sv[3] = mask1;                                  // needed at __call0,__call1
                    sv[4] = mask2;                                  // needed at __call0,__call1
                    if (callNo == 1)
                    {
                        sv[5] = evc1;                               // needed at __call1
                        sv[6] = (int)evc;                           // needed at __call1
                        sv[7] = DetPrmsToObjArr(evt.DetectParams);  // needed at __call1
                        sv[8] = evt.Params;                         // needed at __call1
                    }
                }
            }
        }
        private void SendScriptErrorMessage(Exception e, ScriptEventCode ev)
        {
            StringBuilder msg     = new StringBuilder();
            bool          toowner = false;

            msg.Append("YEngine: ");
            if (e.Message != null)
            {
                string text = e.Message;
                if (text.StartsWith("(OWNER)"))
                {
                    text    = text.Substring(7);
                    toowner = true;
                }
                msg.Append(text);
            }

            msg.Append(" (script: ");
            msg.Append(m_Item.Name);
            msg.Append(" event: ");
            msg.Append(ev.ToString());
            msg.Append(" primID: ");
            msg.Append(m_Part.UUID.ToString());
            msg.Append(" at: <");
            Vector3 pos = m_Part.AbsolutePosition;

            msg.Append((int)Math.Floor(pos.X));
            msg.Append(',');
            msg.Append((int)Math.Floor(pos.Y));
            msg.Append(',');
            msg.Append((int)Math.Floor(pos.Z));
            msg.Append(">) Script must be Reset to re-enable.\n");

            string msgst = msg.ToString();

            if (msgst.Length > 1000)
            {
                msgst = msgst.Substring(0, 1000);
            }

            if (toowner)
            {
                ScenePresence sp = m_Engine.World.GetScenePresence(m_Part.OwnerID);
                if (sp != null && !sp.IsNPC)
                {
                    m_Engine.World.SimChatToAgent(m_Part.OwnerID, Utils.StringToBytes(msgst), 0x7FFFFFFF, m_Part.AbsolutePosition,
                                                  m_Part.Name, m_Part.UUID, false);
                }
            }
            else
            {
                m_Engine.World.SimChat(Utils.StringToBytes(msgst),
                                       ChatTypeEnum.DebugChannel, 0x7FFFFFFF,
                                       m_Part.AbsolutePosition,
                                       m_Part.Name, m_Part.UUID, false);
            }
            m_log.Debug(string.Format(
                            "[SCRIPT ERROR]: {0} (at event {1}, part {2} {3} at {4} in {5}",
                            (e.Message == null)? "" : e.Message,
                            ev.ToString(),
                            m_Part.Name,
                            m_Part.UUID,
                            m_Part.AbsolutePosition,
                            m_Part.ParentGroup.Scene.Name));

            m_SleepUntil = DateTime.MaxValue;
        }