public void AddEventSchQueue(ScriptData ID, string FunctionName, DetectParams[] qParams, EventPriority priority,
                                     params object[] param)
        {
            QueueItemStruct QIS = new QueueItemStruct
            {
                EventsProcData = new ScriptEventsProcData(),
                ID             = ID,
                functionName   = FunctionName,
                llDetectParams = qParams,
                param          = param,
                VersionID      = Interlocked.Read(ref ID.VersionID),
                State          = ID.State,
                CurrentlyAt    = null
            };

            if (ID.Script == null || ID.IgnoreNew)
            {
                return;
            }

            if (!ID.SetEventParams(QIS)) // check events delay rules
            {
                return;
            }

            ScriptEvents.Enqueue(QIS);

            long threadCount = Interlocked.Read(ref scriptThreadpool.nthreads);

            if (threadCount == 0 || threadCount < (ScriptEvents.Count + (SleepingScriptEventCount / 2)) * EventPerformance)
            {
                scriptThreadpool.QueueEvent(eventLoop, 2);
            }
        }
        public bool EventSchProcessQIS(ref QueueItemStruct QIS)
        {
            try
            {
                Exception      ex      = null;
                EnumeratorInfo Running = QIS.ID.Script.ExecuteEvent(QIS.State,
                                                                    QIS.functionName,
                                                                    QIS.param, QIS.CurrentlyAt, out ex);

                if (ex != null)
                {
                    //Check exceptions, some are ours to deal with, and others are to be logged
                    if (ex.Message.Contains("SelfDeleteException"))
                    {
                        if (QIS.ID.Part != null && QIS.ID.Part.ParentEntity != null)
                        {
                            IBackupModule backup =
                                QIS.ID.Part.ParentEntity.Scene.RequestModuleInterface <IBackupModule>();
                            if (backup != null)
                            {
                                backup.DeleteSceneObjects(
                                    new ISceneEntity[1] {
                                    QIS.ID.Part.ParentEntity
                                }, true, true);
                            }
                        }
                    }
                    else if (ex.Message.Contains("ScriptDeleteException"))
                    {
                        if (QIS.ID.Part != null && QIS.ID.Part.ParentEntity != null)
                        {
                            QIS.ID.Part.Inventory.RemoveInventoryItem(QIS.ID.ItemID);
                        }
                    }
                    //Log it for the user
                    else if (!(ex.Message.Contains("EventAbortException")) &&
                             !(ex.Message.Contains("MinEventDelayException")))
                    {
                        QIS.ID.DisplayUserNotification(ex.ToString(), "executing", false, true);
                    }
                    EventManager.EventComplete(QIS);
                    return(false);
                }
                else if (Running != null)
                {
                    //Did not finish so requeue it
                    QIS.CurrentlyAt = Running;
                    QIS.RunningNumber++;
                    return(true); //Do the return... otherwise we open the queue for this event back up
                }
            }
            catch (Exception ex)
            {
                //Error, tell the user
                QIS.ID.DisplayUserNotification(ex.ToString(), "executing", false, true);
            }
            //Tell the event manager about it so that the events will be removed from the queue
            EventManager.EventComplete(QIS);
            return(false);
        }
        public bool AddEventSchQIS(QueueItemStruct QIS, EventPriority priority)
        {
            if (QIS.ID == null || QIS.ID.IgnoreNew)
            {
                EventManager.EventComplete(QIS);
                return(false);
            }

            if (QIS.ID.Script == null)
            {
                QIS.ID.CheckAddEventToQueue(QIS);
                return(false);
            }

            if (!QIS.ID.SetEventParams(QIS)) // check events delay rules
            {
                EventManager.EventComplete(QIS);
                return(false);
            }

            QIS.CurrentlyAt = null;

            if (priority == EventPriority.Suspended || priority == EventPriority.Continued)
            {
                lock (SleepingScriptEvents)
                {
                    long time = priority == EventPriority.Suspended
                                    ? DateTime.Now.AddMilliseconds(10).Ticks
                                    : DateTime.Now.Ticks;
                    //Let it sleep for 10ms so that other scripts can process before it, any repeating plugins ought to use this
                    SleepingScriptEvents.Enqueue(QIS, time);
                    SleepingScriptEventCount++;
#if Debug
                    MainConsole.Instance.Warn(ScriptEventCount + ", " + QIS.functionName);
#endif
                }
            }
            else
            {
                ScriptEvents.Enqueue(QIS);
            }

            long threadCount = Interlocked.Read(ref scriptThreadpool.nthreads);
            if (threadCount == 0 || threadCount < (ScriptEvents.Count + (SleepingScriptEventCount / 2)) * EventPerformance)
            {
                scriptThreadpool.QueueEvent(eventLoop, 2);
            }
            return(true);
        }
