internal override void DoWork(ref Worker wr) { var me = this.me; if (me < 0 && me == Interlocked.CompareExchange(ref this.me, 0, me)) { return; } if (0 != Pick.PickAndSetNacks(pk, ref wr, me)) { xJ.DoCancel(iar); } else { Cont.Do(xK, ref wr, xJ.DoEnd(iar)); } }
internal static void PickReaders <T>(ref Cont <T> readersVar, T value, ref Worker wr) { var readers = readersVar; if (null == readers) { return; } readersVar = null; int me = 0; Work cursor = readers; TryReader: var reader = cursor as Cont <T>; cursor = cursor.Next; var pk = reader.GetPick(ref me); if (null == pk) { goto GotReader; } TryPick: var st = Pick.TryPick(pk); if (st > 0) { goto TryNextReader; } if (st < 0) { goto TryPick; } Pick.SetNacks(ref wr, me, pk); GotReader: reader.Value = value; Worker.Push(ref wr, reader); TryNextReader: if (cursor != readers) { goto TryReader; } }
internal static int DoPickOpt(Pick pk) { var st = 0; if (null == pk) { goto Done; } Retry: st = TryPick(pk); if (st < 0) { goto Retry; } Done: return(st); }
internal static void AddGiver <T>(ref Send <T> queue, T x, int me, Pick pk, Cont <Unit> uK) { var last = queue; Giver <T> elem; if (null != last) { goto MaybeReuse; } elem = new Giver <T>(); queue = elem; elem.Next = elem; elem.Value = x; elem.Me = me; elem.Pick = pk; elem.Cont = uK; return; MaybeReuse: elem = last as Giver <T>; if (null == elem) { goto New; } var pkGiver = elem.Pick; if (null != pkGiver && pkGiver.State > 0) { goto Init; } New: elem = new Giver <T>(); queue = elem; elem.Next = last.Next; last.Next = elem; Init: elem.Value = x; elem.Me = me; elem.Pick = pk; elem.Cont = uK; CleanGivers(elem); }
internal static void FailReaders <T>(Cont <T> readers, Exception e, ref Worker wr) { if (null == readers) { return; } Work cursor = readers; TryReader: var reader = cursor as Cont <T>; cursor = cursor.Next; int me = 0; var pk = reader.GetPick(ref me); if (null == pk) { goto GotReader; } TryPick: var st = Pick.TryPick(pk); if (st > 0) { goto TryNextReader; } if (st < 0) { goto TryPick; } Pick.SetNacks(ref wr, me, pk); GotReader: Worker.PushNew(ref wr, new FailWork(e, reader)); TryNextReader: if (cursor != readers) { goto TryReader; } }
internal override void TryAlt(ref Worker wr, int i, Cont <Unit> uK, Else uE) { var pkSelf = uE.pk; Spin: var state = this.State; if (state > Initial) { goto TryPick; } if (state < Initial) { goto Spin; } if (Initial != Interlocked.CompareExchange(ref this.State, ~state, state)) { goto Spin; } WaitQueue.AddTaker(ref this.Takers, i, pkSelf, uK); this.State = Initial; uE.TryElse(ref wr, i + 1); return; 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; }
internal static int PickAndSetNacks(Pick pk, ref Worker wr, int i) { TryPick: var state = Pick.TryPick(pk); if (state > 0) { goto AlreadyPicked; } if (state < 0) { goto TryPick; } SetNacks(ref wr, i, pk); AlreadyPicked: return(state); }
internal static void AddTaker <T>(ref Cont <T> queue, int me, Pick pk, Cont <T> xK) { var last = queue; Taker <T> elem; if (null != last) { goto MaybeReuse; } elem = new Taker <T>(); queue = elem; elem.Next = elem; elem.Me = me; elem.Pick = pk; elem.Cont = xK; return; MaybeReuse: elem = last as Taker <T>; if (null == elem) { goto New; } var pkTaker = elem.Pick; if (/*null != pkTaker &&*/ pkTaker.State > 0) { goto Init; } New: elem = new Taker <T>(); queue = elem; elem.Next = last.Next; last.Next = elem; Init: elem.Me = me; elem.Pick = pk; elem.Cont = xK; CleanTakers(elem); }
/// <summary>Internal implementation detail.</summary> internal override void TryAlt(ref Worker wr, int i, Pick pkSelf, Cont <Unit> uK) { Spin: var state = this.State; if (state > Initial) { goto TryPick; } if (state < Initial) { goto Spin; } if (Initial != Interlocked.CompareExchange(ref this.State, Locked, Initial)) { goto Spin; } WaitQueue.AddTaker(ref this.Takers, i, pkSelf, uK); this.State = Initial; uK.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); uK.DoCont(ref wr, null); AlreadyPicked: return; }
/// Internal implementation detail. internal override void TryAlt(ref Worker wr, int i, Pick pkSelf, Cont <T> aK) { TryPick: var stSelf = Pick.TryPick(pkSelf); if (stSelf > 0) { goto AlreadyPicked; } if (stSelf < 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 <Unit> uK, Else uE) { var pkSelf = uE.pk; TryPick: var stSelf = Pick.TryPick(pkSelf); if (stSelf > 0) { goto AlreadyPicked; } if (stSelf < 0) { goto TryPick; } Pick.SetNacks(ref wr, i, pkSelf); Work.Do(uK, ref wr); AlreadyPicked: return; }
internal override void TryAlt(ref Worker wr, int i, Cont <T> xK, Else xE) { var pkSelf = xE.pk; TryPick: var stSelf = Pick.TryPick(pkSelf); if (stSelf > 0) { goto AlreadyPicked; } if (stSelf < 0) { goto TryPick; } Pick.SetNacks(ref wr, i, pkSelf); Cont.Do(xK, ref wr, this.value); AlreadyPicked: return; }
public static Nack AddNack(Pick pk, int i0) { TryClaim: var st = TryClaim(pk); if (st > 0) { goto AlreadyPicked; } if (st < 0) { goto TryClaim; } var nk = new Nack(pk.Nacks, i0); pk.Nacks = nk; Unclaim(pk); return(nk); AlreadyPicked: return(null); }
internal static void Unclaim(Pick pk) { pk.State = Available; }
internal static void Signal(ref Worker wr, Nack nk) { Spin: var state = nk.State; if (state > Initial) { goto JustExit; // XXX Can this happen? } if (state < Initial) { goto Spin; } if (Initial != Interlocked.CompareExchange(ref nk.State, state + 1, state)) { goto Spin; } var takers = nk.Takers; if (null == takers) { goto JustExit; } nk.Takers = null; var me = 0; Work cursor = takers; TryTaker: var taker = cursor as Cont <Unit>; cursor = cursor.Next; var pk = taker.GetPick(ref me); if (null == pk) { goto GotTaker; } TryPick: var st = Pick.TryPick(pk); if (st > 0) { goto TryNextTaker; } if (st < 0) { goto TryPick; } Pick.SetNacks(ref wr, me, pk); GotTaker: Worker.Push(ref wr, taker); TryNextTaker: if (cursor != takers) { goto TryTaker; } JustExit: return; }
internal static int TryPick(Pick pk) { return(Interlocked.CompareExchange(ref pk.State, Picked, Available)); }
internal static void Run(int me) { var wr = new Worker(); wr.Init(); //Func<Worker> box = () => wr; var mine = Scheduler.Events[me]; Work work = null; while (true) { try { goto Begin; WorkerLoop: wr.WorkStack = work.Next; Do: wr.Handler = work; work.DoWork(ref wr); work = wr.WorkStack; Begin: if (null != work) { goto WorkerLoop; } EnterScheduler: SpinlockTTAS.Enter(ref Scheduler.Lock); TryScheduler: work = Scheduler.WorkStack; if (null == work) { goto TryTimed; } { var next = work.Next; Scheduler.WorkStack = next; if (null == next) { goto NoWake; } var waiter = Scheduler.Waiters; if (0 <= waiter) { Scheduler.Events[waiter].Set(); } } NoWake: SpinlockTTAS.Exit(ref Scheduler.Lock); goto Do; TryTimed: var waitTicks = Timeout.Infinite; { var tt = Scheduler.TopTimed; if (null == tt) { goto JustWait; } waitTicks = tt.Ticks - Environment.TickCount; if (waitTicks > 0) { goto JustWait; } Scheduler.DropTimed(); SpinlockTTAS.Exit(ref Scheduler.Lock); var pk = tt.Pick; if (null == pk) { goto GotIt; } TryPick: var st = Pick.TryPick(pk); if (st > 0) { goto EnterScheduler; } if (st < 0) { goto TryPick; } Pick.SetNacks(ref wr, tt.Me, pk); GotIt: work = tt; goto Do; } JustWait: var n = Scheduler.Waiters; if (n < 0) { mine.Next = -1; Scheduler.Waiters = me; } else { WorkerEvent other = Scheduler.Events[n]; mine.Next = other.Next; other.Next = me; } mine.Reset(); SpinlockTTAS.Exit(ref Scheduler.Lock); mine.Wait(waitTicks); SpinlockTTAS.Enter(ref Scheduler.Lock); if (Scheduler.Waiters == me) { Scheduler.Waiters = mine.Next; } else { WorkerEvent ev = Scheduler.Events[Scheduler.Waiters]; if (ev.Next != me) { do { ev = Scheduler.Events[ev.Next]; } while (ev.Next != me); } ev.Next = mine.Next; } goto TryScheduler; } catch (Exception e) { work = new FailWork(wr.WorkStack, e, wr.Handler); } } }
internal Else Init(Pick pk, S1 s1) { this.pk = pk; this.State1 = s1; return(this); }
internal Else Init(Pick pk) { this.pk = pk; return(this); }
internal AltCallback(Scheduler sr, FromBeginEnd <X> xJ, Cont <X> xK, Pick pk, int me) : base(sr, xJ, xK) { this.pk = pk; this.me = me; }
internal Else_State(Pick pk, S s) : base(pk) { State = s; }
internal WorkTimed(int ticks, int me, Pick pk) { this.Ticks = ticks; this.Me = me; this.Pick = pk; }
internal static void PickClaimed(Pick pk) { pk.State = 1; }
internal static void Unclaim(Pick pk) { pk.State = 0; }
internal static int TryPick(Pick pk) { return(Interlocked.CompareExchange(ref pk.State, 1, 0)); }
internal override void DoJob(ref Worker wr, Cont <int> iK) { TryNextTimed: var waitTicks = Timeout.Infinite; var tt = this.TopTimed; if (null == tt) { goto Return; } var tickCount = Environment.TickCount; waitTicks = tt.Ticks - tickCount; if (waitTicks > 0) { goto Return; } this.Lock.Enter(); tt = this.TopTimed; if (null == tt) { goto ExitAndReturnWithInfinite; } waitTicks = tt.Ticks - tickCount; if (waitTicks > 0) { goto ExitAndReturn; } DropTimed(); this.Lock.Exit(); var pk = tt.Pick; if (null == pk) { goto GotIt; } TryPick: var st = Pick.TryPick(pk); if (st > 0) { goto TryNextTimed; } if (st < 0) { goto TryPick; } Pick.SetNacks(ref wr, tt.Me, pk); GotIt: Worker.Push(ref wr, tt); iK.DoCont(ref wr, 0); return; ExitAndReturnWithInfinite: waitTicks = Timeout.Infinite; ExitAndReturn: this.Lock.Exit(); Return: iK.DoCont(ref wr, waitTicks); }
internal static void PickClaimedAndSetNacks(ref Worker wr, int i, Pick pk) { pk.State = 1; SetNacks(ref wr, i, pk); }
internal Else(Pick pk) { this.pk = pk; }
internal WorkTimed(int ticks, int me, Pick pk) { this.Ticks = ((long)ticks) << 32; this.Me = me; this.Pick = pk; }