Beispiel #1
0
        /// Internal implementation detail.
        internal override void DoJob(ref Worker wr, Cont <T> aK)
        {
Spin:
            var state = this.State;

            if (state > Empty)
            {
                goto GotValue;
            }
            if (state < Empty)
            {
                goto Spin;
            }
            if (Empty != Interlocked.CompareExchange(ref this.State, Locked, Empty))
            {
                goto Spin;
            }

            WaitQueue.AddTaker(ref this.Takers, aK);
            this.State = Empty;
            return;

GotValue:
            aK.DoCont(ref wr, this.Value);
            return;
        }
Beispiel #2
0
            internal override void DoJob(ref Worker wr, Cont <Y> yK)
            {
                var tM = this.tM;

Spin:
                var state = tM.State;

                if (state == MVar.Locked)
                {
                    goto Spin;
                }
                if (state != Interlocked.CompareExchange(ref tM.State, MVar.Locked, state))
                {
                    goto Spin;
                }

                if (state <= MVar.Empty)
                {
                    goto EmptyOrDemand;
                }

                var t = tM.Value;

                tM.State = MVar.Empty;

                MVarTryModifyFunCont <T, Y> .Do(this, yK, ref wr, t);

                return;

EmptyOrDemand:
                WaitQueue.AddTaker(ref tM.Takers, new MVarTryModifyFunCont <T, Y>(this, yK));
                tM.State = MVar.Demand;
            }
Beispiel #3
0
    internal override void TryAlt(ref Worker wr, int i, Cont<Unit> uK, Else aE) {
      var pkSelf = aE.pk;
    Spin:
      if (0 == this.Count) goto TryPick;
      var state = this.State;
      if (state < 0) goto Spin;
      if (Interlocked.Exchange(ref this.State, ~state) < state) goto Spin;

      if (0 == this.Count) goto UnlockAndTryPick;
      
      WaitQueue.AddTaker(ref this.Awaiters, i, pkSelf, uK);
      this.State = 0;
      aE.TryElse(ref wr, i + 1);
      return;

    UnlockAndTryPick:
      this.State = 0;
    TryPick:
      var st = Pick.TryPick(pkSelf);
      if (st > 0) goto AlreadyPicked;
      if (st < 0) goto TryPick;

      Pick.SetNacks(ref wr, i, pkSelf);

      Work.Do(uK, ref wr);
    AlreadyPicked:
      return;
    }
Beispiel #4
0
        // Note that via selective communication it is possible for a job to offer
        // to both give and take on the same channel simultaneously.  So, both
        // Givers and Takers queues must be maintained even though in many cases
        // only one of them is non empty.

        internal override void DoJob(ref Worker wr, Cont <T> xK)
        {
TryNextGiver:
            this.Lock.Enter();
            var tail = this.Givers;

            if (null != tail)
            {
                goto TryGiver;
            }
            WaitQueue.AddTaker(ref this.Takers, xK);
            this.Lock.Exit();
            return;

TryGiver:
            var cursor = tail.Next;

            if (tail == cursor)
            {
                this.Givers = null;
            }
            else
            {
                tail.Next = cursor.Next;
            }
            this.Lock.Exit();

            var giver = cursor as Giver <T>;

            if (null == giver)
            {
                goto GotSend;
            }

            var pkOther = giver.Pick;

            if (null == pkOther)
            {
                goto GotGiver;
            }

TryPickOther:
            var stOther = Pick.TryPick(pkOther);

            if (stOther > 0)
            {
                goto TryNextGiver;
            }
            if (stOther < 0)
            {
                goto TryPickOther;
            }

            Pick.SetNacks(ref wr, giver.Me, pkOther);
GotGiver:
            Worker.Push(ref wr, giver.Cont);
GotSend:
            Cont.Do(xK, ref wr, cursor.Value);
            return;
        }
