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;
                    }
                }
            }
Esempio n. 2
0
            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;
                    }
                }
            }
Esempio n. 4
0
            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;
                    }
                }
            }