/// <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(); } } } }
/// <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(); } }
/// <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; } } }
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; } } }