Beispiel #5
0
        internal override void DoJob(ref Worker wr, Cont <Unit> uK)
        {
Spin:
            var state = this.State;

            if (state > Running)
            {
                goto Terminated;
            }
            if (state < Running)
            {
                goto Spin;
            }
            if (state != Interlocked.CompareExchange(ref this.State, Locked, state))
            {
                goto Spin;
            }

            WaitQueue.AddTaker(ref this.Joiners, uK);
            this.State = Running;
            return;

Terminated:
            Work.Do(uK, ref wr);
        }
Beispiel #6
0
        internal override void DoJob(ref Worker wr, Cont <Unit> uK)
        {
Spin:
            if (0 == this.Count)
            {
                goto Done;
            }
            var state = this.State;

            if (state < 0)
            {
                goto Spin;
            }
            if (Interlocked.Exchange(ref this.State, ~state) < state)
            {
                goto Spin;
            }

            if (0 == this.Count)
            {
                goto UnlockAndDone;
            }

            WaitQueue.AddTaker(ref this.Awaiters, uK);
            this.State = 0;
            return;

UnlockAndDone:
            this.State = 0;
Done:
            Work.Do(uK, ref wr);
        }
Beispiel #7
0
            internal override void DoJob(ref Worker wr, Cont <T> tK)
            {
                var tM = this.tM;

Spin:
                var state = tM.State;

                if (state == MVar.Locked)
                {
                    goto Spin;
                }
                if (state != Interlocked.CompareExchange(ref tM.State, MVar.Locked, state))
                {
                    goto Spin;
                }

                if (state <= MVar.Empty)
                {
                    goto EmptyOrDemand;
                }

                var t = tM.Value;

                tM.State = MVar.Full;
                Cont.Do(tK, ref wr, t);
                return;

EmptyOrDemand:
                WaitQueue.AddTaker(ref tM.Takers, new MVarReadCont <T>(tM, tK));
                tM.State = MVar.Demand;
            }
Beispiel #8
0
        internal override void DoJob(ref Worker wr, Cont <T> aK)
        {
Spin:
            var state = this.State;

            if (state == Locked)
            {
                goto Spin;
            }
            if (state != Interlocked.CompareExchange(ref this.State, Locked, state))
            {
                goto Spin;
            }

            if (state <= Empty)
            {
                goto EmptyOrDemand;
            }

            T value = this.Value;

            this.Value = default(T); // Avoid memory leaks.
            this.State = Empty;
            Cont.Do(aK, ref wr, value);
            return;

EmptyOrDemand:
            WaitQueue.AddTaker(ref this.Takers, aK);
            this.State = Demand;
        }
Beispiel #9
0
        internal override void DoJob(ref Worker wr, Cont <T> aK)
        {
Spin:
            var state = this.State;

Reconsider:
            if (state > Running)
            {
                goto Completed;
            }
            if (state < Delayed)
            {
                goto Spin;
            }
            var check = state;

            state = Interlocked.CompareExchange(ref this.State, state - MakeLocked, state);
            if (Delayed == state)
            {
                goto Delayed;
            }
            if (state != check)
            {
                goto Reconsider;
            }

            WaitQueue.AddTaker(ref this.Readers, aK);
            this.State = Running;
            return;

Delayed:
            var readers = this.Readers;

            this.Readers = null;
            this.State   = Running;

            var fulfill = readers as Fulfill;

            fulfill.tP     = this;
            fulfill.reader = aK;
            var tJ = fulfill.tJ;

            fulfill.tJ = null;
            Job.Do(tJ, ref wr, fulfill);
            return;

Completed:
            if (state == HasValue)
            {
                Cont.Do(aK, ref wr, this.Value);
            }
            else
            {
                aK.DoHandle(ref wr, (this.Readers as Fail <T>).exn);
            }
        }
