void OnNext(PublisherMergeInner inner, R value) { if (bp.TryEnter()) { long r = bp.Requested(); if (r != 0L) { actual.OnNext(value); if (r != long.MaxValue) { bp.Produced(1); } inner.Request(1); } else { inner.Enqueue(value); } if (bp.Leave()) { return; } } else { inner.Enqueue(value); if (!bp.Enter()) { return; } } DrainLoop(); }
void DrainLoop() { ISubscriber <R> a = actual; int missed = 1; for (;;) { bool d = IsDone(); PublisherMergeInner[] inners = Volatile.Read(ref subscribers); int n = inners.Length; bool empty = n == 0 && q.IsEmpty(); if (CheckTerminated(d, empty, a)) { return; } long r = bp.Requested(); long e = 0L; if (r != 0L) { if (q.IsConsumable()) { while (e != r) { d = IsDone(); R t; empty = !q.Poll(out t); if (CheckTerminated(d, empty, a)) { return; } if (empty) { break; } a.OnNext(t); e++; } if (e != 0L) { r = bp.Produced(e); s.Request(e); e = 0L; } } d = IsDone(); inners = Volatile.Read(ref subscribers); n = inners.Length; empty = n == 0 && q.IsEmpty(); if (CheckTerminated(d, empty, a)) { return; } } int idx = lastIndex; if (idx >= n) { idx = 0; } for (int i = 0; i < n; i++) { PublisherMergeInner inner = inners[idx]; d = inner.IsDone(); empty = inner.IsEmpty(); if (d && empty) { Remove(inner); s.Request(1); inners = Volatile.Read(ref subscribers); n = inners.Length; idx--; } else if (r != e && !empty) { while (e != r) { d = inner.IsDone(); R t; empty = !inner.Poll(out t); if (d && empty) { Remove(inner); s.Request(1); inners = Volatile.Read(ref subscribers); n = inners.Length; idx--; break; } else if (empty) { break; } a.OnNext(t); e++; } d = inner.IsDone(); empty = inner.IsEmpty(); if (e == r && d && empty) { Remove(inner); s.Request(1); inners = Volatile.Read(ref subscribers); n = inners.Length; idx--; } if (e != 0L) { r = bp.Produced(e); if (!d) { inner.Request((int)e); } e = 0L; } } idx++; if (idx >= n) { idx = 0; } } d = IsDone(); inners = Volatile.Read(ref subscribers); n = inners.Length; empty = n == 0 && q.IsEmpty(); if (CheckTerminated(d, empty, a)) { return; } lastIndex = idx; missed = bp.Leave(missed); if (missed == 0) { break; } } }