Exemple #1
0
            public override ValueTask <T> ReadAsync(CancellationToken cancellationToken)
            {
                if (cancellationToken.IsCancellationRequested)
                {
                    return(new ValueTask <T>(Task.FromCanceled <T>(cancellationToken)));
                }

                BoundedChannel <T> parent = _parent;

                lock (parent.SyncObj)
                {
                    parent.AssertInvariants();

                    // If there are any items, hand one back.
                    if (!parent._items.IsEmpty)
                    {
                        return(new ValueTask <T>(DequeueItemAndPostProcess()));
                    }

                    // There weren't any items.  If we're done writing so that there
                    // will never be more items, fail.
                    if (parent._doneWriting != null)
                    {
                        return(ChannelUtilities.GetInvalidCompletionValueTask <T>(parent._doneWriting));
                    }

                    // Otherwise, queue the reader.
                    var reader = ReaderInteractor <T> .Create(parent._runContinuationsAsynchronously, cancellationToken);

                    parent._blockedReaders.EnqueueTail(reader);
                    return(new ValueTask <T>(reader.Task));
                }
            }
Exemple #2
0
            public override ValueTask <T> ReadAsync(CancellationToken cancellationToken)
            {
                if (cancellationToken.IsCancellationRequested)
                {
                    return(new ValueTask <T>(Task.FromCanceled <T>(cancellationToken)));
                }

                if (TryRead(out T item))
                {
                    return(new ValueTask <T>(item));
                }

                SingleConsumerUnboundedChannel <T> parent = _parent;

                AsyncOperation <T> oldBlockedReader, newBlockedReader;

                lock (parent.SyncObj)
                {
                    // Now that we hold the lock, try reading again.
                    if (TryRead(out item))
                    {
                        return(new ValueTask <T>(item));
                    }

                    // If no more items will be written, fail the read.
                    if (parent._doneWriting != null)
                    {
                        return(ChannelUtilities.GetInvalidCompletionValueTask <T>(parent._doneWriting));
                    }

                    // Try to use the singleton reader.  If it's currently being used, then the channel
                    // is being used erroneously, and we cancel the outstanding operation.
                    oldBlockedReader = parent._blockedReader;
                    if (!cancellationToken.CanBeCanceled && _readerSingleton.TryOwnAndReset())
                    {
                        newBlockedReader = _readerSingleton;
                        if (newBlockedReader == oldBlockedReader)
                        {
                            // The previous operation completed, so null out the "old" reader
                            // so we don't end up canceling the new operation.
                            oldBlockedReader = null;
                        }
                    }
                    else
                    {
                        newBlockedReader = new AsyncOperation <T>(_parent._runContinuationsAsynchronously, cancellationToken);
                    }
                    parent._blockedReader = newBlockedReader;
                }

                oldBlockedReader?.TrySetCanceled();
                return(newBlockedReader.ValueTaskOfT);
            }
            public override ValueTask <T> ReadAsync(CancellationToken cancellationToken)
            {
                if (cancellationToken.IsCancellationRequested)
                {
                    return(new ValueTask <T>(Task.FromCanceled <T>(cancellationToken)));
                }

                // Dequeue an item if we can.
                UnboundedChannel <T> parent = _parent;

                if (parent._items.TryDequeue(out T item))
                {
                    CompleteIfDone(parent);
                    return(new ValueTask <T>(item));
                }

                lock (parent.SyncObj)
                {
                    parent.AssertInvariants();

                    // Try to dequeue again, now that we hold the lock.
                    if (parent._items.TryDequeue(out item))
                    {
                        CompleteIfDone(parent);
                        return(new ValueTask <T>(item));
                    }

                    // There are no items, so if we're done writing, fail.
                    if (parent._doneWriting != null)
                    {
                        return(ChannelUtilities.GetInvalidCompletionValueTask <T>(parent._doneWriting));
                    }

                    // If we're able to use the singleton reader, do so.
                    if (!cancellationToken.CanBeCanceled)
                    {
                        AsyncOperation <T> singleton = _readerSingleton;
                        if (singleton.TryOwnAndReset())
                        {
                            parent._blockedReaders.EnqueueTail(singleton);
                            return(singleton.ValueTaskOfT);
                        }
                    }

                    // Otherwise, create and queue a reader.
                    var reader = new AsyncOperation <T>(parent._runContinuationsAsynchronously, cancellationToken);
                    parent._blockedReaders.EnqueueTail(reader);
                    return(reader.ValueTaskOfT);
                }
            }