Beispiel #10
0
            internal override void TryAlt(ref Worker wr, int i, Cont <Y> yK, Else tE)
            {
                var tM     = this.tM;
                var pkSelf = tE.pk;

Spin:
                var state = tM.State;

                if (state == MVar.Locked)
                {
                    goto Spin;
                }
                if (state != Interlocked.CompareExchange(ref tM.State, MVar.Locked, state))
                {
                    goto Spin;
                }

                if (state <= MVar.Empty)
                {
                    goto EmptyOrDemand;
                }

TryPick:
                var stSelf = Pick.TryPick(pkSelf);

                if (stSelf > 0)
                {
                    goto AlreadyPicked;
                }
                if (stSelf < 0)
                {
                    goto TryPick;
                }

                Pick.SetNacks(ref wr, i, pkSelf);

                var t = tM.Value;

                tM.State = MVar.Empty;

                MVarTryModifyFunCont <T, Y> .Do(this, yK, ref wr, t);

                return;

AlreadyPicked:
                tM.State = MVar.Full;
                return;

EmptyOrDemand:
                WaitQueue.AddTaker(ref tM.Takers, i, pkSelf, new MVarTryModifyFunCont <T, Y>(this, yK));
                tM.State = MVar.Demand;
                tE.TryElse(ref wr, i + 1);
                return;
            }
Beispiel #11
0
        internal override void TryAlt(ref Worker wr, int i, Cont <T> aK, Else aE)
        {
            var pkSelf = aE.pk;

Spin:
            var state = this.State;

            if (state == Locked)
            {
                goto Spin;
            }
            if (state != Interlocked.CompareExchange(ref this.State, Locked, state))
            {
                goto Spin;
            }

            if (state <= Empty)
            {
                goto EmptyOrDemand;
            }

TryPick:
            var stSelf = Pick.TryPick(pkSelf);

            if (stSelf > 0)
            {
                goto AlreadyPicked;
            }
            if (stSelf < 0)
            {
                goto TryPick;
            }

            Pick.SetNacks(ref wr, i, pkSelf);

            T value = this.Value;

            this.Value = default(T);
            this.State = Empty;
            Cont.Do(aK, ref wr, value);
            return;

AlreadyPicked:
            this.State = Full;
            return;

EmptyOrDemand:
            WaitQueue.AddTaker(ref this.Takers, i, pkSelf, aK);
            this.State = Demand;
            aE.TryElse(ref wr, i + 1);
            return;
        }
Beispiel #12
0
        /// Internal implementation detail.
        internal override void DoJob(ref Worker wr, Cont <T> aK)
        {
Spin:
            var state = this.State;

            if (state < Running)
            {
                goto Completed;
            }
            if (state == Locked)
            {
                goto Spin;
            }
            if (state != Interlocked.CompareExchange(ref this.State, Locked, state))
            {
                goto Spin;
            }

            if (state == Running)
            {
                goto Running;
            }

            var job = this.Readers as Cont;

            var taker = new Taker <T>();

            taker.Cont   = aK;
            taker.Next   = taker;
            this.Readers = taker;

            this.State = Running;

            job.DoWork(ref wr);
            return;

Running:
            WaitQueue.AddTaker(ref this.Readers, aK);
            this.State = Running;
            return;

Completed:
            if (state == Completed)
            {
                aK.DoCont(ref wr, this.Value);
            }
            else
            {
                aK.DoHandle(ref wr, (this.Readers as Fail).exn);
            }
        }
Beispiel #13
0
        /// Internal implementation detail.
        internal override void TryAlt(ref Worker wr, int i, Pick pkSelf, Cont <T> aK)
        {
Spin:
            var state = this.State;

            if (state == Locked)
            {
                goto Spin;
            }
            if (state != Interlocked.CompareExchange(ref this.State, Locked, state))
            {
                goto Spin;
            }

            if (state <= Empty)
            {
                goto EmptyOrDemand;
            }

TryPick:
            var stSelf = Pick.TryPick(pkSelf);

            if (stSelf > 0)
            {
                goto AlreadyPicked;
            }
            if (stSelf < 0)
            {
                goto TryPick;
            }

            T value = this.Value;

            this.Value = default(T);
            this.State = Empty;
            aK.DoCont(ref wr, value);
            return;

AlreadyPicked:
            this.State = Full;
            return;

EmptyOrDemand:
            WaitQueue.AddTaker(ref this.Takers, i, pkSelf, aK);
            this.State = Demand;
            aK.TryNext(ref wr, i + 1, pkSelf);
            return;
        }