예제 #4
0
        public bool CheckAddEventToQueue(QueueItemStruct itm)
        {
            if (funcsToDrop.Contains(itm.functionName))
            {
                return(false);//Drop them, don't enqueue
            }
            lock (m_eventQueueLock)
            {
                if (m_eventQueueTimer == null)//Have it try again in 5ms
                {
                    m_eventQueueTimer = new Timer(EventQueuePoke, null, 5, 5);
                }

                m_eventQueue.Enqueue(itm);
            }
            return(false);
        }
예제 #5
0
        /// <summary>
        ///     This removes the event from the queue and allows it to be fired again
        /// </summary>
        /// <param name="QIS"></param>
        public void EventComplete(QueueItemStruct QIS)
        {
            lock (QIS.ID.ScriptEventLock)
            {
                scriptEvents eventType = (scriptEvents)Enum.Parse(typeof(scriptEvents), QIS.functionName);
                switch (eventType)
                {
                case scriptEvents.timer:
                    QIS.ID.TimerInQueue = false;
                    break;

                case scriptEvents.control:
                    if (QIS.ID.ControlEventsInQueue > 0)
                    {
                        QIS.ID.ControlEventsInQueue--;
                    }
                    break;

                case scriptEvents.collision:
                    QIS.ID.CollisionInQueue = false;
                    break;

                case scriptEvents.collision_end:
                    QIS.ID.CollisionInQueue = false;
                    break;

                case scriptEvents.moving_end:
                    QIS.ID.MovingInQueue = false;
                    break;

                case scriptEvents.touch:
                    QIS.ID.TouchInQueue = false;
                    break;

                case scriptEvents.touch_end:
                    QIS.ID.TouchInQueue = false;
                    break;

                case scriptEvents.land_collision:
                    QIS.ID.LandCollisionInQueue = false;
                    break;

                case scriptEvents.land_collision_end:
                    QIS.ID.LandCollisionInQueue = false;
                    break;

                case scriptEvents.sensor:
                    QIS.ID.SensorInQueue = false;
                    break;

                case scriptEvents.no_sensor:
                    QIS.ID.NoSensorInQueue = false;
                    break;

                case scriptEvents.at_target:
                    QIS.ID.AtTargetInQueue = false;
                    break;

                case scriptEvents.not_at_target:
                    QIS.ID.NotAtTargetInQueue = false;
                    break;

                case scriptEvents.at_rot_target:
                    QIS.ID.AtRotTargetInQueue = false;
                    break;

                case scriptEvents.not_at_rot_target:
                    QIS.ID.NotAtRotTargetInQueue = false;
                    break;

                case scriptEvents.changed:
                    Changed scriptChanged;
                    if (QIS.param[0] is Changed)
                    {
                        scriptChanged = (Changed)QIS.param[0];
                    }
                    else
                    {
                        scriptChanged = (Changed)(((LSL_Types.LSLInteger)QIS.param[0]).value);
                    }
                    QIS.ID.ChangedInQueue.Remove(scriptChanged);
                    break;
                }
            }
        }
        public void EventSchExec(QueueItemStruct QIS)
        {
            if (QIS.ID == null || QIS.ID.Script == null)
            {
                return;
            }

            if (!QIS.ID.Running)
            {
                //do only state_entry and on_rez
                if (!(QIS.functionName == "state_entry" || QIS.functionName == "on_rez"))
                {
                    return;
                }
            }

            //Check the versionID so that we can kill events
            if (QIS.functionName != "link_message" &&
                QIS.VersionID != Interlocked.Read(ref QIS.ID.VersionID))
            {
                MainConsole.Instance.DebugFormat("[WDNE]: Found bad version ID in queue, resetting, {0} to {1}",
                                                 QIS.VersionID, Interlocked.Read(ref QIS.ID.VersionID));
                MainConsole.Instance.DebugFormat("[WDNE]:     Function: '{0}' in region {1}",
                                                 QIS.functionName == "" ? QIS.functionName : "unknown",
                                                 QIS.ID.Part.ParentEntity.Scene.RegionInfo.RegionName);
                //return;
            }

            if (MainConsole.Instance.IsTraceEnabled)
            {
                MainConsole.Instance.TraceFormat("[WDNE]: Running Event {0} in object {1} in region {2}",
                                                 QIS.functionName, QIS.ID.Part,
                                                 QIS.ID.Part.ParentEntity.Scene.RegionInfo.RegionName);
            }
            if (!EventSchProcessQIS(ref QIS)) //Execute the event
            {
                //All done
                lock (SleepingScriptEvents)
                    QIS.EventsProcData.State = ScriptEventsState.Idle;
            }
            else
            {
                if (QIS.CurrentlyAt.SleepTo.Ticks != 0)
                {
                    lock (SleepingScriptEvents) {
                        QIS.EventsProcData.TimeCheck = QIS.CurrentlyAt.SleepTo;
                        QIS.EventsProcData.State     = ScriptEventsState.Sleep;

                        //If it is greater, we need to check sooner for this one
                        if (NextSleepersTest.Ticks > QIS.CurrentlyAt.SleepTo.Ticks)
                        {
                            NextSleepersTest = QIS.CurrentlyAt.SleepTo;
                        }

                        SleepingScriptEvents.Enqueue(QIS, QIS.CurrentlyAt.SleepTo.Ticks);
                        SleepingScriptEventCount++;
                    }
                }
                else
                {
                    lock (SleepingScriptEvents) {
                        QIS.EventsProcData.State = ScriptEventsState.Running;
                        ScriptEvents.Enqueue(QIS);
                    }
                }
            }
        }
        public void eventLoop()
        {
            int numberOfEmptyWork = 0;

            while (!m_ScriptEngine.ConsoleDisabled && !m_ScriptEngine.Disabled &&
                   m_ScriptEngine.Scene.ShouldRunHeartbeat)
            {
                //int numScriptsProcessed = 0;
                int numSleepScriptsProcessed = 0;
                //const int minNumScriptsToProcess = 1;
                //processMoreScripts:
                QueueItemStruct QIS   = new QueueItemStruct();
                bool            found = false;

                //Check whether it is time, and then do the thread safety piece
                bool checkTime;
                lock (SleepingScriptEvents)
                    checkTime = Interlocked.CompareExchange(ref m_CheckingSleepers, 1, 0) == 0;
                if (checkTime)
                {
                    lock (SleepingScriptEvents) {
restart:
                        if (SleepingScriptEvents.Count > 0)
                        {
                            QIS   = SleepingScriptEvents.Dequeue().Value;
                            found = true;
                            if (QIS.RunningNumber > 2 && SleepingScriptEventCount > 0 &&
                                numSleepScriptsProcessed < SleepingScriptEventCount)
                            {
                                QIS.RunningNumber = 1;
                                SleepingScriptEvents.Enqueue(QIS, QIS.EventsProcData.TimeCheck.Ticks);
                                numSleepScriptsProcessed++; found = false;
                                found = false;
                                goto restart;
                            }
                        }
                    }
                    if (found)
                    {
                        bool expired;
                        lock (SleepingScriptEvents)
                            expired = QIS.EventsProcData.TimeCheck.Ticks < DateTime.Now.Ticks;

                        if (expired)
                        {
                            DateTime NextTime = DateTime.MaxValue;
                            lock (SleepingScriptEvents) {
                                if (SleepingScriptEvents.Count > 0)
                                {
                                    NextTime = SleepingScriptEvents.Peek().Value.EventsProcData.TimeCheck;
                                }
                                //Now add in the next sleep time
                                NextSleepersTest = NextTime;

                                //All done
                                Interlocked.Exchange(ref m_CheckingSleepers, 0);
                            }

                            //Execute the event
                            EventSchExec(QIS);
                            lock (SleepingScriptEvents)
                                SleepingScriptEventCount--;
                            //numScriptsProcessed++;
                        }
                        else
                        {
                            lock (SleepingScriptEvents) {
                                NextSleepersTest = QIS.EventsProcData.TimeCheck;
                                SleepingScriptEvents.Enqueue(QIS, QIS.EventsProcData.TimeCheck.Ticks);
                                //All done
                                Interlocked.Exchange(ref m_CheckingSleepers, 0);
                            }
                        }
                    }
                    else   //No more left, don't check again
                    {
                        lock (SleepingScriptEvents) {
                            NextSleepersTest = DateTime.MaxValue;
                            //All done
                            Interlocked.Exchange(ref m_CheckingSleepers, 0);
                        }
                    }
                }
                int timeToSleep = 5;
                //If we can, get the next event
                if (Interlocked.CompareExchange(ref m_CheckingEvents, 1, 0) == 0)
                {
                    if (ScriptEvents.TryDequeue(out QIS))
                    {
                        Interlocked.Exchange(ref m_CheckingEvents, 0);
#if Debug
                        MainConsole.Instance.Warn(QIS.functionName + "," + ScriptEvents.Count);
#endif
                        EventSchExec(QIS);
                        //numScriptsProcessed++;
                    }
                    else
                    {
                        Interlocked.Exchange(ref m_CheckingEvents, 0);
                    }
                }
                //Process a bunch each time
                //if (ScriptEventCount > 0 && numScriptsProcessed < minNumScriptsToProcess)
                //    goto processMoreScripts;

                lock (SleepingScriptEvents) {
                    if (ScriptEvents.Count == 0 && NextSleepersTest.Ticks != DateTime.MaxValue.Ticks)
                    {
                        timeToSleep = (int)(NextSleepersTest - DateTime.Now).TotalMilliseconds;
                    }
                }
                if (timeToSleep < 5)
                {
                    timeToSleep = 5;
                }
                if (timeToSleep > 50)
                {
                    timeToSleep = 50;
                }

                if (SleepingScriptEventCount == 0 && ScriptEvents.Count == 0)
                {
                    numberOfEmptyWork++;
                    if (numberOfEmptyWork > EMPTY_WORK_KILL_THREAD_TIME)
                    //Don't break immediately, otherwise we have to wait to spawn more threads
                    {
                        break; //No more events, end
                    }
                    else if (numberOfEmptyWork > EMPTY_WORK_KILL_THREAD_TIME / 20)
                    {
                        timeToSleep += 10;
                    }
                }
                else if (Interlocked.Read(ref scriptThreadpool.nthreads) >
                         (ScriptEvents.Count + (int)((SleepingScriptEventCount / 2f + 0.5f))) ||
                         Interlocked.Read(ref scriptThreadpool.nthreads) > MaxScriptThreads)
                {
                    numberOfEmptyWork++;
                    if (numberOfEmptyWork > (EMPTY_WORK_KILL_THREAD_TIME / 2)) //Don't break immediately
                    {
                        break;                                                 //Too many threads, kill some off
                    }
                    else if (numberOfEmptyWork > EMPTY_WORK_KILL_THREAD_TIME / 20)
                    {
                        timeToSleep += 5;
                    }
                }
                else
                {
                    numberOfEmptyWork /= 2; //Cut it down, but don't zero it out, as this may just be one event
                }
#if Debug
                MainConsole.Instance.Warn("Sleep: " + timeToSleep);
#endif
                Interlocked.Increment(ref scriptThreadpool.nSleepingthreads);
                Thread.Sleep(timeToSleep);
                Interlocked.Decrement(ref scriptThreadpool.nSleepingthreads);
            }
        }