Exemple #4
0
            public override ValueTask <T> ReadAsync(CancellationToken cancellationToken)
            {
                if (cancellationToken.IsCancellationRequested)
                {
                    return(new ValueTask <T>(Task.FromCanceled <T>(cancellationToken)));
                }

                BoundedChannel <T> parent = _parent;

                lock (parent.SyncObj)
                {
                    parent.AssertInvariants();

                    // If there are any items, hand one back.
                    if (!parent._items.IsEmpty)
                    {
                        return(new ValueTask <T>(DequeueItemAndPostProcess()));
                    }

                    // There weren't any items.  If we're done writing so that there
                    // will never be more items, fail.
                    if (parent._doneWriting != null)
                    {
                        return(ChannelUtilities.GetInvalidCompletionValueTask <T>(parent._doneWriting));
                    }

                    // If we're able to use the singleton reader, do so.
                    if (!cancellationToken.CanBeCanceled)
                    {
                        AsyncOperation <T> singleton = _readerSingleton;
                        if (singleton.TryOwnAndReset())
                        {
                            parent._blockedReaders.EnqueueTail(singleton);
                            return(singleton.ValueTaskOfT);
                        }
                    }

                    // Otherwise, queue a reader.  Note that in addition to checking whether synchronous continuations were requested,
                    // we also check whether the supplied cancellation token can be canceled.  The writer calls UnregisterCancellation
                    // while holding the lock, and if a callback needs to be unregistered and is currently running, it needs to wait
                    // for that callback to complete so that the subsequent code knows it won't be contending with another thread
                    // trying to complete the operation.  However, if we allowed a synchronous continuation from this operation, that
                    // cancellation callback could end up running arbitrary code, including code that called back into the reader or
                    // writer and tried to take the same lock held by the thread running UnregisterCancellation... deadlock.  As such,
                    // we only allow synchronous continuations here if both a) the caller requested it and the token isn't cancelable.
                    var reader = new AsyncOperation <T>(parent._runContinuationsAsynchronously | cancellationToken.CanBeCanceled, cancellationToken);
                    parent._blockedReaders.EnqueueTail(reader);
                    return(reader.ValueTaskOfT);
                }
            }
            private ValueTask <T> ReadAsyncCore(CancellationToken cancellationToken)
            {
                if (cancellationToken.IsCancellationRequested)
                {
                    return(new ValueTask <T>(Task.FromCanceled <T>(cancellationToken)));
                }

                UnboundedChannel <T> parent = _parent;

                lock (parent.SyncObj)
                {
                    parent.AssertInvariants();

                    // If there are any items, return one.
                    if (parent._items.TryDequeue(out T item))
                    {
                        // Dequeue an item
                        if (parent._doneWriting != null && parent._items.IsEmpty)
                        {
                            // If we've now emptied the items queue and we're not getting any more, complete.
                            ChannelUtilities.Complete(parent._completion, parent._doneWriting);
                        }

                        return(new ValueTask <T>(item));
                    }

                    // There are no items, so if we're done writing, fail.
                    if (parent._doneWriting != null)
                    {
                        return(ChannelUtilities.GetInvalidCompletionValueTask <T>(parent._doneWriting));
                    }

                    // If we're able to use the singleton reader, do so.
                    if (!cancellationToken.CanBeCanceled)
                    {
                        AsyncOperation <T> singleton = _readerSingleton;
                        if (singleton.TryOwnAndReset())
                        {
                            parent._blockedReaders.EnqueueTail(singleton);
                            return(singleton.ValueTaskOfT);
                        }
                    }

                    // Otherwise, create and queue a reader.
                    var reader = new AsyncOperation <T>(parent._runContinuationsAsynchronously, cancellationToken);
                    parent._blockedReaders.EnqueueTail(reader);
                    return(reader.ValueTaskOfT);
                }
            }
