Beispiel #1
0
        public void Dispose()
        {
            lock (SyncObject)
            {
                if (_disposed)
                {
                    return;
                }

                _disposed = true;

                CreditWaiter waiter = _waitersTail;
                if (waiter != null)
                {
                    do
                    {
                        CreditWaiter next = waiter.Next;
                        waiter.Next = null;
                        waiter.Dispose();
                        waiter = next;
                    }while (waiter != _waitersTail);

                    _waitersTail = null;
                }
            }
        }
Beispiel #2
0
        public ValueTask <int> RequestCreditAsync(int amount, CancellationToken cancellationToken)
        {
            lock (SyncObject)
            {
                if (_disposed)
                {
                    throw new ObjectDisposedException($"{nameof(CreditManager)}:{_owner.GetType().Name}:{_name}");
                }

                // If we can satisfy the request with credit already available, do so synchronously.
                if (_current > 0)
                {
                    Debug.Assert(_waitersTail is null, "Shouldn't have waiters when credit is available");

                    int granted = Math.Min(amount, _current);
                    if (NetEventSource.IsEnabled)
                    {
                        _owner.Trace($"{_name}. requested={amount}, current={_current}, granted={granted}");
                    }
                    _current -= granted;
                    return(new ValueTask <int>(granted));
                }

                if (NetEventSource.IsEnabled)
                {
                    _owner.Trace($"{_name}. requested={amount}, no credit available.");
                }

                // Otherwise, create a new waiter.
                CreditWaiter waiter = cancellationToken.CanBeCanceled ?
                                      new CancelableCreditWaiter(SyncObject, cancellationToken) :
                                      new CreditWaiter();
                waiter.Amount = amount;

                // Add the waiter at the tail of the queue.
                if (_waitersTail is null)
                {
                    _waitersTail = waiter.Next = waiter;
                }
                else
                {
                    waiter.Next       = _waitersTail.Next;
                    _waitersTail.Next = waiter;
                    _waitersTail      = waiter;
                }

                // And return a ValueTask<int> for it.
                return(waiter.AsValueTask());
            }
        }
Beispiel #3
0
        public void AdjustCredit(int amount)
        {
            // Note credit can be adjusted *downward* as well.
            // This can cause the current credit to become negative.

            lock (SyncObject)
            {
                if (NetEventSource.IsEnabled)
                {
                    _owner.Trace($"{_name}. {nameof(amount)}={amount}, current={_current}");
                }

                if (_disposed)
                {
                    return;
                }

                Debug.Assert(_current <= 0 || _waitersTail is null, "Shouldn't have waiters when credit is available");

                _current = checked (_current + amount);

                while (_current > 0 && _waitersTail != null)
                {
                    // Get the waiter from the head of the queue.
                    CreditWaiter waiter  = _waitersTail.Next;
                    int          granted = Math.Min(waiter.Amount, _current);

                    // Remove the waiter from the list.
                    if (waiter.Next == waiter)
                    {
                        Debug.Assert(_waitersTail == waiter);
                        _waitersTail = null;
                    }
                    else
                    {
                        _waitersTail.Next = waiter.Next;
                    }
                    waiter.Next = null;

                    // Ensure that we grant credit only if the task has not been canceled.
                    if (waiter.TrySetResult(granted))
                    {
                        _current -= granted;
                    }

                    waiter.Dispose();
                }
            }
        }
Beispiel #4
0
        public ValueTask <int> RequestCreditAsync(int amount, CancellationToken cancellationToken)
        {
            lock (SyncObject)
            {
                // If we can satisfy the request with credit already available, do so synchronously.
                int granted = TryRequestCreditNoLock(amount);

                if (granted > 0)
                {
                    return(new ValueTask <int>(granted));
                }

                if (NetEventSource.Log.IsEnabled())
                {
                    _owner.Trace($"{_name}. requested={amount}, no credit available.");
                }

                // Otherwise, create a new waiter.
                CreditWaiter waiter = cancellationToken.CanBeCanceled ?
                                      new CancelableCreditWaiter(SyncObject, cancellationToken) :
                                      new CreditWaiter();
                waiter.Amount = amount;

                // Add the waiter at the tail of the queue.
                if (_waitersTail is null)
                {
                    _waitersTail = waiter.Next = waiter;
                }
                else
                {
                    waiter.Next       = _waitersTail.Next;
                    _waitersTail.Next = waiter;
                    _waitersTail      = waiter;
                }

                // And return a ValueTask<int> for it.
                return(waiter.AsValueTask());
            }
        }