예제 #8
0
        public bool CheckAddEventToQueue(QueueItemStruct itm)
        {
            if (funcsToDrop.Contains(itm.functionName))
                return false;//Drop them, don't enqueue


            lock (m_eventQueueLock)
            {
                if (m_eventQueueTimer == null)//Have it try again in 5ms
                    m_eventQueueTimer = new Timer(EventQueuePoke, null, 5, 5);

                m_eventQueue.Enqueue(itm);
            }
            return false;
        }
예제 #9
0
        public bool SetEventParams(QueueItemStruct itm)
        {
            if (Suspended || !Running)
                return false; //No suspended scripts...
            if (itm.llDetectParams.Length > 0)
                LastDetectParams = itm.llDetectParams;

            if (itm.functionName == "state_entry" || itm.functionName == "state_exit" || itm.functionName == "on_rez")
                return true;

            long NowTicks = Util.EnvironmentTickCount();

            if (EventDelayTicks != 0)
            {
                if (NowTicks < NextEventTimeTicks)
                    return false;
                NextEventTimeTicks = NowTicks + EventDelayTicks;
            }
            switch (itm.functionName)
            {
                    //Times pulled from http://wiki.secondlife.com/wiki/LSL_Delay
                case "touch": //Limits for 0.1 seconds
                case "touch_start":
                case "touch_end":
                    if (NowTicks < NextEventDelay[itm.functionName])
                        return CheckAddEventToQueue(itm);
                    NextEventDelay[itm.functionName] = NowTicks + (long) (TouchEventDelayTicks*TicksPerMillisecond);
                    break;
                case "timer": //Settable timer limiter
                    if (NowTicks < NextEventDelay[itm.functionName])
                        return CheckAddEventToQueue(itm);
                    NextEventDelay[itm.functionName] = NowTicks + (long) (TimerEventDelayTicks*TicksPerMillisecond);
                    break;
                case "collision":
                case "collision_start":
                case "collision_end":
                case "land_collision":
                case "land_collision_start":
                case "land_collision_end":
                    if (NowTicks < NextEventDelay[itm.functionName])
                        return CheckAddEventToQueue(itm);
                    NextEventDelay[itm.functionName] = NowTicks + (long) (CollisionEventDelayTicks*TicksPerMillisecond);
                    break;
                case "control":
                    if (NowTicks < NextEventDelay[itm.functionName])
                        return CheckAddEventToQueue(itm);
                    NextEventDelay[itm.functionName] = NowTicks + (long) (0.05f*TicksPerMillisecond);
                    break;
                default: //Default is 0.05 seconds for event limiting
                    if (!NextEventDelay.ContainsKey(itm.functionName))
                        break; //If it doesn't exist, we don't limit it
                    if (NowTicks < NextEventDelay[itm.functionName])
                        return CheckAddEventToQueue(itm);
                    NextEventDelay[itm.functionName] = NowTicks + (long) (DefaultEventDelayTicks*TicksPerMillisecond);
                    break;
            }
            //Add the event to the stats
            ScriptScore++;
            m_ScriptEngine.ScriptEPS++;
            return true;
        }