Beispiel #14
0
        internal override void TryAlt(ref Worker wr, int i, Cont <Unit> uK, Else uE)
        {
            var pk = uE.pk;

Spin:
            var state = this.State;

            if (state > Running)
            {
                goto TryPick;
            }
            if (state < Running)
            {
                goto Spin;
            }
            if (state != Interlocked.CompareExchange(ref this.State, Locked, state))
            {
                goto Spin;
            }

            WaitQueue.AddTaker(ref this.Joiners, i, pk, uK);
            this.State = Running;
            uE.TryElse(ref wr, i + 1);
            return;

TryPick:
            var st = Pick.TryPick(pk);

            if (st > 0)
            {
                goto AlreadyPicked;
            }
            if (st < 0)
            {
                goto TryPick;
            }

            Pick.SetNacks(ref wr, i, pk);

            Work.Do(uK, ref wr);
AlreadyPicked:
            return;
        }
Beispiel #15
0
        internal override void DoJob(ref Worker wr, Cont <T> aK)
        {
            this.Lock.Enter();

            if (this.Values.Count > 0)
            {
                goto GotValue;
            }

            WaitQueue.AddTaker(ref this.Takers, aK);
            this.Lock.Exit();
            return;

GotValue:
            T value = this.Values.Dequeue();

            this.Lock.Exit();
            Cont.Do(aK, ref wr, value);
            return;
        }
Beispiel #16
0
        /// Internal implementation detail.
        internal override void TryAlt(ref Worker wr, int i, Pick pkSelf, Cont <T> aK)
        {
Spin:
            var state = this.State;

            if (state > Empty)
            {
                goto TryPick;
            }
            if (state < Empty)
            {
                goto Spin;
            }
            if (Empty != Interlocked.CompareExchange(ref this.State, Locked, Empty))
            {
                goto Spin;
            }

            WaitQueue.AddTaker(ref this.Takers, i, pkSelf, aK);
            this.State = Empty;
            aK.TryNext(ref wr, i + 1, pkSelf);
            return;

TryPick:
            var st = Pick.TryPick(pkSelf);

            if (st > 0)
            {
                goto AlreadyPicked;
            }
            if (st < 0)
            {
                goto TryPick;
            }

            Pick.SetNacks(ref wr, i, pkSelf);

            aK.DoCont(ref wr, this.Value);
AlreadyPicked:
            return;
        }
Beispiel #17
0
        internal override void TryAlt(ref Worker wr, int i, Cont <T> aK, Else aE)
        {
            var pkSelf = aE.pk;

            this.Lock.Enter();

            if (this.Values.Count > 0)
            {
                goto GotValue;
            }

            WaitQueue.AddTaker(ref this.Takers, i, pkSelf, aK);
            this.Lock.Exit();
            aE.TryElse(ref wr, i + 1);
            return;

GotValue:
            var stSelf = Pick.TryPick(pkSelf);

            if (stSelf > 0)
            {
                goto AlreadyPicked;
            }
            if (stSelf < 0)
            {
                goto GotValue;
            }

            T value = this.Values.Dequeue();

            this.Lock.Exit();
            Pick.SetNacks(ref wr, i, pkSelf);
            Cont.Do(aK, ref wr, value);
            return;

AlreadyPicked:
            this.Lock.Exit();
            return;
        }
