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