internal override void Drain() { if (Interlocked.Increment(ref wip) != 1) { return; } var missed = 1; var observers = this.observers; var downstream = this.downstream; var delayErrors = this.delayErrors; var sources = this.queue; for (; ;) { if (Volatile.Read(ref disposed)) { while (observers.TryDequeue(out var inner)) { inner.Dispose(); } while (sources.TryDequeue(out var _)) { ; } } else { if (!delayErrors) { var ex = Volatile.Read(ref errors); if (ex != null) { Volatile.Write(ref disposed, true); downstream.OnError(ex); DisposableHelper.Dispose(ref upstream); continue; } } if (!noMoreSources && active < maxConcurrency && !sources.IsEmpty) { if (sources.TryDequeue(out var v)) { var src = default(ISingleSource <R>); try { src = RequireNonNullRef(mapper(v), "The mapper returned a null ISingleSource"); } catch (Exception ex) { if (delayErrors) { ExceptionHelper.AddException(ref errors, ex); Volatile.Write(ref done, true); } else { Interlocked.CompareExchange(ref errors, ex, null); } noMoreSources = true; DisposableHelper.Dispose(ref upstream); continue; } active++; SubscribeTo(src); continue; } } var d = Volatile.Read(ref done) && sources.IsEmpty; var empty = !observers.TryPeek(out var inner); if (d && empty) { Volatile.Write(ref disposed, true); var ex = Volatile.Read(ref errors); if (ex != null) { downstream.OnError(ex); } else { downstream.OnCompleted(); } DisposableHelper.Dispose(ref upstream); } else if (!empty) { var state = inner.GetState(); if (state == 1) { downstream.OnNext(inner.value); observers.TryDequeue(out var _); active--; continue; } else if (state == 2) { observers.TryDequeue(out var _); active--; continue; } } } missed = Interlocked.Add(ref wip, -missed); if (missed == 0) { break; } } }
internal override void Drain() { if (Interlocked.Increment(ref wip) != 1) { return; } var missed = 1; var observers = this.observers; var downstream = this.downstream; var delayErrors = this.delayErrors; var sources = this.sources; for (; ;) { if (Volatile.Read(ref disposed)) { while (observers.TryDequeue(out var inner)) { inner.Dispose(); } if (sources != null) { this.sources = null; sources.Dispose(); } } else { if (!delayErrors) { var ex = Volatile.Read(ref errors); if (ex != null) { Volatile.Write(ref disposed, true); downstream.OnError(ex); continue; } } if (active < maxConcurrency && !done) { var src = default(IMaybeSource <T>); try { if (sources.MoveNext()) { src = sources.Current; } else { done = true; } } catch (Exception ex) { done = true; sources.Dispose(); this.sources = null; if (delayErrors) { ExceptionHelper.AddException(ref errors, ex); } else { Interlocked.CompareExchange(ref errors, ex, null); } continue; } if (!done) { active++; SubscribeTo(src); continue; } else { sources.Dispose(); this.sources = null; } } var d = done; var empty = !observers.TryPeek(out var inner); if (d && empty) { Volatile.Write(ref disposed, true); var ex = Volatile.Read(ref errors); if (ex != null) { downstream.OnError(ex); } else { downstream.OnCompleted(); } } else if (!empty) { var state = inner.GetState(); if (state == 1) { downstream.OnNext(inner.value); observers.TryDequeue(out var _); active--; continue; } else if (state == 2) { observers.TryDequeue(out var _); active--; continue; } } } missed = Interlocked.Add(ref wip, -missed); if (missed == 0) { break; } } }
protected override void Drain() { if (Interlocked.Increment(ref wip) != 1) { return; } var missed = 1; var q = queue; var maxConcurrency = this.maxConcurrency; for (; ;) { if (Volatile.Read(ref disposed)) { while (q.TryDequeue(out var _)) { ; } } else { if (!delayErrors) { var ex = Volatile.Read(ref errors); if (ex != null) { downstream.OnError(ex); base.Dispose(); continue; } } if (mapperCrash) { while (q.TryDequeue(out var _)) { ; } } else if (Volatile.Read(ref active) < maxConcurrency && !q.IsEmpty) { if (q.TryDequeue(out var v)) { var c = default(ICompletableSource); try { c = RequireNonNullRef(mapper(v), "The mapper returned a null ICompletableSource"); } catch (Exception ex) { mapperCrash = true; if (delayErrors) { ExceptionHelper.AddException(ref errors, ex); } else { Interlocked.CompareExchange(ref errors, ex, null); } done = true; DisposableHelper.Dispose(ref upstream); continue; } var inner = new InnerObserver(this); if (Add(inner)) { Interlocked.Increment(ref active); c.Subscribe(inner); } continue; } } var d = done; var a = Volatile.Read(ref active); var empty = a == 0 && q.IsEmpty; if (d && empty) { var ex = Volatile.Read(ref errors); if (ex != null) { downstream.OnError(ex); } else { downstream.OnCompleted(); } base.Dispose(); } } missed = Interlocked.Add(ref wip, -missed); if (missed == 0) { break; } } }
internal void Drain() { if (Interlocked.Increment(ref wip) != 1) { return; } var missed = 1; var observers = this.observers; var n = observers.Length; var downstream = this.downstream; var delayErrors = this.delayErrors; var hasValues = this.hasValues; for (; ;) { for (; ;) { if (Volatile.Read(ref disposed)) { Array.Clear(values, 0, values.Length); break; } if (!delayErrors) { var ex = Volatile.Read(ref error); if (ex != null) { downstream.OnError(ex); DisposeAll(); continue; } } int ready = 0; bool done = false; for (int i = 0; i < n; i++) { if (hasValues[i]) { ready++; } else { var inner = Volatile.Read(ref observers[i]); if (inner != null) { var d = inner.IsDone(); var q = Volatile.Read(ref inner.queue); var v = default(T); var success = false; try { if (q != null) { v = q.TryPoll(out success); } } catch (Exception ex) { if (delayErrors) { inner.Dispose(); ExceptionHelper.AddException(ref error, ex); inner.SetDone(); d = true; } else { Interlocked.CompareExchange(ref error, ex, null); ex = Volatile.Read(ref error); downstream.OnError(ex); DisposeAll(); continue; } } if (d && !success) { done = true; break; } if (success) { hasValues[i] = true; values[i] = v; ready++; } } } } if (done) { var ex = Volatile.Read(ref error); if (ex != null) { downstream.OnError(ex); } else { downstream.OnCompleted(); } DisposeAll(); continue; } if (ready == n) { var vals = values; values = new T[n]; Array.Clear(hasValues, 0, hasValues.Length); var result = default(R); try { result = mapper(vals); } catch (Exception ex) { if (delayErrors) { ExceptionHelper.AddException(ref error, ex); ex = ExceptionHelper.Terminate(ref error); downstream.OnError(ex); DisposeAll(); } else { if (Interlocked.CompareExchange(ref error, ex, null) == null) { downstream.OnError(ex); DisposeAll(); } } continue; } downstream.OnNext(result); } else { break; } } missed = Interlocked.Add(ref wip, -missed); if (missed == 0) { break; } } }