Beispiel #18
0
        /// Internal implementation detail.
        internal override void TryAlt(ref Worker wr, int i, Pick pkSelf, Cont <T> aK)
        {
            this.Lock.Enter();

            if (this.Values.Count > 0)
            {
                goto GotValue;
            }

            WaitQueue.AddTaker(ref this.Takers, i, pkSelf, aK);
            this.Lock.Exit();
            aK.TryNext(ref wr, i + 1, pkSelf);
            return;

GotValue:
            var stSelf = Pick.TryPick(pkSelf);

            if (stSelf > 0)
            {
                goto AlreadyPicked;
            }
            if (stSelf < 0)
            {
                goto GotValue;
            }

            T value = this.Values.Dequeue();

            this.Lock.Exit();
            Pick.SetNacks(ref wr, i, pkSelf);
            aK.DoCont(ref wr, value);
            return;

AlreadyPicked:
            this.Lock.Exit();
            return;
        }
Beispiel #19
0
 internal void UnsafeAddReader(Cont <T> tK)
 {
     WaitQueue.AddTaker(ref this.Readers, tK);
 }
Beispiel #20
0
        internal override void TryAlt(ref Worker wr, int i, Cont <T> aK, Else aE)
        {
Spin:
            var state = this.State;

Reconsider:
            if (state > Running)
            {
                goto Completed;
            }
            if (state < Delayed)
            {
                goto Spin;
            }
            var check = state;

            state = Interlocked.CompareExchange(ref this.State, state - MakeLocked, state);
            if (Delayed == state)
            {
                goto Delayed;
            }
            if (state != check)
            {
                goto Reconsider;
            }

            WaitQueue.AddTaker(ref this.Readers, i, aE.pk, aK);
            this.State = Running;
            aE.TryElse(ref wr, i + 1);
            return;

Delayed:
            var readers = this.Readers;

            this.Readers = null;
            this.State   = Running;

            var fulfill = readers as Fulfill;

            fulfill.reader = aK;
            fulfill.me     = i;
            fulfill.pk     = aE.pk;

            Worker.PushNew(ref wr, fulfill);
            aE.TryElse(ref wr, i + i);
            return;

Completed:
            var pkSelf = aE.pk;

TryPick:
            var stSelf = Pick.TryPick(pkSelf);

            if (stSelf > 0)
            {
                goto AlreadyPicked;
            }
            if (stSelf < 0)
            {
                goto TryPick;
            }

            Pick.SetNacks(ref wr, i, pkSelf);

            if (state == HasValue)
            {
                Cont.Do(aK, ref wr, this.Value);
            }
            else
            {
                aK.DoHandle(ref wr, (this.Readers as Fail <T>).exn);
            }
AlreadyPicked:
            return;
        }
Beispiel #21
0
        internal override void TryAlt(ref Worker wr, int i, Cont <T> aK, Else aE)
        {
            var pkSelf = aE.pk;

Spin:
            var state = this.State;

            if (state > Running)
            {
                goto Completed;
            }
            if (state < Delayed)
            {
                goto Spin;
            }
            if (state != Interlocked.CompareExchange(ref this.State, ~state, state))
            {
                goto Spin;
            }

            if (Delayed == state)
            {
                goto Delayed;
            }

            WaitQueue.AddTaker(ref this.Readers, i, pkSelf, aK);
            this.State = Running;
            aE.TryElse(ref wr, i + 1);
            return;

Delayed:
            var taker = new Taker <T>();

            taker.Cont = aK;
            taker.Me   = i;
            taker.Pick = pkSelf;
            taker.Next = taker;

            var readers = this.Readers;

            this.Readers = taker;
            this.State   = Running;

            var fulfill = readers as Fulfill;
            var tJ      = fulfill.tP;

            fulfill.tP = this;
            Worker.PushNew(ref wr, new JobWork <T>(tJ, fulfill));
            aE.TryElse(ref wr, i + i);
            return;

Completed:
            var stSelf = Pick.TryPick(pkSelf);

            if (stSelf > 0)
            {
                goto AlreadyPicked;
            }
            if (stSelf < 0)
            {
                goto Completed;
            }

            Pick.SetNacks(ref wr, i, pkSelf);

            if (state == HasValue)
            {
                Cont.Do(aK, ref wr, this.Value);
            }
            else
            {
                aK.DoHandle(ref wr, (this.Readers as Fail <T>).exn);
            }
AlreadyPicked:
            return;
        }
