internal override WaitNode TryTakePrologue(StParker pk, int key, out T di, ref WaitNode hint) { var localQueue = Current; if (TryTake(out di, localQueue)) { if (pk.TryLock()) { pk.UnparkSelf(key); } else { localQueue.TryAdd(di); } return(null); } var wn = new WaitNode(pk, key); waitQueue.Enqueue(wn); if (!pk.IsLocked && TryTake(out di, localQueue)) { if (pk.TryLock()) { waitQueue.Unlink(wn, hint); pk.UnparkSelf(key); return(null); } localQueue.TryAdd(di); } return(wn); }
internal WaitBlock(WaitType t, int r, int k) { parker = new StParker(); waitType = t; request = r; waitKey = k; }
// // Exchanges a data item, activating the specified cancellers. // public bool Exchange(T myData, out T yourData, StCancelArgs cargs) { if (TryExchange(myData, out yourData)) { return(true); } var pk = new StParker(); var wn = new WaitNode(pk, myData); if (TryExchange(wn, myData, out yourData)) { return(true); } int ws = pk.Park(spinCount, cargs); if (ws == StParkStatus.Success) { yourData = wn.Channel; return(true); } CancelExchange(wn); StCancelArgs.ThrowIfException(ws); return(false); }
// // Executes the prologue of the TryTake operation. // internal override WaitNode TryTakePrologue(StParker pk, int key, out T di, ref WaitNode hint) { WaitNode wn = base.TryTakePrologue(pk, key, out di, ref hint); if (wn == null) { FreeSlot(); } return wn; }
internal WaitBlock(StParker pk, WaitType t, int r, int k) { parker = pk; waitType = t; request = r; waitKey = k; }
public static int Sleep(StCancelArgs cargs) { int ws = new StParker().Park(0, cargs); StCancelArgs.ThrowIfException(ws); return(ws); }
// // Tries to take a data item from the queue, activating the // specified cancellers. // public bool TryTake(out T di, StCancelArgs cargs) { if (TryTake(out di)) { return(true); } if (cargs.Timeout == 0) { return(false); } StParker pk = new StParker(); WaitNode wn, hint = null; if ((wn = TryTakePrologue(pk, StParkStatus.Success, out di, ref hint)) == null) { return(true); } int ws = pk.Park(cargs); if (ws == StParkStatus.Success) { TakeEpilogue(); di = wn.channel; return(true); } // // The take was cancelled; so, cancel the take attempt and // report the failure appropriately. // CancelTakeAttempt(wn, hint); StCancelArgs.ThrowIfException(ws); return(false); }
internal WaitBlock WaitWithParker(StParker pk, WaitType type, int key, ref int sc) { WaitBlock wb = null; do { WaitBlock s; if ((s = state) == SET) { return(null); } if (wb == null) { wb = new WaitBlock(pk, type, 0, key); } wb.next = s; if (Interlocked.CompareExchange(ref state, wb, s) == s) { sc = s == null ? spinCount : 0; return(wb); } } while (true); }
/*++ * * Generic API * * --*/ // // Tries to add a data item to the queue, activating the specified // cancellers. // public bool TryAdd(T di, StCancelArgs cargs) { if (TryAdd(di)) { return(true); } if (cargs.Timeout == 0) { return(false); } WaitNode hint = null; WaitNode wn; StParker pk = new StParker(); if ((wn = TryAddPrologue(pk, StParkStatus.Success, di, ref hint)) == null) { return(true); } int ws = pk.Park(cargs); if (ws == StParkStatus.Success) { return(true); } // // The add operation was cancelled; so, cancel the add attempt // and report the failure appropriately. // CancelAddAttempt(wn, hint); StCancelArgs.ThrowIfException(ws); return(false); }
internal override WaitBlock _WaitAnyPrologue(StParker pk, int key, ref WaitBlock hint, ref int sc) { WaitBlock wb = null; do { if (_TryAcquire()) { return(null); } if (wb == null) { wb = new WaitBlock(pk, WaitType.WaitAny, ACQUIRE, key); } WaitBlock pred; if (EnqueueWaiter(wb, out pred)) { sc = ((hint = pred) == head) ? spinCount : 0; return(wb); } } while (true); }
// // Registers the specified parker with the alerter. // internal bool RegisterParker(StParker pk) { do { StParker s; // // If the alerter is already set, return false. // if ((s = state) == ALERTED) { return(false); } // // Try to insert the parker in the alert list. // pk.pnext = s; if (Interlocked.CompareExchange <StParker>(ref state, pk, s) == s) { return(true); } } while (true); }
// // Waits until the synchronizer allows the acquire, activating // the specified cancellers. // public bool WaitOne(StCancelArgs cargs) { if (_TryAcquire()) { return(true); } if (cargs.Timeout == 0) { return(false); } var pk = new StParker(); WaitBlock hint = null; int sc = 0; WaitBlock wb; if ((wb = _WaitAnyPrologue(pk, StParkStatus.Success, ref hint, ref sc)) == null) { return(true); } int ws = pk.Park(sc, cargs); if (ws == StParkStatus.Success) { _WaitEpilogue(); return(true); } _CancelAcquire(wb, hint); StCancelArgs.ThrowIfException(ws); return(false); }
internal override WaitBlock _WaitAllPrologue(StParker pk, ref WaitBlock hint, ref int sc) { WaitBlock wb = null; if (_AllowsAcquire) { return(null); } if (wb == null) { wb = new WaitBlock(pk, WaitType.WaitAll, ACQUIRE, StParkStatus.StateChange); } WaitBlock pred; if (EnqueueWaiter(wb, out pred)) { sc = ((hint = pred) == head) ? spinCount : 0; return(wb); } return(null); }
// // Executes the prologue of the TryAdd operation. // internal override WaitNode TryAddPrologue(StParker pk, int key, T di, ref WaitNode ignored) { if (pk.TryLock()) { pk.UnparkSelf(key); } AddWorker(di); return(null); }
// // Constructor: registers a take with a blocking queue. // internal StRegisteredTake(StBlockingQueue <T> queue, StTakeCallback <T> callback, object cbState, int timeout, bool executeOnce) { // // Validate the arguments. // if (timeout == 0) { throw new ArgumentOutOfRangeException("\"timeout\" can not be zero"); } if (callback == null) { throw new ArgumentOutOfRangeException("\"callback\" must be specified"); } // // Initialize the registered take fields. // this.queue = queue; cbparker = new CbParker(UnparkCallback); if ((this.timeout = timeout) != Timeout.Infinite) { toTimer = new RawTimer(cbparker); } this.executeOnce = executeOnce; this.callback = callback; this.cbState = cbState; // // Execute the TryTakePrologue prologue on the queue. // waitNode = queue.TryTakePrologue(cbparker, StParkStatus.Success, out dataItem, ref hint); // // Set the state to active and enable the unpark callback. // state = ACTIVE; int ws; if ((ws = cbparker.EnableCallback(timeout, toTimer)) != StParkStatus.Pending) { // // The take operation was already accomplished. To prevent // uncontrolled reentrancy, the unpark callback is executed inline. // UnparkCallback(ws); } }
// // Executes the prologue of the Waitable.WaitAny method. // internal override WaitBlock _WaitAnyPrologue(StParker pk, int key, ref WaitBlock ignored, ref int sc) { if (TryEnterWriteInternal()) { return(null); } var wb = new WaitBlock(pk, WaitType.WaitAny, ENTER_WRITE, key); sc = EnqueueEnterWrite(wb); return(wb); }
internal override WaitBlock _WaitAnyPrologue(StParker pk, int key, ref WaitBlock ignored, ref int sc) { if (TryAcquireInternal(1)) { return(null); } var wb = new WaitBlock(pk, WaitType.WaitAny, 1, key); sc = EnqueueAcquire(wb, 1); return(wb); }
// // Executes the prologue of the Waitable.WaitAll method. // internal override WaitBlock _WaitAllPrologue(StParker pk, ref WaitBlock ignored, ref int sc) { if (_AllowsAcquire) { return(null); } var wb = new WaitBlock(pk, WaitType.WaitAll, ENTER_WRITE, StParkStatus.StateChange); sc = EnqueueEnterWrite(wb); return(wb); }
private bool SlowTryInit(int spinCount) { StParker s; do { if ((s = state) == FREE && Interlocked.CompareExchange(ref state, BUSY, FREE) == FREE) { return(true); } if (s == AVAILABLE) { return(false); } if (spinCount-- <= 0) { break; } Platform.SpinWait(1); } while (true); // // The initialization is taking place. So, create a locked parker // and insert it in the wait queue, if the lock remains busy. // var pk = new StParker(0); do { if ((s = state) == FREE && Interlocked.CompareExchange(ref state, BUSY, FREE) == FREE) { return(true); } if (s == AVAILABLE) { return(false); } pk.pnext = s; if (Interlocked.CompareExchange(ref state, pk, s) == s) { break; } } while (true); return(pk.Park() == STATUS_INIT); }
// // Deregisters the specified parker from the alerter. // internal void DeregisterParker(StParker pk) { // // Very often there is only a parker inserted in the alerter // list. So, consider first this case. // if (pk.pnext == null && Interlocked.CompareExchange <StParker>(ref state, null, pk) == pk) { return; } SlowDeregisterParker(pk); }
// // Deregisters the specified parker when it isn't the only // parker in the alerter list. // private void SlowDeregisterParker(StParker pk) { // // Absorb the locked parkers at top of the stack. // StParker p; do { if ((p = state) == null || p == ALERTED) { return; } if (p.IsLocked) { Interlocked.CompareExchange <StParker>(ref state, p.pnext, p); } else { break; } } while (true); // // Compute a entry ahead the parker that we want to unlink, // and try to unsplice it. // StParker past; if ((past = pk.pnext) != null && past.IsLocked) { past = past.pnext; } while (p != null && p != past) { StParker n = p.pnext; if (n != null && n.IsLocked) { p.CasNext(n, n.pnext); } else { p = n; } } }
// // Exits the lock. // public void Exit() { // // Since that atomic operations on references are more // expensive than on integers, we optimize the release when // the spin lock's wait queue is empty. However, when the queue // seems empty before the lock is released, but it's seen // non-empty after the lock is released, our algorithm resorts // to two atomic instructions. // if (top == null) { Interlocked.Exchange(ref state, FREE); if (top == null) { return; } } else { state = FREE; } // // Unpark all waiting threads. // // NOTE: Since that the spin lock's queue is implemented with // a stack, we build another stack in order to unpark the // waiting thread according to its arrival order. // StParker p = Interlocked.Exchange <StParker>(ref top, null); StParker ws = null, n; while (p != null) { n = p.pnext; p.pnext = ws; ws = p; p = n; } while (ws != null) { n = ws.pnext; ws.Unpark(StParkStatus.Success); ws = n; } }
// // Constructors. // public StTimer(bool notificationTimer) { if (notificationTimer) { tmrEvent = new StNotificationEvent(); } else { tmrEvent = new StSynchronizationEvent(); } state = INACTIVE; cbparker = new CbParker(TimerCallback); timer = new RawTimer(cbparker); }
// // Tries to unregister the callback. This method is thread-safe. // public bool Unregister() { StParker p = parker; if (p == null) { return(false); } parker = null; if (p.TryCancel()) { p.Unpark(StParkStatus.WaitCancelled); return(true); } return(false); }
// // Executes the prologue of the TryAdd operation. // internal override WaitNode TryAddPrologue(StParker pk, int key, T di, ref WaitNode hint) { if (TryReserveSlot()) { if (pk.TryLock()) { AddWorker(di); pk.UnparkSelf(key); } else { FreeSlot(); } return null; } // // ... // WaitNode wn; hint = waitQueue.Enqueue(wn = new WaitNode(pk, key, di)); // // As a slot could have been free after the check done // above, but before we insert the wait block in the wait queue, // we must retry to reserve a free slot. // if (TryReserveSlot()) { if (pk.TryLock()) { AddWorker(di); pk.UnparkSelf(key); } else { waitQueue.Unlink(wn, hint); FreeSlot(); } return null; } return wn; }
static TimerList() { // // Create the objects. // _lock = new SpinLock(TIMER_LIST_LOCK_SPINS); timerListHead = new RawTimer(null); limitTimer = new RawTimer(null); parker = new StParker(1); // // Initialize the limit timer as unlinked. // limitTimer.next = limitTimer; // // Initialize the timer list as empty. // timerListHead.next = timerListHead.prev = timerListHead; // // Set the start base time e set the *delay* sentinel. // baseTime = Environment.TickCount; timerListHead.delay = Int32.MaxValue; // // Create and start the timer thread. // new Thread(TimerThread).Start(); }
// // Frees the lock and selects a candidate owner from the queue // of waiting threads. // public void Exit() { WaitBlock wb = head; bool unpark = false; StParker pk = null; while ((wb = wb.next) != null && wb.request != CANDIDATE) { pk = wb.parker; if (pk.TryLock()) { wb.request = CANDIDATE; unpark = true; break; } } state = FREE; if (unpark) { pk.Unpark(StParkStatus.Success); } }
// // Constructors. // public SpinLock(int sc) { state = FREE; top = null; spinCount = Platform.IsMultiProcessor ? sc : 0; }
// // Slow path to acquire the spin lock. // private void SlowEnter() { StParker pk = null; do { // // First, try to acquire the spin lock, spinning for the // specified number of cycles, if the wait queue is empty. // int sc = spinCount; do { if (state == FREE && Interlocked.CompareExchange(ref state, BUSY, FREE) == FREE) { return; } if (top != null || sc-- <= 0) { break; } Platform.SpinWait(1); } while (true); // // The spin lock is busy. So, create, or reset, a parker and // insert it in the wait queue. // if (pk == null) { pk = new StParker(0); } else { pk.Reset(0); } do { StParker t; pk.pnext = (t = top); if (Interlocked.CompareExchange <StParker>(ref top, pk, t) == t) { break; } } while (true); // // Since that the lock can become free after the parker is // inserted in the wait queue, we must retry to acquire the spinlock // if it seems free. // // NOTE: We don't remove the parker from the wait queue, because // it will be surely removed next time the lock is release. // if (state == FREE && Interlocked.CompareExchange(ref state, BUSY, FREE) == FREE) { return; } // // Park the current thread and, after release, retry the // spin lock acquire. // pk.Park(); } while (true); }
internal override WaitBlock _WaitAllPrologue(StParker pk, ref WaitBlock hint, ref int sc) { return(waitEvent.WaitWithParker(pk, WaitType.WaitAll, StParkStatus.StateChange, ref sc)); }