public IDisposable Subscribe(IObserver <T> observer) { var ccd = new CacheConsumerDisposable(observer, this, head); Add(ccd); if (Volatile.Read(ref once) == 0 && Interlocked.CompareExchange(ref once, 1, 0) == 0) { var d = source.Subscribe(this); DisposableHelper.SetOnce(ref upstream, d); cancel?.Invoke(this); } Drain(ccd); return(ccd); }
void Remove(CacheConsumerDisposable ccd) { for (; ;) { var a = Volatile.Read(ref observers); var n = a.Length; if (n == 0) { break; } var j = -1; for (int i = 0; i < n; i++) { if (a[i] == ccd) { j = i; break; } } if (j < 0) { break; } var b = default(CacheConsumerDisposable[]); if (n == 1) { b = EMPTY; } else { b = new CacheConsumerDisposable[n - 1]; Array.Copy(a, 0, b, 0, j); Array.Copy(a, j + 1, b, j, n - j - 1); } if (Interlocked.CompareExchange(ref observers, b, a) == a) { break; } } }
bool Add(CacheConsumerDisposable ccd) { for (; ;) { var a = Volatile.Read(ref observers); if (a == TERMINATED) { return(false); } var n = a.Length; var b = new CacheConsumerDisposable[n + 1]; Array.Copy(a, 0, b, 0, n); b[n] = ccd; if (Interlocked.CompareExchange(ref observers, b, a) == a) { return(true); } } }
public void Subscribe(ISignalObserver <T> observer) { var ccd = new CacheConsumerDisposable(observer, this, head); observer.OnSubscribe(ccd); Add(ccd); if (ccd.IsDisposed()) { Remove(ccd); return; } if (Volatile.Read(ref once) == 0 && Interlocked.CompareExchange(ref once, 1, 0) == 0) { cancel?.Invoke(this); source.Subscribe(this); } Drain(ccd); }
void Drain(CacheConsumerDisposable ccd) { if (Interlocked.Increment(ref ccd.wip) != 1) { return; } var missed = 1; var downstream = ccd.downstream; for (; ;) { var i = ccd.index; var n = ccd.node; var o = ccd.offset; if (n != null) { var a = n.items; var cap = a.Length; for (; ;) { if (ccd.IsDisposed()) { n = null; break; } var ex = Volatile.Read(ref terminated); var s = Volatile.Read(ref size); bool empty = i == s; if (ex != null && empty) { if (ex == ExceptionHelper.TERMINATED) { downstream.OnCompleted(); } else { downstream.OnError(ex); } n = null; break; } if (empty) { break; } if (o == cap) { var b = n.next; n = b; a = b.items; o = 0; } var v = a[o]; downstream.OnNext(v); i++; o++; } ccd.index = i; ccd.node = n; ccd.offset = o; } missed = Interlocked.Add(ref ccd.wip, -missed); if (missed == 0) { break; } } }