Exemple #6
0
            public override ValueTask <T> ReadAsync(CancellationToken cancellationToken)
            {
                if (cancellationToken.IsCancellationRequested)
                {
                    return(new ValueTask <T>(Task.FromCanceled <T>(cancellationToken)));
                }

                BoundedChannel <T> parent = _parent;

                lock (parent.SyncObj)
                {
                    parent.AssertInvariants();

                    // If there are any items, hand one back.
                    if (!parent._items.IsEmpty)
                    {
                        return(new ValueTask <T>(DequeueItemAndPostProcess()));
                    }

                    // There weren't any items.  If we're done writing so that there
                    // will never be more items, fail.
                    if (parent._doneWriting != null)
                    {
                        return(ChannelUtilities.GetInvalidCompletionValueTask <T>(parent._doneWriting));
                    }

                    // If we're able to use the singleton reader, do so.
                    if (!cancellationToken.CanBeCanceled)
                    {
                        AsyncOperation <T> singleton = _readerSingleton;
                        if (singleton.TryOwnAndReset())
                        {
                            parent._blockedReaders.EnqueueTail(singleton);
                            return(singleton.ValueTaskOfT);
                        }
                    }

                    // Otherwise, queue the reader.
                    var reader = new AsyncOperation <T>(parent._runContinuationsAsynchronously, cancellationToken);
                    parent._blockedReaders.EnqueueTail(reader);
                    return(reader.ValueTaskOfT);
                }
            }
            public override ValueTask <T> ReadAsync(CancellationToken cancellationToken)
            {
                {
                    return(TryRead(out T item) ?
                           new ValueTask <T>(item) :
                           ReadAsyncCore(cancellationToken));
                }

                ValueTask <T> ReadAsyncCore(CancellationToken ct)
                {
                    SingleConsumerUnboundedChannel <T> parent = _parent;

                    if (ct.IsCancellationRequested)
                    {
                        return(new ValueTask <T>(Task.FromCanceled <T>(ct)));
                    }

                    lock (parent.SyncObj)
                    {
                        // Now that we hold the lock, try reading again.
                        if (TryRead(out T item))
                        {
                            return(new ValueTask <T>(item));
                        }

                        // If no more items will be written, fail the read.
                        if (parent._doneWriting != null)
                        {
                            return(ChannelUtilities.GetInvalidCompletionValueTask <T>(parent._doneWriting));
                        }

                        Debug.Assert(parent._blockedReader == null || parent._blockedReader.Task.IsCanceled,
                                     "Incorrect usage; multiple outstanding reads were issued against this single-consumer channel");

                        // Store the reader to be completed by a writer.
                        var reader = ReaderInteractor <T> .Create(parent._runContinuationsAsynchronously, ct);

                        parent._blockedReader = reader;
                        return(new ValueTask <T>(reader.Task));
                    }
                }
            }
            private ValueTask <T> ReadAsyncCore(CancellationToken cancellationToken)
            {
                if (cancellationToken.IsCancellationRequested)
                {
                    return(new ValueTask <T>(Task.FromCanceled <T>(cancellationToken)));
                }

                UnboundedChannel <T> parent = _parent;

                lock (parent.SyncObj)
                {
                    parent.AssertInvariants();

                    // If there are any items, return one.
                    if (parent._items.TryDequeue(out T item))
                    {
                        // Dequeue an item
                        if (parent._doneWriting != null && parent._items.IsEmpty)
                        {
                            // If we've now emptied the items queue and we're not getting any more, complete.
                            ChannelUtilities.Complete(parent._completion, parent._doneWriting);
                        }

                        return(new ValueTask <T>(item));
                    }

                    // There are no items, so if we're done writing, fail.
                    if (parent._doneWriting != null)
                    {
                        return(ChannelUtilities.GetInvalidCompletionValueTask <T>(parent._doneWriting));
                    }

                    // Otherwise, queue the reader.
                    var reader = ReaderInteractor <T> .Create(parent._runContinuationsAsynchronously, cancellationToken);

                    parent._blockedReaders.EnqueueTail(reader);
                    return(new ValueTask <T>(reader.Task));
                }
            }