예제 #10
0
 /// <summary>
 ///     This removes the event from the queue and allows it to be fired again
 /// </summary>
 /// <param name="QIS"></param>
 public void EventComplete(QueueItemStruct QIS)
 {
     lock (QIS.ID.ScriptEventLock)
     {
         scriptEvents eventType = (scriptEvents) Enum.Parse(typeof (scriptEvents), QIS.functionName);
         switch (eventType)
         {
             case scriptEvents.timer:
                 QIS.ID.TimerInQueue = false;
                 break;
             case scriptEvents.control:
                 if (QIS.ID.ControlEventsInQueue > 0)
                     QIS.ID.ControlEventsInQueue--;
                 break;
             case scriptEvents.collision:
                 QIS.ID.CollisionInQueue = false;
                 break;
             case scriptEvents.collision_end:
                 QIS.ID.CollisionInQueue = false;
                 break;
             case scriptEvents.moving_end:
                 QIS.ID.MovingInQueue = false;
                 break;
             case scriptEvents.touch:
                 QIS.ID.TouchInQueue = false;
                 break;
             case scriptEvents.touch_end:
                 QIS.ID.TouchInQueue = false;
                 break;
             case scriptEvents.land_collision:
                 QIS.ID.LandCollisionInQueue = false;
                 break;
             case scriptEvents.land_collision_end:
                 QIS.ID.LandCollisionInQueue = false;
                 break;
             case scriptEvents.sensor:
                 QIS.ID.SensorInQueue = false;
                 break;
             case scriptEvents.no_sensor:
                 QIS.ID.NoSensorInQueue = false;
                 break;
             case scriptEvents.at_target:
                 QIS.ID.AtTargetInQueue = false;
                 break;
             case scriptEvents.not_at_target:
                 QIS.ID.NotAtTargetInQueue = false;
                 break;
             case scriptEvents.at_rot_target:
                 QIS.ID.AtRotTargetInQueue = false;
                 break;
             case scriptEvents.not_at_rot_target:
                 QIS.ID.NotAtRotTargetInQueue = false;
                 break;
             case scriptEvents.changed:
             Changed scriptChanged;
                 if (QIS.param[0] is Changed)
                 {
                     scriptChanged = (Changed) QIS.param[0];
                 }
                 else
                 {
                     scriptChanged = (Changed) (((LSL_Types.LSLInteger) QIS.param[0]).value);
                 }
                 QIS.ID.ChangedInQueue.Remove(scriptChanged);
                 break;
         }
     }
 }
        public bool EventSchProcessQIS(ref QueueItemStruct QIS)
        {
            try
            {
                Exception ex = null;
                EnumeratorInfo Running = QIS.ID.Script.ExecuteEvent(QIS.State,
                                                                    QIS.functionName,
                                                                    QIS.param, QIS.CurrentlyAt, out ex);

                if (ex != null)
                {
                    //Check exceptions, some are ours to deal with, and others are to be logged
                    if (ex.Message.Contains("SelfDeleteException"))
                    {
                        if (QIS.ID.Part != null && QIS.ID.Part.ParentEntity != null)
                        {
                            IBackupModule backup =
                                QIS.ID.Part.ParentEntity.Scene.RequestModuleInterface<IBackupModule>();
                            if (backup != null)
                                backup.DeleteSceneObjects(
                                    new ISceneEntity[1] {QIS.ID.Part.ParentEntity}, true, true);
                        }
                    }
                    else if (ex.Message.Contains("ScriptDeleteException"))
                    {
                        if (QIS.ID.Part != null && QIS.ID.Part.ParentEntity != null)
                            QIS.ID.Part.Inventory.RemoveInventoryItem(QIS.ID.ItemID);
                    }
                        //Log it for the user
                    else if (!(ex.Message.Contains("EventAbortException")) &&
                             !(ex.Message.Contains("MinEventDelayException")))
                        QIS.ID.DisplayUserNotification(ex.ToString(), "executing", false, true);
                    EventManager.EventComplete(QIS);
                    return false;
                }
                else if (Running != null)
                {
                    //Did not finish so requeue it
                    QIS.CurrentlyAt = Running;
                    QIS.RunningNumber++;
                    return true; //Do the return... otherwise we open the queue for this event back up
                }
            }
            catch (Exception ex)
            {
                //Error, tell the user
                QIS.ID.DisplayUserNotification(ex.ToString(), "executing", false, true);
            }
            //Tell the event manager about it so that the events will be removed from the queue
            EventManager.EventComplete(QIS);
            return false;
        }
        public void EventSchExec(QueueItemStruct QIS)
        {
            if (QIS.ID == null || QIS.ID.Script == null)
                return;

            if (!QIS.ID.Running)
            {
                //do only state_entry and on_rez
                if (!(QIS.functionName == "state_entry" || QIS.functionName == "on_rez"))
                {
                    return;
                }
            }

            //Check the versionID so that we can kill events
            if (QIS.functionName != "link_message" &&
                QIS.VersionID != Interlocked.Read(ref QIS.ID.VersionID))
            {
                MainConsole.Instance.DebugFormat("[WDNE]: Found bad version ID in queue, resetting, {0} to {1}",
                                                QIS.VersionID, Interlocked.Read(ref QIS.ID.VersionID));
                MainConsole.Instance.DebugFormat("[WDNE]:     Function: '{0}' in region {1}",
					QIS.functionName == "" ? QIS.functionName : "unknown",
                    QIS.ID.Part.ParentEntity.Scene.RegionInfo.RegionName);
                //return;
            }

            if(MainConsole.Instance.IsTraceEnabled)
                MainConsole.Instance.TraceFormat("[WDNE]: Running Event {0} in object {1} in region {2}",
                                           QIS.functionName, QIS.ID.Part,
                                           QIS.ID.Part.ParentEntity.Scene.RegionInfo.RegionName);
            if (!EventSchProcessQIS(ref QIS)) //Execute the event
            {
                //All done
                lock (SleepingScriptEvents) 
                    QIS.EventsProcData.State = ScriptEventsState.Idle;
            }
            else
            {
                if (QIS.CurrentlyAt.SleepTo.Ticks != 0)
                {
                    lock(SleepingScriptEvents) {
                        QIS.EventsProcData.TimeCheck = QIS.CurrentlyAt.SleepTo;
                        QIS.EventsProcData.State = ScriptEventsState.Sleep;
                    
                        //If it is greater, we need to check sooner for this one
                        if (NextSleepersTest.Ticks > QIS.CurrentlyAt.SleepTo.Ticks)
                            NextSleepersTest = QIS.CurrentlyAt.SleepTo;
                    
                        SleepingScriptEvents.Enqueue(QIS, QIS.CurrentlyAt.SleepTo.Ticks);
                        SleepingScriptEventCount++;
                    }
                }
                else
                {
                    lock (SleepingScriptEvents) {
                        QIS.EventsProcData.State = ScriptEventsState.Running;
                        ScriptEvents.Enqueue (QIS);
                    }
                }
            }
        }
        public void eventLoop()
        {
            int numberOfEmptyWork = 0;
            while (!m_ScriptEngine.ConsoleDisabled && !m_ScriptEngine.Disabled &&
                   m_ScriptEngine.Scene.ShouldRunHeartbeat) {
                //int numScriptsProcessed = 0;
                int numSleepScriptsProcessed = 0;
                //const int minNumScriptsToProcess = 1;
                //processMoreScripts:
                QueueItemStruct QIS = new QueueItemStruct ();
                bool found = false;

                //Check whether it is time, and then do the thread safety piece
                bool checkTime;
                lock (SleepingScriptEvents)
                    checkTime = Interlocked.CompareExchange (ref m_CheckingSleepers, 1, 0) == 0;
                if (checkTime) {
                    lock (SleepingScriptEvents) {
                    restart:
                        if (SleepingScriptEvents.Count > 0) {
                            QIS = SleepingScriptEvents.Dequeue ().Value;
                            found = true;
                            if (QIS.RunningNumber > 2 && SleepingScriptEventCount > 0 &&
                                numSleepScriptsProcessed < SleepingScriptEventCount) {
                                QIS.RunningNumber = 1;
                                SleepingScriptEvents.Enqueue (QIS, QIS.EventsProcData.TimeCheck.Ticks);
                                numSleepScriptsProcessed++; found = false;
                                found = false;
                                goto restart;
                            }
                        }
                    }
                    if (found) {
                        bool expired;
                        lock (SleepingScriptEvents)
                            expired = QIS.EventsProcData.TimeCheck.Ticks < DateTime.Now.Ticks;

                        if (expired) {
                            DateTime NextTime = DateTime.MaxValue;
                            lock (SleepingScriptEvents) {
                                if (SleepingScriptEvents.Count > 0)
                                    NextTime = SleepingScriptEvents.Peek ().Value.EventsProcData.TimeCheck;
                                //Now add in the next sleep time
                                NextSleepersTest = NextTime;

                                //All done
                                Interlocked.Exchange (ref m_CheckingSleepers, 0);
                            }

                            //Execute the event
                            EventSchExec (QIS);
                            lock (SleepingScriptEvents)
                                SleepingScriptEventCount--;
                            //numScriptsProcessed++;
                        } else {
                            lock (SleepingScriptEvents) {
                                NextSleepersTest = QIS.EventsProcData.TimeCheck;
                                SleepingScriptEvents.Enqueue (QIS, QIS.EventsProcData.TimeCheck.Ticks);
                                //All done
                                Interlocked.Exchange (ref m_CheckingSleepers, 0);
                            }
                        }
                    } else //No more left, don't check again
                      {
                        lock (SleepingScriptEvents) {
                            NextSleepersTest = DateTime.MaxValue;
                            //All done
                            Interlocked.Exchange (ref m_CheckingSleepers, 0);
                        }
                    }
                }
                int timeToSleep = 5;
                //If we can, get the next event
                if (Interlocked.CompareExchange (ref m_CheckingEvents, 1, 0) == 0) {
                    if (ScriptEvents.TryDequeue (out QIS)) {
                        Interlocked.Exchange (ref m_CheckingEvents, 0);
#if Debug
                        MainConsole.Instance.Warn(QIS.functionName + "," + ScriptEvents.Count);
#endif
                        EventSchExec (QIS);
                        //numScriptsProcessed++;
                    } else
                        Interlocked.Exchange (ref m_CheckingEvents, 0);
                }
                //Process a bunch each time
                //if (ScriptEventCount > 0 && numScriptsProcessed < minNumScriptsToProcess)
                //    goto processMoreScripts;

                lock (SleepingScriptEvents) {
                    if (ScriptEvents.Count == 0 && NextSleepersTest.Ticks != DateTime.MaxValue.Ticks)
                        timeToSleep = (int)(NextSleepersTest - DateTime.Now).TotalMilliseconds;
                }
                if (timeToSleep < 5)
                    timeToSleep = 5;
                if (timeToSleep > 50)
                    timeToSleep = 50;

                if (SleepingScriptEventCount == 0 && ScriptEvents.Count == 0)
                {
                    numberOfEmptyWork++;
                    if (numberOfEmptyWork > EMPTY_WORK_KILL_THREAD_TIME)
                        //Don't break immediately, otherwise we have to wait to spawn more threads
                    {
                        break; //No more events, end
                    }
                    else if (numberOfEmptyWork > EMPTY_WORK_KILL_THREAD_TIME/20)
                        timeToSleep += 10;
                }
                else if (Interlocked.Read(ref scriptThreadpool.nthreads) >
                         (ScriptEvents.Count + (int) ((SleepingScriptEventCount/2f + 0.5f))) ||
                         Interlocked.Read(ref scriptThreadpool.nthreads) > MaxScriptThreads)
                {
                    numberOfEmptyWork++;
                    if (numberOfEmptyWork > (EMPTY_WORK_KILL_THREAD_TIME/2)) //Don't break immediately
                    {
                        break; //Too many threads, kill some off
                    }
                    else if (numberOfEmptyWork > EMPTY_WORK_KILL_THREAD_TIME/20)
                        timeToSleep += 5;
                }
                else
                    numberOfEmptyWork /= 2; //Cut it down, but don't zero it out, as this may just be one event
#if Debug
                MainConsole.Instance.Warn ("Sleep: " + timeToSleep);
#endif
                Interlocked.Increment(ref scriptThreadpool.nSleepingthreads);
                Thread.Sleep(timeToSleep);
                Interlocked.Decrement(ref scriptThreadpool.nSleepingthreads);
            }
        }
        public bool AddEventSchQIS(QueueItemStruct QIS, EventPriority priority)
        {
            if (QIS.ID == null || QIS.ID.IgnoreNew)
            {
                EventManager.EventComplete(QIS);
                return false;
            }

            if (QIS.ID.Script == null)
            {
                QIS.ID.CheckAddEventToQueue(QIS);
                return false;
            }

            if (!QIS.ID.SetEventParams(QIS)) // check events delay rules
            {
                EventManager.EventComplete(QIS);
                return false;
            }

            QIS.CurrentlyAt = null;

            if (priority == EventPriority.Suspended || priority == EventPriority.Continued)
            {
                lock (SleepingScriptEvents)
                {
                    long time = priority == EventPriority.Suspended
                                    ? DateTime.Now.AddMilliseconds(10).Ticks
                                    : DateTime.Now.Ticks;
                    //Let it sleep for 10ms so that other scripts can process before it, any repeating plugins ought to use this
                    SleepingScriptEvents.Enqueue(QIS, time);
                    SleepingScriptEventCount++;
#if Debug
                MainConsole.Instance.Warn (ScriptEventCount + ", " + QIS.functionName);
#endif
                }
            }
            else
                ScriptEvents.Enqueue(QIS);

            long threadCount = Interlocked.Read(ref scriptThreadpool.nthreads);
            if (threadCount == 0 || threadCount < (ScriptEvents.Count + (SleepingScriptEventCount/2))*EventPerformance)
            {
                scriptThreadpool.QueueEvent(eventLoop, 2);
            }
            return true;
        }
        public void AddEventSchQueue(ScriptData ID, string FunctionName, DetectParams[] qParams, EventPriority priority,
                                     params object[] param)
        {
            QueueItemStruct QIS = new QueueItemStruct
            {
                EventsProcData = new ScriptEventsProcData(),
                ID = ID,
                functionName = FunctionName,
                llDetectParams = qParams,
                param = param,
                VersionID = Interlocked.Read(ref ID.VersionID),
                State = ID.State,
                CurrentlyAt = null
            };

            if (ID.Script == null || ID.IgnoreNew)
                return;

            if (!ID.SetEventParams(QIS)) // check events delay rules
                return;

            ScriptEvents.Enqueue(QIS);

            long threadCount = Interlocked.Read(ref scriptThreadpool.nthreads);
            if (threadCount == 0 || threadCount < (ScriptEvents.Count + (SleepingScriptEventCount/2))*EventPerformance)
            {
                scriptThreadpool.QueueEvent(eventLoop, 2);
            }
        }
