/// <inheritdoc/>
 public void Request(long n)
 {
     if (SubscriptionHelper.Validate(n))
     {
         if (Interlocked.CompareExchange(ref state, REQUESTED, READY) == READY)
         {
             actual.OnNext(value);
             if (Volatile.Read(ref state) != CANCELLED)
             {
                 actual.OnComplete();
             }
         }
     }
 }
示例#2
0
        /// <summary>
        /// Atomically set the next ISubscription on this arbiter.
        /// </summary>
        /// <param name="s">The new ISubscription instance.</param>
        public void Set(ISubscription s)
        {
            if (Volatile.Read(ref wip) == 0 && Interlocked.CompareExchange(ref wip, 1, 0) == 0)
            {
                var  c = current;
                long r = requested;

                if (SubscriptionHelper.IsCancelled(c))
                {
                    s?.Cancel();

                    if (Interlocked.Decrement(ref wip) == 0)
                    {
                        return;
                    }
                }
                else
                {
                    c?.Cancel();

                    current = s;

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

                    if (r != 0L)
                    {
                        s?.Request(r);
                    }
                }
            }
            else
            {
                ISubscription c = Interlocked.Exchange(ref missedSubscription, s);
                c?.Cancel();
                if (Interlocked.Increment(ref wip) != 1)
                {
                    return;
                }
                Drain();
            }
        }
示例#3
0
        /// <inheritdoc/>
        public void Request(long n)
        {
            if (!SubscriptionHelper.Validate(n))
            {
                return;
            }
            for (;;)
            {
                int s = Volatile.Read(ref state);
                if (s == CANCELLED || s == HAS_REQUEST_NO_VALUE || s == HAS_REQUEST_HAS_VALUE)
                {
                    return;
                }
                if (s == NO_REQUEST_HAS_VALUE)
                {
                    if (Interlocked.CompareExchange(ref state, HAS_REQUEST_HAS_VALUE, NO_REQUEST_HAS_VALUE) == NO_REQUEST_HAS_VALUE)
                    {
                        T v = value;

                        if (fusionState == EMPTY)
                        {
                            fusionState = HAS_VALUE;
                        }

                        actual.OnNext(v);

                        if (Volatile.Read(ref state) != CANCELLED)
                        {
                            actual.OnComplete();
                        }

                        return;
                    }
                    return;
                }
                if (Interlocked.CompareExchange(ref state, HAS_REQUEST_NO_VALUE, NO_REQUEST_NO_VALUE) == NO_REQUEST_NO_VALUE)
                {
                    break;
                }
            }
        }
示例#4
0
        void Drain()
        {
            long          requestAmount = 0L;
            ISubscription requestTarget = null;

            int missed = 1;

            for (;;)
            {
                long mRequested = Volatile.Read(ref missedRequested);

                if (mRequested != 0L)
                {
                    mRequested = Interlocked.Exchange(ref missedRequested, 0L);
                }

                long mProduced = Volatile.Read(ref missedProduced);
                if (mProduced != 0L)
                {
                    mProduced = Interlocked.Exchange(ref missedProduced, 0L);
                }

                long r = requested;

                if (r != long.MaxValue)
                {
                    long u = BackpressureHelper.AddCap(r, mRequested);

                    if (u != long.MaxValue)
                    {
                        long v = u - mProduced;

                        if (v < 0L)
                        {
                            ExceptionHelper.OnErrorDropped(new InvalidOperationException("More produced than requested: " + v));
                            v = 0L;
                        }

                        requested = v;
                        r         = v;
                    }
                    else
                    {
                        requested = u;
                        r         = u;
                    }
                }


                ISubscription mSubscription = Volatile.Read(ref missedSubscription);
                if (mSubscription != null)
                {
                    mSubscription = Interlocked.Exchange(ref missedSubscription, null);
                }

                var c = current;

                if (SubscriptionHelper.IsCancelled(c))
                {
                    mSubscription?.Cancel();
                }
                else
                {
                    if (mSubscription != null)
                    {
                        current?.Cancel();

                        current = mSubscription;

                        if (r != 0L)
                        {
                            requestAmount = BackpressureHelper.AddCap(requestAmount, r);
                            requestTarget = mSubscription;
                        }
                    }
                    else
                    if (mRequested != 0)
                    {
                        requestAmount = BackpressureHelper.AddCap(requestAmount, mRequested);
                        requestTarget = current;
                    }
                }

                missed = QueueDrainHelper.Leave(ref wip, missed);
                if (missed == 0)
                {
                    if (requestAmount != 0L)
                    {
                        requestTarget?.Request(requestAmount);
                    }
                    break;
                }
            }
        }