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