예제 #16
0
        public bool SetEventParams(QueueItemStruct itm)
        {
            if (Suspended || !Running)
            {
                return(false); //No suspended scripts...
            }
            if (itm.llDetectParams.Length > 0)
            {
                LastDetectParams = itm.llDetectParams;
            }

            if (itm.functionName == "state_entry" || itm.functionName == "state_exit" || itm.functionName == "on_rez")
            {
                return(true);
            }

            long NowTicks = Util.EnvironmentTickCount();

            if (EventDelayTicks != 0)
            {
                if (NowTicks < NextEventTimeTicks)
                {
                    return(false);
                }
                NextEventTimeTicks = NowTicks + EventDelayTicks;
            }
            switch (itm.functionName)
            {
            //Times pulled from http://wiki.secondlife.com/wiki/LSL_Delay
            case "touch":     //Limits for 0.1 seconds
            case "touch_start":
            case "touch_end":
                if (NowTicks < NextEventDelay[itm.functionName])
                {
                    return(CheckAddEventToQueue(itm));
                }
                NextEventDelay[itm.functionName] = NowTicks + (long)(TouchEventDelayTicks * TicksPerMillisecond);
                break;

            case "timer":     //Settable timer limiter
                if (NowTicks < NextEventDelay[itm.functionName])
                {
                    return(CheckAddEventToQueue(itm));
                }
                NextEventDelay[itm.functionName] = NowTicks + (long)(TimerEventDelayTicks * TicksPerMillisecond);
                break;

            case "collision":
            case "collision_start":
            case "collision_end":
            case "land_collision":
            case "land_collision_start":
            case "land_collision_end":
                if (NowTicks < NextEventDelay[itm.functionName])
                {
                    return(CheckAddEventToQueue(itm));
                }
                NextEventDelay[itm.functionName] = NowTicks + (long)(CollisionEventDelayTicks * TicksPerMillisecond);
                break;

            case "control":
                if (NowTicks < NextEventDelay[itm.functionName])
                {
                    return(CheckAddEventToQueue(itm));
                }
                NextEventDelay[itm.functionName] = NowTicks + (long)(0.05f * TicksPerMillisecond);
                break;

            default:     //Default is 0.05 seconds for event limiting
                if (!NextEventDelay.ContainsKey(itm.functionName))
                {
                    break;     //If it doesn't exist, we don't limit it
                }
                if (NowTicks < NextEventDelay[itm.functionName])
                {
                    return(CheckAddEventToQueue(itm));
                }
                NextEventDelay[itm.functionName] = NowTicks + (long)(DefaultEventDelayTicks * TicksPerMillisecond);
                break;
            }
            //Add the event to the stats
            ScriptScore++;
            m_ScriptEngine.ScriptEPS++;
            return(true);
        }