public void InnerComplete(InnerObserver <R> sender)
 {
     sender.Dispose();
     if (Volatile.Read(ref active) == sender)
     {
         sender.SetDone();
         Drain();
     }
 }
Пример #2
0
 protected void Remove(InnerObserver inner)
 {
     if (Volatile.Read(ref disposed))
     {
         return;
     }
     lock (this)
     {
         if (Volatile.Read(ref disposed))
         {
             return;
         }
         disposables.Remove(inner);
     }
     inner.Dispose();
 }
 public void InnerError(InnerObserver <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();
             }
         }
     }
 }
            void DrainLoop()
            {
                int missed    = 1;
                var observers = this.observers;

                for (; ;)
                {
                    if (Volatile.Read(ref disposed))
                    {
                        if (current != null)
                        {
                            current.Dispose();
                            current = null;
                        }

                        while (observers.TryPoll(out var inner))
                        {
                            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;
                                }
                            }

                            var empty = !observers.TryPoll(out curr);

                            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 empty = q == null || !q.TryPoll(out v);

                                if (d && empty)
                                {
                                    curr.Dispose();
                                    current = null;
                                    curr    = null;
                                    InnerConsumed();
                                    continueOuter = true;
                                    break;
                                }

                                if (empty)
                                {
                                    break;
                                }

                                downstream.OnNext(v);
                            }

                            if (continueOuter)
                            {
                                continue;
                            }
                        }
                    }

                    missed = Interlocked.Add(ref wip, -missed);
                    if (missed == 0)
                    {
                        break;
                    }
                }
            }