Exemple #1
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;
                    }
                }
            }
Exemple #2
0
            void DrainLoop()
            {
                var missed      = 1;
                var delayErrors = this.delayErrors;
                var downstream  = this.downstream;


                for (; ;)
                {
                    for (; ;)
                    {
                        var a = Volatile.Read(ref active);

                        if (a == DISPOSED)
                        {
                            break;
                        }

                        if (!delayErrors)
                        {
                            var ex = Volatile.Read(ref errors);
                            if (ex != null)
                            {
                                downstream.OnError(ex);
                                Dispose();
                                break;
                            }
                        }

                        bool d = Volatile.Read(ref done);

                        if (d && a == null)
                        {
                            var ex = ExceptionHelper.Terminate(ref errors);
                            if (ex == null)
                            {
                                downstream.OnCompleted();
                            }
                            else
                            {
                                downstream.OnError(ex);
                            }
                            Dispose();
                            break;
                        }

                        if (a == null)
                        {
                            break;
                        }

                        var innerDone = a.IsDone();
                        var q         = a.GetQueue();
                        var v         = default(R);
                        var empty     = true;

                        if (q != null)
                        {
                            v     = q.TryPoll(out var success);
                            empty = !success;
                        }

                        if (innerDone && empty)
                        {
                            Interlocked.CompareExchange(ref active, null, a);
                        }
                        else
                        if (empty)
                        {
                            break;
                        }
                        else
                        {
                            downstream.OnNext(v);
                        }
                    }

                    missed = Interlocked.Add(ref wip, -missed);
                    if (missed == 0)
                    {
                        break;
                    }
                }
            }
            internal void Drain()
            {
                if (Interlocked.Increment(ref wip) == 1)
                {
                    var q           = queue;
                    var delayErrors = this.delayErrors;


                    for (; ;)
                    {
                        if (disposed)
                        {
                            while (q.TryDequeue(out var _))
                            {
                                ;
                            }
                        }
                        else
                        {
                            if (!active)
                            {
                                var d = Volatile.Read(ref done);
                                if (d && !delayErrors)
                                {
                                    var ex = Volatile.Read(ref errors);
                                    if (ex != null)
                                    {
                                        downstream.OnError(ex);
                                        disposed = true;
                                        continue;
                                    }
                                }

                                bool empty = !q.TryDequeue(out var v);

                                if (d && empty)
                                {
                                    var ex = ExceptionHelper.Terminate(ref errors);
                                    if (ex != null)
                                    {
                                        downstream.OnError(ex);
                                    }
                                    else
                                    {
                                        downstream.OnCompleted();
                                    }
                                    disposed = true;
                                    continue;
                                }

                                if (!empty)
                                {
                                    var c = default(ICompletableSource);

                                    try
                                    {
                                        c = RequireNonNullRef(mapper(v), "The mapper returned a null ICompletableSource");
                                    }
                                    catch (Exception ex)
                                    {
                                        DisposableHelper.Dispose(ref upstream);

                                        ExceptionHelper.AddException(ref errors, ex);
                                        ex = ExceptionHelper.Terminate(ref errors);

                                        downstream.OnError(ex);

                                        disposed = true;
                                        continue;
                                    }

                                    active = true;
                                    c.Subscribe(inner);
                                }
                            }
                        }

                        if (Interlocked.Decrement(ref wip) == 0)
                        {
                            break;
                        }
                    }
                }
            }