Beispiel #22
0
Datei: Ch.cs Projekt: silky/Hopac
        /// Internal implementation detail.
        internal override void TryAlt(ref Worker wr, int i, Pick pkSelf, Cont <T> xK)
        {
            this.Lock.Enter();
            var tail = this.Givers;

            if (null == tail)
            {
                goto TryTaker;
            }
            Giver <T> cache  = null;
            var       cursor = tail.Next;

TryGiver:
            var giver = cursor;

            cursor = cursor.Next;
            var pkOther = giver.Pick;

            if (null == pkOther)
            {
                goto TryPickSelf;
            }
            if (pkOther == pkSelf)
            {
                goto OtherIsSelf;
            }

TryPickOther:
            var stOther = Pick.TryClaim(pkOther);

            if (stOther > 0)
            {
                goto TryNextGiver;
            }
            if (stOther < 0)
            {
                goto TryPickOther;
            }

TryPickSelf:
            var stSelf = Pick.TryPick(pkSelf);

            if (stSelf > 0)
            {
                goto SelfAlreadyPicked;
            }
            if (stSelf < 0)
            {
                goto BackOff;
            }

            //GotGiver:
            WaitQueue.ReplaceRange(ref this.Givers, giver, cache);
            this.Lock.Exit();
            if (null != pkOther)
            {
                Pick.PickClaimed(pkOther);
                Pick.SetNacks(ref wr, giver.Me, pkOther);
            }
            Pick.SetNacks(ref wr, i, pkSelf);
            var uK = giver.Cont;

            uK.Next = null;
            Worker.Push(ref wr, uK);
            xK.DoCont(ref wr, giver.Value);
            return;

BackOff:
            if (null == pkOther)
            {
                goto TryPickSelf;
            }
            Pick.Unclaim(pkOther);
            goto TryPickOther;

OtherIsSelf:
            WaitQueue.Enqueue(ref cache, giver);
            if (giver != tail)
            {
                goto TryGiver;
            }

            this.Givers = cache;
            goto TryTaker;

TryNextGiver:
            if (giver != tail)
            {
                goto TryGiver;
            }

            this.Givers = cache;
TryTaker:
            WaitQueue.AddTaker(ref this.Takers, i, pkSelf, xK);
            this.Lock.Exit();
            xK.TryNext(ref wr, i + 1, pkSelf);
            return;

SelfAlreadyPicked:
            if (null != pkOther)
            {
                Pick.Unclaim(pkOther);
            }

            WaitQueue.ReplaceRangeInclusive(this.Givers, giver, cache);
            this.Lock.Exit();
            return;
        }
