/// <summary> /// Called by the timer thread to fire the expired timers. Returns true if there are future timers /// in the queue, and if so, also sets nextExpiration. /// </summary> /// <param name="nextExpiration">The next expiration.</param> /// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns> public bool Fire(out int nextExpiration) { while (true) { // Check if we got to the end. If so, free the handle. CountdownTimerNode timer = _timers.Next; if (timer == _timers) { lock (_timers) { timer = _timers.Next; if (timer == _timers) { if (_thisHandle != IntPtr.Zero) { ((GCHandle)_thisHandle).Free(); _thisHandle = IntPtr.Zero; } nextExpiration = 0; return(false); } } } if (!timer.Fire()) { nextExpiration = timer.Expiration; return(true); } } }
/// <summary> /// Create a new TimerQueue. TimerQueues must be created while s_NewQueues is locked in /// order to synchronize with Shutdown(). /// </summary> /// <param name="durationMilliseconds">The duration milliseconds.</param> public CountdownTimerQueue(int durationMilliseconds) : base(durationMilliseconds) { // Create the doubly-linked list with a sentinel head and tail so that this member never needs updating. _timers = new CountdownTimerNode(); _timers.Next = _timers; _timers.Prev = _timers; }
/// <summary> /// Creates new timers. This method is thread-safe. /// </summary> /// <param name="callback">The callback.</param> /// <param name="context">The context.</param> /// <returns><see cref="CancellationTimer" />Timer.</returns> public override CancellationTimer CreateTimer(Callback callback, object context) { var timer = new CountdownTimerNode(callback, context, this.Duration, this._countdownTimerNode); // Add this on the tail. (Actually, one before the tail - _timers is the sentinel tail.) var needProd = false; lock (this._countdownTimerNode) { // If this is the first timer in the list, we need to create a queue handle and prod the timer thread. if (this._countdownTimerNode.Next == this._countdownTimerNode) { if (this._thisHandle == IntPtr.Zero) { this._thisHandle = (IntPtr)GCHandle.Alloc(this); } needProd = true; } timer.Next = this._countdownTimerNode; timer.Prev = this._countdownTimerNode.Prev; this._countdownTimerNode.Prev.Next = timer; this._countdownTimerNode.Prev = timer; } // If, after we add the new tail, there is a chance that the tail is the next // node to be processed, we need to wake up the timer thread. if (needProd) { CountdownTimer.Prod(); } return(timer); }
/// <summary> /// Creates new timers. This method is thread-safe. /// </summary> /// <param name="callback">The callback.</param> /// <param name="context">The context.</param> /// <returns>CountdownTimerTimer.</returns> public override CancelationTimer CreateTimer(Callback callback, object context) { var timer = new CountdownTimerNode(callback, context, Duration, _timers); // Add this on the tail. (Actually, one before the tail - _timers is the sentinel tail.) var needProd = false; lock (_timers) { //if (!(_timers.Prev!.Next == _timers)) //{ // NetEventSource.Fail(this, $"Tail corruption."); //} // If this is the first timer in the list, we need to create a queue handle and prod the timer thread. if (_timers.Next == _timers) { if (_thisHandle == IntPtr.Zero) { _thisHandle = (IntPtr)GCHandle.Alloc(this); } needProd = true; } timer.Next = _timers; timer.Prev = _timers.Prev; _timers.Prev.Next = timer; _timers.Prev = timer; } // If, after we add the new tail, there is a chance that the tail is the next // node to be processed, we need to wake up the timer thread. if (needProd) { CountdownTimer.Prod(); } return(timer); }