public void DeleteTimer(TimerQueueTimer timer) { if (timer.m_dueTime != Timeout.UnsignedInfinite) { if (timer.m_next != null) timer.m_next.m_prev = timer.m_prev; if (timer.m_prev != null) timer.m_prev.m_next = timer.m_next; if (m_timers == timer) m_timers = timer.m_next; timer.m_dueTime = Timeout.UnsignedInfinite; timer.m_period = Timeout.UnsignedInfinite; timer.m_startTicks = 0; timer.m_prev = null; timer.m_next = null; } }
public TimerHolder(TimerQueueTimer timer) { m_timer = timer; }
private static void QueueTimerCompletion(TimerQueueTimer timer) { WaitCallback callback = s_fireQueuedTimerCompletion; if (callback == null) s_fireQueuedTimerCompletion = callback = new WaitCallback(FireQueuedTimerCompletion); // Can use "unsafe" variant because we take care of capturing and restoring // the ExecutionContext. ThreadPool.UnsafeQueueUserWorkItem(callback, timer); }
public bool UpdateTimer(TimerQueueTimer timer, uint dueTime, uint period) { if (timer.m_dueTime == Timeout.UnsignedInfinite) { // the timer is not in the list; add it (as the head of the list). timer.m_next = m_timers; timer.m_prev = null; if (timer.m_next != null) timer.m_next.m_prev = timer; m_timers = timer; } timer.m_dueTime = dueTime; timer.m_period = (period == 0) ? Timeout.UnsignedInfinite : period; timer.m_startTicks = TickCount; return EnsureAppDomainTimerFiresBy(dueTime); }
internal void Resume() { // // Update timers to adjust their due-time to accomodate Pause/Resume // lock (this) { // prevent ThreadAbort while updating state try { } finally { int pauseTicks = m_pauseTicks; m_pauseTicks = 0; // Set this to 0 so that now timers can be scheduled int resumedTicks = TickCount; int pauseDuration = resumedTicks - pauseTicks; bool haveTimerToSchedule = false; uint nextAppDomainTimerDuration = uint.MaxValue; TimerQueueTimer timer = m_timers; while (timer != null) { Contract.Assert(timer.m_dueTime != Timeout.UnsignedInfinite); Contract.Assert(resumedTicks >= timer.m_startTicks); uint elapsed; // How much of the timer dueTime has already elapsed // Timers started before the paused event has to be sufficiently delayed to accomodate // for the Pause time. However, timers started after the Paused event shouldnt be adjusted. // E.g. ones created by the app in its Activated event should fire when it was designated. // The Resumed event which is where this routine is executing is after this Activated and hence // shouldn't delay this timer if (timer.m_startTicks <= pauseTicks) { elapsed = (uint)(pauseTicks - timer.m_startTicks); } else { elapsed = (uint)(resumedTicks - timer.m_startTicks); } // Handling the corner cases where a Timer was already due by the time Resume is happening, // We shouldn't delay those timers. // Example is a timer started in App's Activated event with a very small duration timer.m_dueTime = (timer.m_dueTime > elapsed) ? timer.m_dueTime - elapsed : 0;; timer.m_startTicks = resumedTicks; // re-baseline if (timer.m_dueTime < nextAppDomainTimerDuration) { haveTimerToSchedule = true; nextAppDomainTimerDuration = timer.m_dueTime; } timer = timer.m_next; } if (haveTimerToSchedule) { EnsureAppDomainTimerFiresBy(nextAppDomainTimerDuration); } } } }
public bool InitModel() { //try //{ // // *********************************************** // // set up generic UDP socket and bind to local port // // *********************************************** // _dataSocket = new UdpClient((int)_localPort); //} //catch (Exception ex) //{ // Debug.Write(ex.ToString()); // return false; //} // this delegate is needed for the multi media timer defined // in the TimerQueueTimer class. _ballTimerCallbackDelegate = new TimerQueueTimer.WaitOrTimerDelegate(BallMMTimerCallback); // create our multi-media timers _ballHiResTimer = new TimerQueueTimer(); try { // create a Multi Media Hi Res timer. _ballHiResTimer.Create(10, 10, _ballTimerCallbackDelegate); } catch (QueueTimerException ex) { Console.WriteLine(ex.ToString()); Console.WriteLine("Failed to create Ball timer. Error from GetLastError = {0}", ex.Error); } _paddleTimerCallbackDelegate = new TimerQueueTimer.WaitOrTimerDelegate(paddleMMTimerCallback); _paddleHiResTimer = new TimerQueueTimer(); try { // create a Multi Media Hi Res timer. _paddleHiResTimer.Create(10, 8, _paddleTimerCallbackDelegate); } catch (QueueTimerException ex) { Console.WriteLine(ex.ToString()); Console.WriteLine("Failed to create paddle timer. Error from GetLastError = {0}", ex.Error); } // reset help text //HelpText = ""; ThreadStart threadFunction; threadFunction = new ThreadStart(SynchWithOtherPlayer); _syncWithOtherPlayerThread = new Thread(threadFunction); return true; }
private void LinkTimer(TimerQueueTimer timer) { // Use timer._short to decide to which list to add. ref TimerQueueTimer?listHead = ref timer._short ? ref _shortTimers : ref _longTimers;
private static void CallCallbackInContext(object state) { TimerQueueTimer t = (TimerQueueTimer)state; t._timerCallback(t._state); }
// // 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(); _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 = _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; 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(); } }
// 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 appdomain timer has fired. m_isAppDomainTimerScheduled = false; bool haveTimerToSchedule = false; uint nextAppDomainTimerDuration = uint.MaxValue; int nowTicks = TickCount; // 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 = m_shortTimers; for (int listNum = 0; listNum < 2; listNum++) // short == 0, long == 1 { while (timer != null) { Debug.Assert(timer.m_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.m_next; uint elapsed = (uint)(nowTicks - timer.m_startTicks); int remaining = (int)timer.m_dueTime - (int)elapsed; if (remaining <= 0) { // Timer is ready to fire. if (timer.m_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.m_startTicks = nowTicks; uint elapsedForNextDueTime = elapsed - timer.m_dueTime; timer.m_dueTime = (elapsedForNextDueTime < timer.m_period) ? timer.m_period - elapsedForNextDueTime : 1; // Update the appdomain timer if this becomes the next timer to fire. if (timer.m_dueTime < nextAppDomainTimerDuration) { haveTimerToSchedule = true; nextAppDomainTimerDuration = timer.m_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.m_dueTime) - m_currentAbsoluteThreshold <= 0; if (timer.m_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.UnsafeQueueCustomWorkItem(timer, forceGlobal: true); } } 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 < nextAppDomainTimerDuration) { haveTimerToSchedule = true; nextAppDomainTimerDuration = (uint)remaining; } if (!timer.m_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 appdomain 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). int remaining = m_currentAbsoluteThreshold - nowTicks; if (remaining > 0) { if (m_shortTimers == null && m_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 nextAppDomainTimerDuration. // But we do know that nothing in the long list will be firing before or at m_currentAbsoluteThreshold, // so we can just set nextAppDomainTimerDuration to the difference between then and now. nextAppDomainTimerDuration = (uint)remaining + 1; haveTimerToSchedule = true; } break; } // Switch to processing the long list. timer = m_longTimers; // Now that we're going to process the long list, update the current threshold. m_currentAbsoluteThreshold = nowTicks + ShortTimersThresholdMilliseconds; } } // If we still have scheduled timers, update the appdomain timer to ensure it fires // in time for the next one in line. if (haveTimerToSchedule) { EnsureAppDomainTimerFiresBy(nextAppDomainTimerDuration); } } // Fire the user timer outside of the lock! timerToFireOnThisThread?.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. // 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 static void QueueTimerCompletion(TimerQueueTimer timer) { // Can use "unsafe" variant because we take care of capturing and restoring the ExecutionContext. ThreadPool.UnsafeQueueCustomWorkItem(timer, forceGlobal: true); }