public void InnerNext(InnerSignalObserver <R> sender, R item) { if (Interlocked.CompareExchange(ref wip, 1, 0) == 0) { var q = sender.GetQueue(); if (current == sender && (q == null || q.IsEmpty())) { downstream.OnNext(item); } else { if (q == null) { q = sender.CreateQueue(capacityHint); } q.TryOffer(item); } if (Interlocked.Decrement(ref wip) == 0) { return; } } else { var q = sender.GetOrCreateQueue(capacityHint); q.TryOffer(item); if (Interlocked.Increment(ref wip) != 1) { return; } } DrainLoop(); }
public void UpstreamNext(T value) { if (IsDisposed()) { return; } var o = default(IObservableSource <R>); try { o = ValidationHelper.RequireNonNullRef(mapper(value), "The mapper returned a null IObservableSource"); } catch (Exception ex) { base.Dispose(); OnError(ex); return; } var inner = new InnerSignalObserver <R>(this); observers.Offer(inner); if (!IsDisposed()) { o.Subscribe(inner); } Drain(); }
void Remove(InnerSignalObserver <R> inner) { for (; ;) { var a = Volatile.Read(ref observers); var n = a.Length; if (n == 0) { break; } var j = Array.IndexOf(a, inner); if (j < 0) { break; } var b = default(InnerSignalObserver <R>[]); if (n == 1) { b = Empty; } else { b = new InnerSignalObserver <R> [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; } } }
public void InnerNext(InnerSignalObserver <R> sender, R item) { if (Interlocked.CompareExchange(ref wip, 1, 0) == 0) { var a = Volatile.Read(ref active); if (a == sender) { downstream.OnNext(item); } if (Interlocked.Decrement(ref wip) == 0) { return; } } else { var a = Volatile.Read(ref active); if (a == sender) { var q = sender.GetOrCreateQueue(capacityHint); q.TryOffer(item); if (Interlocked.Increment(ref wip) != 1) { return; } } } DrainLoop(); }
public void InnerError(InnerSignalObserver <R> sender, Exception error) { if (Interlocked.CompareExchange(ref this.error, error, null) == null) { sender.SetDone(); Volatile.Write(ref done, true); Drain(); } }
public void InnerComplete(InnerSignalObserver <R> sender) { sender.Dispose(); if (Volatile.Read(ref active) == sender) { sender.SetDone(); Drain(); } }
public void InnerError(InnerSignalObserver <R> sender, Exception ex) { if (delayErrors) { ExceptionHelper.AddException(ref errors, ex); } else { Interlocked.CompareExchange(ref errors, ex, null); } sender.SetDone(); Drain(); }
public void OnNext(T item) { if (done) { return; } var q = sourceQueue; if (q == null) { var src = default(IObservableSource <R>); try { src = ValidationHelper.RequireNonNullRef(mapper(item), "The mapper returned a null IObservableSource"); } catch (Exception ex) { upstream.Dispose(); OnError(ex); return; } if (src is IDynamicValue <R> d) { TryEmitScalar(d); } else { var inner = new InnerSignalObserver <R>(this); if (Add(inner)) { src.Subscribe(inner); } } } else { q.TryOffer(item); Drain(); } }
bool Add(InnerSignalObserver <R> inner) { for (; ;) { var a = Volatile.Read(ref observers); if (a == Terminated) { return(false); } var n = a.Length; var b = new InnerSignalObserver <R> [n + 1]; Array.Copy(a, 0, b, 0, n); b[n] = inner; if (Interlocked.CompareExchange(ref observers, b, a) == a) { return(true); } } }
public void InnerError(InnerSignalObserver <R> sender, Exception error) { sender.Dispose(); if (Volatile.Read(ref active) == sender) { if (delayErrors) { ExceptionHelper.AddException(ref errors, error); sender.SetDone(); Drain(); } else { if (Interlocked.CompareExchange(ref errors, error, null) == null) { sender.SetDone(); Drain(); } } } }
public override void OnNext(T value) { if (done) { return; } var o = default(IObservableSource <R>); try { o = ValidationHelper.RequireNonNullRef(mapper(value), "The mapper returned a null IObservableSource"); } catch (Exception ex) { OnError(ex); return; } var inner = new InnerSignalObserver <R>(this); for (; ;) { var a = Volatile.Read(ref active); if (a == DISPOSED) { break; } if (Interlocked.CompareExchange(ref active, inner, a) == a) { a?.Dispose(); o.Subscribe(inner); break; } } }
void DrainLoop() { int missed = 1; var observers = this.observers; for (; ;) { if (Volatile.Read(ref disposed)) { if (current != null) { current.Dispose(); current = null; } for (; ;) { var inner = observers.TryPoll(out var success); if (!success) { break; } inner.Dispose(); } Cleanup(); } else { var curr = current; if (curr == null) { var d = Volatile.Read(ref done); if (d) { var ex = Volatile.Read(ref error); if (ex != null) { downstream.OnError(ex); Volatile.Write(ref disposed, true); base.Dispose(); continue; } } curr = observers.TryPoll(out var success); var empty = !success; if (d && empty) { downstream.OnCompleted(); Volatile.Write(ref disposed, true); base.Dispose(); } current = curr; } if (curr != null) { var continueOuter = false; for (; ;) { if (Volatile.Read(ref disposed)) { continueOuter = true; break; } var d = curr.IsDone(); var q = curr.GetQueue(); var v = default(R); var success = false; if (q != null) { try { v = q.TryPoll(out success); } catch (Exception ex) { Interlocked.CompareExchange(ref this.error, ex, null); Volatile.Write(ref disposed, true); continueOuter = true; break; } } if (d && !success) { curr.Dispose(); current = null; curr = null; InnerConsumed(); continueOuter = true; break; } if (!success) { break; } downstream.OnNext(v); } if (continueOuter) { continue; } } } missed = Interlocked.Add(ref wip, -missed); if (missed == 0) { break; } } }
public void InnerComplete(InnerSignalObserver <R> sender) { sender.SetDone(); Drain(); }
void DrainLoop() { var missed = 1; var downstream = this.downstream; var delayErrors = this.delayErrors; var maxConcurrency = this.maxConcurrency; for (; ;) { if (Volatile.Read(ref disposed)) { Volatile.Read(ref scalarQueue)?.Clear(); sourceQueue?.Clear(); } else { if (!delayErrors) { var ex = Volatile.Read(ref errors); if (ex != null) { downstream.OnError(ex); Volatile.Write(ref disposed, true); upstream.Dispose(); DisposeAll(); continue; } } var d = Volatile.Read(ref done); var sq = Volatile.Read(ref scalarQueue); if (sq != null) { var v = sq.TryPoll(out var success); if (success) { downstream.OnNext(v); continue; } } var obs = Volatile.Read(ref observers); var n = obs.Length; var srcs = sourceQueue; if (srcs != null) { if (!noMoreSources && n < maxConcurrency && !srcs.IsEmpty()) { var v = srcs.TryPoll(out var success); var src = default(IObservableSource <R>); try { src = ValidationHelper.RequireNonNullRef(mapper(v), "The mapper returned a null IObservableSource"); } catch (Exception ex) { upstream.Dispose(); if (delayErrors) { ExceptionHelper.AddException(ref errors, ex); } else { Interlocked.CompareExchange(ref errors, ex, null); } success = false; noMoreSources = true; srcs?.Clear(); continue; } if (success) { if (src is IDynamicValue <R> dv) { var w = default(R); var s = false; try { w = dv.GetValue(out s); } catch (Exception ex) { if (delayErrors) { ExceptionHelper.AddException(ref errors, ex); } else { Interlocked.CompareExchange(ref errors, ex, null); } continue; } if (s) { downstream.OnNext(w); } continue; } else { var inner = new InnerSignalObserver <R>(this); if (Add(inner)) { src.Subscribe(inner); continue; } } } } } if (d && n == 0 && (sq == null || sq.IsEmpty()) && (noMoreSources || srcs == null || srcs.IsEmpty())) { var ex = Volatile.Read(ref errors); if (ex != null) { downstream.OnError(ex); } else { downstream.OnCompleted(); } Volatile.Write(ref disposed, true); } else if (n != 0) { var continueOuter = false; var removed = false; for (int j = 0; j < n; j++) { var inner = obs[j]; for (; ;) { if (Volatile.Read(ref disposed)) { continueOuter = true; break; } if (!delayErrors && Volatile.Read(ref errors) != null) { continueOuter = true; break; } var innerDone = inner.IsDone(); var innerQueue = inner.GetQueue(); if (innerDone && (innerQueue == null || innerQueue.IsEmpty())) { Remove(inner); removed = true; break; } else if (innerQueue != null) { if (innerQueue.IsEmpty()) { break; } var v = default(R); var succ = false; try { v = innerQueue.TryPoll(out succ); } catch (Exception ex) { inner.Dispose(); inner.SetDone(); Remove(inner); if (delayErrors) { ExceptionHelper.AddException(ref errors, ex); } else { Interlocked.CompareExchange(ref errors, ex, null); } removed = true; break; } if (succ) { downstream.OnNext(v); } else { break; } } else { break; } } if (continueOuter) { break; } } if (continueOuter || removed) { continue; } } } missed = Interlocked.Add(ref wip, -missed); if (missed == 0) { break; } } }