Example #1
0
        /// <summary>Wake up all of the waiters and null out the field.</summary>
        /// <param name="waiters">The waiters.</param>
        /// <param name="result">The success value with which to complete each waiter if <paramref name="error">error</paramref> is null.</param>
        /// <param name="error">The failure with which to cmplete each waiter, if non-null.</param>
        internal static void WakeUpWaiters(ref ReaderInteractor <bool> waiters, bool result, Exception error = null)
        {
            ReaderInteractor <bool> w = waiters;

            if (w != null)
            {
                if (error != null)
                {
                    w.Fail(error);
                }
                else
                {
                    w.Success(result);
                }
                waiters = null;
            }
        }
        private bool TryComplete(Exception error = null)
        {
            object blockedReader = null;
            ReaderInteractor <bool> waitingReader = null;
            bool completeTask = false;

            lock (SyncObj)
            {
                // If we're already marked as complete, there's nothing more to do.
                if (_doneWriting != null)
                {
                    return(false);
                }

                // Mark as complete for writing.
                _doneWriting = error ?? ChannelUtilities.DoneWritingSentinel;

                // If we have no more items remaining, then the channel needs to be marked as completed
                // and readers need to be informed they'll never get another item.  All of that needs
                // to happen outside of the lock to avoid invoking continuations under the lock.
                if (_items.IsEmpty)
                {
                    completeTask = true;

                    if (_blockedReader != null)
                    {
                        blockedReader  = _blockedReader;
                        _blockedReader = null;
                    }

                    if (_waitingReader != null)
                    {
                        waitingReader  = _waitingReader;
                        _waitingReader = null;
                    }
                }
            }

            // Complete the channel task if necessary
            if (completeTask)
            {
                ChannelUtilities.Complete(_completion, error);
            }

            Debug.Assert(blockedReader == null || waitingReader == null, "There should only ever be at most one reader.");

            // Complete a blocked reader if necessary
            if (blockedReader != null)
            {
                error = ChannelUtilities.CreateInvalidCompletionException(error);

                ReaderInteractor <T> interactor = blockedReader as ReaderInteractor <T>;
                if (interactor != null)
                {
                    interactor.Fail(error);
                }
                else
                {
                    ((AutoResetAwaiter <T>)blockedReader).SetException(error);
                }
            }

            // Complete a waiting reader if necessary.  (We really shouldn't have both a blockedReader
            // and a waitingReader, but it's more expensive to prevent it than to just tolerate it.)
            if (waitingReader != null)
            {
                if (error != null)
                {
                    waitingReader.Fail(error);
                }
                else
                {
                    waitingReader.Success(false);
                }
            }

            // Successfully completed the channel
            return(true);
        }