/// 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; }
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; }
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; }
// 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; }
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); }
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); }
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; }
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; }
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); } }
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; }
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; }
/// 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); } }
/// 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; }
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; }
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; }
/// 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; }
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; }
/// 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; }
internal void UnsafeAddReader(Cont <T> tK) { WaitQueue.AddTaker(ref this.Readers, tK); }
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; }
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; }
/// 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; }
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; }
/// 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; }