/// <summary> /// Expire all HashedWheelTimeout for the given deadline. /// </summary> /// <param name="deadline"></param> internal void ExpireTimeouts(long deadline) { HashedWheelTimeout timeout = _head; // process all timeouts while (timeout != null) { HashedWheelTimeout next = timeout._next; if (timeout._remainingRounds <= 0) { next = Remove(timeout); if (timeout._deadline <= deadline) { timeout.Expire(); } else { // The timeout was placed into a wrong slot. This should never happen. throw new InvalidOperationException($"timeout.deadline ({timeout._deadline}) > deadline ({deadline})"); } } else if (timeout.Cancelled) { next = Remove(timeout); } else { timeout._remainingRounds--; } timeout = next; } }
private HashedWheelTimeout PollTimeout() { var head = _head; if (head == null) { return(null); } var next = head.Next; if (next == null) { _tail = _head = null; } else { _head = next; next.Prev = null; } // null out prev and next to allow for GC. head.Next = null; head.Prev = null; head.Bucket = null; return(head); }
private HashedWheelTimeout PollTimeout() { HashedWheelTimeout head = this._head; if (head == null) { return(null); } HashedWheelTimeout next = head._next; if (next == null) { _tail = this._head = null; } else { this._head = next; next._prev = null; } // null out prev and next to allow for GC. head._next = null; head._prev = null; head._bucket = null; return(head); }
public void AddTimeout(HashedWheelTimeout timeout) { timeout.Bucket = this; if (_head == null) { _head = _tail = timeout; } else { _tail.Next = timeout; timeout.Prev = _tail; _tail = timeout; } }
internal void ClearTimeouts(ISet <Timeout> set) { for (; ;) { HashedWheelTimeout timeout = PollTimeout(); if (timeout == null) { return; } if (timeout.Expired || timeout.Cancelled) { continue; } set.Add(timeout); } }
public HashedWheelTimeout Remove(HashedWheelTimeout timeout) { var next = timeout.Next; // remove timeout that was either processed or cancelled by updating the linked-list if (timeout.Prev != null) { timeout.Prev.Next = next; } if (timeout.Next != null) { timeout.Next.Prev = timeout.Prev; } if (timeout == _head) { // if timeout is also the tail we need to adjust the entry too if (timeout == _tail) { _tail = null; _head = null; } else { _head = next; } } else if (timeout == _tail) { // if the timeout is the tail modify the tail to be the prev node. _tail = timeout.Prev; } // null out prev, next and bucket to allow for GC. timeout.Prev = null; timeout.Next = null; timeout.Bucket = null; timeout.DecrementPendingTimeouts(); return(next); }
/// <summary> /// Schedules the specified TimerTask for one-time execution after the specified delay. /// </summary> /// <param name="task"></param> /// <param name="span"></param> /// <returns>a handle which is associated with the specified task</returns> public ITimeout NewTimeout(ITimerTask task, TimeSpan span) { if (task == null) { throw new ArgumentNullException(nameof(task)); } if (_cancellationTokenSource != default && _cancellationTokenSource.Token.IsCancellationRequested) { throw new InvalidOperationException("cannot be started once stopped"); } var pendingTimeoutsCount = _pendingTimeouts.IncrementAndGet(); if (_maxPendingTimeouts > 0 && pendingTimeoutsCount > _maxPendingTimeouts) { _pendingTimeouts.DecrementAndGet(); throw new InvalidOperationException( $"Number of pending timeouts ({pendingTimeoutsCount}) is greater than or equal to maximum allowed pending timeouts ({_maxPendingTimeouts})"); } Start(); // Add the timeout to the timeout queue which will be processed on the next tick. // During processing all the queued HashedWheelTimeouts will be added to the correct HashedWheelBucket. var deadline = DateTimeHelper.TotalMilliseconds + (long)span.TotalMilliseconds - StartTime; // Guard against overflow. if (span.Milliseconds > 0 && deadline < 0) { deadline = long.MaxValue; } var timeout = new HashedWheelTimeout(this, task, deadline); _timeouts.Enqueue(timeout); return(timeout); }
/// <summary> /// Schedules the specified TimerTask for one-time execution after the specified delay. /// </summary> /// <param name="task"></param> /// <param name="span"></param> /// <returns>a handle which is associated with the specified task</returns> public Timeout NewTimeout(TimerTask task, TimeSpan span) { if (task == null) { throw new ArgumentNullException(nameof(task)); } if (_workerState == WORKER_STATE_SHUTDOWN) { return(null); } long pendingTimeoutsCount = Interlocked.Increment(ref _pendingTimeouts); if (_maxPendingTimeouts > 0 && pendingTimeoutsCount > _maxPendingTimeouts) { Interlocked.Decrement(ref _pendingTimeouts); throw new InvalidOperationException($"Number of pending timeouts ({pendingTimeoutsCount}) is greater than or equal to maximum allowed pending timeouts ({_maxPendingTimeouts})"); } Start(); // Add the timeout to the timeout queue which will be processed on the next tick. // During processing all the queued HashedWheelTimeouts will be added to the correct HashedWheelBucket. long deadline = GetCurrentMs() + (long)span.TotalMilliseconds - _startTime; // Guard against overflow. if (span.TotalMilliseconds > 0 && deadline < 0) { deadline = long.MaxValue; } HashedWheelTimeout timeout = new HashedWheelTimeout(this, task, deadline); _timeouts.Enqueue(timeout); return(timeout); }
internal void EnqueueCanceledTimeout(HashedWheelTimeout timeout) { _cancelledTimeouts.Enqueue(timeout); }