internal ChannelSendAwaiter <T> SendAsync(T value, IUniqueOportunity oportunity) { Action afterLock = null; _rwl.EnterWriteLock(); try { if (_closing) { throw new InvalidOperationException("channel is closed"); } while (_activeReceivers.Count > 0) { var receiver = _activeReceivers.First.Value; _activeReceivers.RemoveFirst(); if (receiver.LockForSelection()) { if (oportunity.TryAcquire()) { afterLock = () => receiver.Receive(value); oportunity.Release(false); receiver.ConfirmSelection(); return(ChannelSendAwaiter <T> .Done()); } else { receiver.CancelSelection(); _activeReceivers.AddFirst(receiver); return(ChannelSendAwaiter <T> .Never()); } } } if (_buffer != null && _bufferedCount < _buffer.Length) { if (oportunity.TryAcquire()) { oportunity.Release(false); _buffer[(_bufferHead + _bufferedCount++) % _buffer.Length] = value; return(ChannelSendAwaiter <T> .Done()); } else { return(ChannelSendAwaiter <T> .Never()); } } // cleanup var current = _activeSenders.First; while (current != null) { var old = current; current = old.Next; if (!old.Value.IsStillListening()) { _activeSenders.Remove(old); } } var waiter = ChannelSendAwaiter <T> .Waiting(value, oportunity); _activeSenders.AddLast(waiter); return(waiter); } finally { _rwl.ExitWriteLock(); afterLock?.Invoke(); } }
private void ReceiveAsyncInternal(ref ChannelReceiveAwaiter <T> result, ref Func <ChannelReceiveAwaiter <T> > indirectResult, IUniqueOportunity oportunity) { if (_buffer != null && _bufferedCount > 0) { if (oportunity.TryAcquire()) { oportunity.Release(false); result = ChannelReceiveAwaiter <T> .Done(_buffer[_bufferHead]); _buffer[_bufferHead] = default(T); _bufferHead = (_bufferHead + 1) % _buffer.Length; --_bufferedCount; if (_closing && _bufferedCount == 0 && _activeSenders.Count == 0) { _closed = true; } return; } else { result = ChannelReceiveAwaiter <T> .Never(); } } while (_activeSenders.Count > 0) { var sender = _activeSenders.First.Value; _activeSenders.RemoveFirst(); if (sender.LockForSelection()) { if (oportunity.TryAcquire()) { sender.ConfirmSelection(); oportunity.Release(false); indirectResult = () => ChannelReceiveAwaiter <T> .Done(sender.Consume()); if (_closing && _bufferedCount == 0 && _activeSenders.Count == 0) { _closed = true; } return; } else { sender.CancelSelection(); _activeSenders.AddFirst(sender); result = ChannelReceiveAwaiter <T> .Never(); return; } } } if (_closed) { if (oportunity.TryAcquire()) { oportunity.Release(false); result = ChannelReceiveAwaiter <T> .Done(default(T)); return; } else { result = ChannelReceiveAwaiter <T> .Never(); return; } } // cleanup var current = _activeReceivers.First; while (current != null) { var old = current; current = old.Next; if (!old.Value.IsStillListening()) { _activeReceivers.Remove(old); } } var waiter = ChannelReceiveAwaiter <T> .Waiting(oportunity); _activeReceivers.AddLast(waiter); result = waiter; }
internal void CancelSelection() { _uniqueOportunity?.Release(true); }