// Fire any timers that have expired, and update the native timer to schedule the rest of them. // We're in a thread pool work item here, and if there are multiple timers to be fired, we want // to queue all but the first one. The first may can then be invoked synchronously or queued, // a task left up to our caller, which might be firing timers from multiple queues. private void FireNextTimers() { // We fire the first timer on this thread; any other timers that need to be fired // are queued to the ThreadPool. TimerQueueTimer?timerToFireOnThisThread = null; lock (this) { // Since we got here, that means our previous timer has fired. _isTimerScheduled = false; bool haveTimerToSchedule = false; uint nextTimerDuration = uint.MaxValue; long nowTicks = TickCount64; // Sweep through the "short" timers. If the current tick count is greater than // the current threshold, also sweep through the "long" timers. Finally, as part // of sweeping the long timers, move anything that'll fire within the next threshold // to the short list. It's functionally ok if more timers end up in the short list // than is truly necessary (but not the opposite). TimerQueueTimer?timer = _shortTimers; for (int listNum = 0; listNum < 2; listNum++) // short == 0, long == 1 { while (timer != null) { Debug.Assert(timer._dueTime != Timeout.UnsignedInfinite, "A timer in the list must have a valid due time."); // Save off the next timer to examine, in case our examination of this timer results // in our deleting or moving it; we'll continue after with this saved next timer. TimerQueueTimer?next = timer._next; long elapsed = nowTicks - timer._startTicks; long remaining = timer._dueTime - elapsed; if (remaining <= 0) { // Timer is ready to fire. if (timer._period != Timeout.UnsignedInfinite) { // This is a repeating timer; schedule it to run again. // Discount the extra amount of time that has elapsed since the previous firing time to // prevent timer ticks from drifting. If enough time has already elapsed for the timer to fire // again, meaning the timer can't keep up with the short period, have it fire 1 ms from now to // avoid spinning without a delay. timer._startTicks = nowTicks; long elapsedForNextDueTime = elapsed - timer._dueTime; timer._dueTime = (elapsedForNextDueTime < timer._period) ? timer._period - (uint)elapsedForNextDueTime : 1; // Update the timer if this becomes the next timer to fire. if (timer._dueTime < nextTimerDuration) { haveTimerToSchedule = true; nextTimerDuration = timer._dueTime; } // Validate that the repeating timer is still on the right list. It's likely that // it started in the long list and was moved to the short list at some point, so // we now want to move it back to the long list if that's where it belongs. Note that // if we're currently processing the short list and move it to the long list, we may // end up revisiting it again if we also enumerate the long list, but we will have already // updated the due time appropriately so that we won't fire it again (it's also possible // but rare that we could be moving a timer from the long list to the short list here, // if the initial due time was set to be long but the timer then had a short period). bool targetShortList = (nowTicks + timer._dueTime) - _currentAbsoluteThreshold <= 0; if (timer._short != targetShortList) { MoveTimerToCorrectList(timer, targetShortList); } } else { // Not repeating; remove it from the queue DeleteTimer(timer); } // If this is the first timer, we'll fire it on this thread (after processing // all others). Otherwise, queue it to the ThreadPool. if (timerToFireOnThisThread == null) { timerToFireOnThisThread = timer; } else { ThreadPool.UnsafeQueueUserWorkItemInternal(timer, preferLocal: false); } } else { // This timer isn't ready to fire. Update the next time the native timer fires if necessary, // and move this timer to the short list if its remaining time is now at or under the threshold. if (remaining < nextTimerDuration) { haveTimerToSchedule = true; nextTimerDuration = (uint)remaining; } if (!timer._short && remaining <= ShortTimersThresholdMilliseconds) { MoveTimerToCorrectList(timer, shortList: true); } } timer = next; } // Switch to process the long list if necessary. if (listNum == 0) { // Determine how much time remains between now and the current threshold. If time remains, // we can skip processing the long list. We use > rather than >= because, although we // know that if remaining == 0 no timers in the long list will need to be fired, we // don't know without looking at them when we'll need to call FireNextTimers again. We // could in that case just set the next firing to 1, but we may as well just iterate the // long list now; otherwise, most timers created in the interim would end up in the long // list and we'd likely end up paying for another invocation of FireNextTimers that could // have been delayed longer (to whatever is the current minimum in the long list). long remaining = _currentAbsoluteThreshold - nowTicks; if (remaining > 0) { if (_shortTimers == null && _longTimers != null) { // We don't have any short timers left and we haven't examined the long list, // which means we likely don't have an accurate nextTimerDuration. // But we do know that nothing in the long list will be firing before or at _currentAbsoluteThreshold, // so we can just set nextTimerDuration to the difference between then and now. nextTimerDuration = (uint)remaining + 1; haveTimerToSchedule = true; } break; } // Switch to processing the long list. timer = _longTimers; // Now that we're going to process the long list, update the current threshold. _currentAbsoluteThreshold = nowTicks + ShortTimersThresholdMilliseconds; } } // If we still have scheduled timers, update the timer to ensure it fires // in time for the next one in line. if (haveTimerToSchedule) { EnsureTimerFiresBy(nextTimerDuration); } } // Fire the user timer outside of the lock! timerToFireOnThisThread?.Fire(); }
// // Fire any timers that have expired, and update the native timer to schedule the rest of them. // private void FireNextTimers() { // // we fire the first timer on this thread; any other timers that might have fired are queued // to the ThreadPool. // TimerQueueTimer timerToFireOnThisThread = null; using (LockHolder.Hold(Lock)) { // // since we got here, that means our previous timer has fired. // ReleaseTimer(); m_currentNativeTimerDuration = UInt32.MaxValue; bool haveTimerToSchedule = false; uint nextAppDomainTimerDuration = uint.MaxValue; int nowTicks = TickCount; // // Sweep through all timers. The ones that have reached their due time // will fire. We will calculate the next native timer due time from the // other timers. // TimerQueueTimer timer = m_timers; while (timer != null) { Debug.Assert(timer.m_dueTime != Timer.UnsignedInfiniteTimeout); uint elapsed = (uint)(nowTicks - timer.m_startTicks); if (elapsed >= timer.m_dueTime) { // // Remember the next timer in case we delete this one // TimerQueueTimer nextTimer = timer.m_next; if (timer.m_period != Timer.UnsignedInfiniteTimeout) { timer.m_startTicks = nowTicks; timer.m_dueTime = timer.m_period; // // This is a repeating timer; schedule it to run again. // if (timer.m_dueTime < nextAppDomainTimerDuration) { haveTimerToSchedule = true; nextAppDomainTimerDuration = timer.m_dueTime; } } else { // // Not repeating; remove it from the queue // DeleteTimer(timer); } // // If this is the first timer, we'll fire it on this thread. Otherwise, queue it // to the ThreadPool. // if (timerToFireOnThisThread == null) { timerToFireOnThisThread = timer; } else { QueueTimerCompletion(timer); } timer = nextTimer; } else { // // This timer hasn't fired yet. Just update the next time the native timer fires. // uint remaining = timer.m_dueTime - elapsed; if (remaining < nextAppDomainTimerDuration) { haveTimerToSchedule = true; nextAppDomainTimerDuration = remaining; } timer = timer.m_next; } } if (haveTimerToSchedule) { EnsureAppDomainTimerFiresBy(nextAppDomainTimerDuration); } } // // Fire the user timer outside of the lock! // if (timerToFireOnThisThread != null) { timerToFireOnThisThread.Fire(); } }
// Token: 0x06003D1F RID: 15647 RVA: 0x000E3504 File Offset: 0x000E1704 private void FireNextTimers() { TimerQueueTimer timerQueueTimer = null; lock (this) { try { } finally { this.m_isAppDomainTimerScheduled = false; bool flag2 = false; uint num = uint.MaxValue; int tickCount = TimerQueue.TickCount; TimerQueueTimer timerQueueTimer2 = this.m_timers; while (timerQueueTimer2 != null) { uint num2 = (uint)(tickCount - timerQueueTimer2.m_startTicks); if (num2 >= timerQueueTimer2.m_dueTime) { TimerQueueTimer next = timerQueueTimer2.m_next; if (timerQueueTimer2.m_period != 4294967295U) { timerQueueTimer2.m_startTicks = tickCount; timerQueueTimer2.m_dueTime = timerQueueTimer2.m_period; if (timerQueueTimer2.m_dueTime < num) { flag2 = true; num = timerQueueTimer2.m_dueTime; } } else { this.DeleteTimer(timerQueueTimer2); } if (timerQueueTimer == null) { timerQueueTimer = timerQueueTimer2; } else { TimerQueue.QueueTimerCompletion(timerQueueTimer2); } timerQueueTimer2 = next; } else { uint num3 = timerQueueTimer2.m_dueTime - num2; if (num3 < num) { flag2 = true; num = num3; } timerQueueTimer2 = timerQueueTimer2.m_next; } } if (flag2) { this.EnsureAppDomainTimerFiresBy(num); } } } if (timerQueueTimer != null) { timerQueueTimer.Fire(); } }
private volatile int m_pauseTicks = 0; // Time when Pause was called // // Fire any timers that have expired, and update the native timer to schedule the rest of them. // We're in a thread pool work item here, and if there are multiple timers to be fired, we want // to queue all but the first one. The first may can then be invoked synchronously or queued, // a task left up to our caller, which might be firing timers from multiple queues. // private void FireNextTimers() { // // we fire the first timer on this thread; any other timers that might have fired are queued // to the ThreadPool. // TimerQueueTimer timerToFireOnThisThread = null; lock (this) { // prevent ThreadAbort while updating state try { } finally { // // since we got here, that means our previous timer has fired. // m_isAppDomainTimerScheduled = false; bool haveTimerToSchedule = false; uint nextAppDomainTimerDuration = uint.MaxValue; int nowTicks = TickCount; // // Sweep through all timers. The ones that have reached their due time // will fire. We will calculate the next native timer due time from the // other timers. // TimerQueueTimer timer = m_timers; while (timer != null) { Debug.Assert(timer.m_dueTime != Timeout.UnsignedInfinite); uint elapsed = (uint)(nowTicks - timer.m_startTicks); if (elapsed >= timer.m_dueTime) { // // Remember the next timer in case we delete this one // TimerQueueTimer nextTimer = timer.m_next; if (timer.m_period != Timeout.UnsignedInfinite) { timer.m_startTicks = nowTicks; uint elapsedForNextDueTime = elapsed - timer.m_dueTime; if (elapsedForNextDueTime < timer.m_period) { // Discount the extra amount of time that has elapsed since the previous firing time to // prevent timer ticks from drifting timer.m_dueTime = timer.m_period - elapsedForNextDueTime; } else { // Enough time has elapsed to fire the timer yet again. The timer is not able to keep up // with the short period, have it fire 1 ms from now to avoid spinning without a delay. timer.m_dueTime = 1; } // // This is a repeating timer; schedule it to run again. // if (timer.m_dueTime < nextAppDomainTimerDuration) { haveTimerToSchedule = true; nextAppDomainTimerDuration = timer.m_dueTime; } } else { // // Not repeating; remove it from the queue // DeleteTimer(timer); } // // If this is the first timer, we'll fire it on this thread. Otherwise, queue it // to the ThreadPool. // if (timerToFireOnThisThread == null) { timerToFireOnThisThread = timer; } else { QueueTimerCompletion(timer); } timer = nextTimer; } else { // // This timer hasn't fired yet. Just update the next time the native timer fires. // uint remaining = timer.m_dueTime - elapsed; if (remaining < nextAppDomainTimerDuration) { haveTimerToSchedule = true; nextAppDomainTimerDuration = remaining; } timer = timer.m_next; } } if (haveTimerToSchedule) { EnsureAppDomainTimerFiresBy(nextAppDomainTimerDuration); } } } // // Fire the user timer outside of the lock! // if (timerToFireOnThisThread != null) { timerToFireOnThisThread.Fire(); } }
private void FireNextTimers() { TimerQueueTimer timerQueueTimer = (TimerQueueTimer)null; lock (this) { try { } finally { this.m_isAppDomainTimerScheduled = false; bool local_3 = false; uint local_4 = uint.MaxValue; int local_5 = TimerQueue.TickCount; TimerQueueTimer local_6 = this.m_timers; while (local_6 != null) { uint local_7 = (uint)(local_5 - local_6.m_startTicks); if (local_7 >= local_6.m_dueTime) { TimerQueueTimer temp_33 = local_6.m_next; if ((int)local_6.m_period != -1) { local_6.m_startTicks = local_5; TimerQueueTimer temp_44 = local_6; int temp_45 = (int)temp_44.m_period; temp_44.m_dueTime = (uint)temp_45; if (local_6.m_dueTime < local_4) { local_3 = true; local_4 = local_6.m_dueTime; } } else { this.DeleteTimer(local_6); } if (timerQueueTimer == null) { timerQueueTimer = local_6; } else { TimerQueue.QueueTimerCompletion(local_6); } local_6 = temp_33; } else { uint local_8 = local_6.m_dueTime - local_7; if (local_8 < local_4) { local_3 = true; local_4 = local_8; } local_6 = local_6.m_next; } } if (local_3) { this.EnsureAppDomainTimerFiresBy(local_4); } } } if (timerQueueTimer == null) { return; } timerQueueTimer.Fire(); }