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); }
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); }
/// <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); } }
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; }
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; }
/// <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); } }
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); }