Beispiel #23
0
        internal override void TryAlt(ref Worker wr, int i, Cont <T> xK, Else xE)
        {
            var pkSelf = xE.pk;

            this.Lock.Enter();
            var tail = this.Givers;

            if (null == tail)
            {
                goto TryTaker;
            }
            Send <T> cache  = null;
            var      cursor = tail.Next;

TryGiver:
            var giver = cursor as Giver <T>;
            Pick pkOther = null;

            if (null != giver)
            {
                goto Giver;
            }

TryPick:
            var st = Pick.TryPick(pkSelf);

            if (st > 0)
            {
                goto AlreadyPicked;
            }
            if (st < 0)
            {
                goto TryPick;
            }

            WaitQueue.RemoveRange(ref this.Givers, cursor);
            this.Lock.Exit();

            Pick.SetNacks(ref wr, i, pkSelf);
            Cont.Do(xK, ref wr, cursor.Value);
            return;

AlreadyPicked:
            WaitQueue.RemoveRangeInclusive(this.Givers, cursor);
            this.Lock.Exit();
            return;

Giver:
            cursor  = cursor.Next;
            pkOther = giver.Pick;

            if (null == pkOther)
            {
                goto TryPickSelf;
            }
            if (pkOther == pkSelf)
            {
                goto OtherIsSelf;
            }

TryPickOther:
            var stOther = Pick.TryClaim(pkOther);

            if (stOther > 0)
            {
                goto TryNextGiver;
            }
            if (stOther < 0)
            {
                goto TryPickOther;
            }

TryPickSelf:
            var stSelf = Pick.TryPick(pkSelf);

            if (stSelf > 0)
            {
                goto SelfAlreadyPicked;
            }
            if (stSelf < 0)
            {
                goto BackOff;
            }

            //GotGiver:
            WaitQueue.RemoveRange(ref this.Givers, giver);
            this.Lock.Exit();
            if (null != pkOther)
            {
                Pick.PickClaimedAndSetNacks(ref wr, giver.Me, pkOther);
            }
            Pick.SetNacks(ref wr, i, pkSelf);
            Worker.Push(ref wr, giver.Cont);
            Cont.Do(xK, ref wr, giver.Value);
            return;

BackOff:
            if (null == pkOther)
            {
                goto TryPickSelf;
            }
            Pick.Unclaim(pkOther);
            goto TryPickOther;

OtherIsSelf:
            WaitQueue.Enqueue(ref cache, giver);
            if (giver != tail)
            {
                goto TryGiver;
            }

            this.Givers = cache;
            goto TryTaker;

TryNextGiver:
            if (giver != tail)
            {
                goto TryGiver;
            }

            this.Givers = cache;
TryTaker:
            WaitQueue.AddTaker(ref this.Takers, i, pkSelf, xK);
            this.Lock.Exit();
            xE.TryElse(ref wr, i + 1);
            return;

SelfAlreadyPicked:
            if (null != pkOther)
            {
                Pick.Unclaim(pkOther);
            }

            WaitQueue.RemoveRangeInclusive(this.Givers, giver);
            this.Lock.Exit();
            return;
        }
Beispiel #24
0
        /// Internal implementation detail.
        internal override void TryAlt(ref Worker wr, int i, Pick pkSelf, Cont <T> aK)
        {
Spin:
            var state = this.State;

            if (state < Running)
            {
                goto Completed;
            }
            if (state == Locked)
            {
                goto Spin;
            }
            if (state != Interlocked.CompareExchange(ref this.State, Locked, state))
            {
                goto Spin;
            }

            if (state == Running)
            {
                goto Running;
            }

            var job = this.Readers as Cont;

            var taker = new Taker <T>();

            taker.Me     = i;
            taker.Pick   = pkSelf;
            taker.Cont   = aK;
            taker.Next   = taker;
            this.Readers = taker;

            this.State = Running;

            Worker.Push(ref wr, job);
            aK.TryNext(ref wr, i + 1, pkSelf);
            return;

Running:
            WaitQueue.AddTaker(ref this.Readers, i, pkSelf, aK);
            this.State = Running;
            aK.TryNext(ref wr, i + 1, pkSelf);
            return;

Completed:
            var stSelf = Pick.TryPick(pkSelf);

            if (stSelf > 0)
            {
                goto AlreadyPicked;
            }
            if (stSelf < 0)
            {
                goto Completed;
            }

            Pick.SetNacks(ref wr, i, pkSelf);

            if (state == Completed)
            {
                aK.DoCont(ref wr, this.Value);
            }
            else
            {
                aK.DoHandle(ref wr, (this.Readers as Fail).exn);
            }
AlreadyPicked:
            return;
        }