/*++ * * 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); }
// // 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); }
public static int Sleep(StCancelArgs cargs) { int ws = new StParker().Park(0, cargs); StCancelArgs.ThrowIfException(ws); return(ws); }
// // Waits until acquire the specified number of permits, activating // the specified cancellers. // public bool Wait(int acquireCount, StCancelArgs cargs) { if (acquireCount <= 0 || acquireCount > maximumCount) { throw new ArgumentException("acquireCount"); } if (TryAcquireInternal(acquireCount)) { return true; } if (cargs.Timeout == 0) { return false; } var wb = new WaitBlock(WaitType.WaitAny, acquireCount); int sc = EnqueueAcquire(wb, acquireCount); int ws = wb.parker.Park(sc, cargs); if (ws == StParkStatus.Success) { return true; } CancelAcquire(wb); StCancelArgs.ThrowIfException(ws); return false; }
// // Waits until acquire the specified number of permits, activating // the specified cancellers. // public bool Wait(int acquireCount, StCancelArgs cargs) { if (acquireCount <= 0 || acquireCount > maximumCount) { throw new ArgumentException("acquireCount"); } if (TryAcquireInternal(acquireCount)) { return(true); } if (cargs.Timeout == 0) { return(false); } var wb = new WaitBlock(WaitType.WaitAny, acquireCount); int sc = EnqueueAcquire(wb, acquireCount); int ws = wb.parker.Park(sc, cargs); if (ws == StParkStatus.Success) { return(true); } CancelAcquire(wb); StCancelArgs.ThrowIfException(ws); return(false); }
// // 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); }
// // 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); }
// // Tries to enter the read lock, activating the specified // cancellers. // public bool TryEnterRead(StCancelArgs cargs) { OwnerEntry hint; int tid; if (FastTryEnterRead((tid = Thread.CurrentThread.ManagedThreadId), out hint)) { return true; } // // The current thread isn't a read lock owner. So, allocate an // entry on the lock owner table, before acquire the non-reentrant // r/w lock. // hint = readOwner.AllocateEntry(tid, hint); if (rwlock.TryEnterRead(cargs)) { return true; } // // The specified timeout expired, so remove our entry // from the lock owner table and return failure. // hint.Free(); return false; }
private int SlowWait(StCancelArgs cargs, WaitBlock wb) { do { WaitBlock s; if ((s = state) == SET) { return(StParkStatus.Success); } wb.next = s; if (Interlocked.CompareExchange(ref state, wb, s) == s) { break; } } while (true); int ws = wb.parker.Park(wb.next == null ? spinCount : 0, cargs); if (ws != StParkStatus.Success) { Unlink(wb); } return(ws); }
// // Tries to acquire the lock, activating the specified // cancellers. // public bool Enter(StCancelArgs cargs) { if (TryEnter()) { return(true); } return((cargs.Timeout != 0) ? SlowEnter(cargs) : false); }
/// <summary> /// Waits until one of the specified waitables can be acquired, /// activating the specified cancellers. /// </summary> /// <param name="ws">The array of Waitables.</param> /// <param name="cargs">The cancellation arguments.</param> /// <returns></returns> public static int WaitAny(StWaitable[] ws, StCancelArgs cargs) { if (ws == null) { throw new ArgumentNullException("ws"); } return(WaitAnyInternal(ws, null, cargs)); }
public StCancelArgs(int timeout, StAlerter alerter, bool interruptible) { if (timeout < -1) { throw new ArgumentOutOfRangeException("timeout", timeout, "Wrong timeout value"); } this = new StCancelArgs(); Timeout = timeout; Alerter = alerter; Interruptible = interruptible; }
// // Waits until the future's value is available, activating the // specified cancellers. // public bool Wait(out T result, StCancelArgs cargs) { if (waitEvent.Wait(cargs) == StParkStatus.Success) { result = _value; return(true); } result = default(T); return(false); }
public StCancelArgs(int timeout, StAlerter alerter, bool interruptible) { if (timeout < -1) { throw new ArgumentOutOfRangeException("timeout", timeout, "Wrong timeout value"); } this = new StCancelArgs(); Timeout = timeout; Alerter = alerter; Interruptible = interruptible; }
private bool SlowEnter(StCancelArgs cargs) { int lastTime = cargs.Timeout != Timeout.Infinite ? Environment.TickCount : 0; bool timeRemaining = true; WaitBlock wb = EnqueueWaiter(); do { if (TryEnter()) { Cleanup(wb); return(true); } if (!timeRemaining) { return(false); } int ws = wb.parker.Park(head.next == wb ? spinCount : 0, cargs); if (ws != StParkStatus.Success) { StCancelArgs.ThrowIfException(ws); return(false); } if (TryEnter()) { Cleanup(wb); return(true); } // // We failed to acquire the lock so we must clear the current // thread as the candidate owner. After doing so we must recheck // the state of lock. If the wait timed out, we exit the loop // before parking again. // if ((timeRemaining = cargs.AdjustTimeout(ref lastTime))) { wb.parker.Reset(); } // // Avoid a release-followed-by-acquire hazard. // Interlocked.Exchange(ref wb.request, ACQUIRE); } while (true); }
// // Waits until enter the write lock, activating the specified // cancellers. // public bool TryEnterWrite(StCancelArgs cargs) { // // Try to enter the write lock and, if succeed, return success. // if (TryEnterWriteInternal()) { return(true); } // // Return failure, if a null timeout was specified. // if (cargs.Timeout == 0) { return(false); } // // Create a wait block and insert it in the r/w lock's queue. // WaitBlock wb = new WaitBlock(WaitType.WaitAny, ENTER_WRITE, StParkStatus.Success); int sc = EnqueueEnterWrite(wb); // // Park the current thread, activating the specified cancellers // and spinning if appropriate. // int ws = wb.parker.Park(sc, cargs); // // If we entered the write lock, return success. // if (ws == StParkStatus.Success) { return(true); } // // The request was cancelled; so, cancel the enter write lock // attempt and report the failure appropriately. // CancelAcquire(wb); StCancelArgs.ThrowIfException(ws); return(false); }
/// <summary> /// Waits until all of the specified waitables or wait handles can be /// acquired, activating the specified cancellers. /// </summary> /// <param name="ws"></param> /// <param name="hs"></param> /// <param name="cargs"></param> /// <returns></returns> public static bool WaitAll(StWaitable[] ws, WaitHandle[] hs, StCancelArgs cargs) { if (hs == null) { throw new ArgumentNullException("hs"); } if (cargs.Alerter != null) { throw new ArgumentException("Cancellation through the alerter mechanism is not supported", "cargs"); } return(WaitAllInternal(ws, hs, cargs)); }
// // Tries to enter the lock, activating the specifed cancellers. // public bool TryEnter(StCancelArgs cargs) { // // First check if the lock is free and, if so, try to acquire it. // int tid = Thread.CurrentThread.ManagedThreadId; if (nrlock.state == StLock.FREE && Interlocked.CompareExchange(ref nrlock.state, StLock.BUSY, StLock.FREE) == StLock.FREE) { // // Set the owner thread, since that a free lock has a zero // recursive acquisition count. // owner = tid; return(true); } if (owner == tid) { // // Recursive enter, so increment the recursive acquisition // counter. // count++; return(true); } if (cargs.Timeout != 0 && nrlock.Enter(cargs)) { owner = tid; return(true); } // // The acquire attempt was cancelled, so return failure. // return(false); }
// // Tries to enter the write lock, activating the specified // cancellers. // public bool TryEnterWrite(StCancelArgs cargs) { int tid; if (FastTryEnterWrite(tid = Thread.CurrentThread.ManagedThreadId)) { return true; } // // We are not the current writer; so, try to enter the write // on the associated non-reentrant r/w lock. // if (rwlock.TryEnterWrite(cargs)) { writer = tid; count = 1; return true; } // // The specified timeout expired, so return failure. // return false; }
/// <summary> /// Waits until one of the specified waitables or wait handles can be /// acquired, activating the specified cancellers. /// </summary> /// <param name="ws">The array of waitables.</param> /// <param name="hs">The array of wait handles.</param> /// <param name="cargs">The cancellation arguments.</param> /// <returns></returns> public static int WaitAny(StWaitable[] ws, WaitHandle[] hs, StCancelArgs cargs) { if (ws == null) { throw new ArgumentNullException("ws"); } if (hs == null) { throw new ArgumentNullException("hs"); } int len = ws.Length; for (int i = 0; i < hs.Length; i++) { if (hs[i].WaitOne(0)) { return(StParkStatus.Success + len + i); } } return(WaitAnyInternal(ws, hs, cargs)); }
private bool SlowEnter(StCancelArgs cargs) { int lastTime = cargs.Timeout != Timeout.Infinite ? Environment.TickCount : 0; bool timeRemaining = true; WaitBlock wb = EnqueueWaiter(); do { if (TryEnter()) { Cleanup(wb); return true; } if (!timeRemaining) { return false; } int ws = wb.parker.Park(head.next == wb ? spinCount : 0, cargs); if (ws != StParkStatus.Success) { StCancelArgs.ThrowIfException(ws); return false; } if (TryEnter()) { Cleanup(wb); return true; } // // We failed to acquire the lock so we must clear the current // thread as the candidate owner. After doing so we must recheck // the state of lock. If the wait timed out, we exit the loop // before parking again. // if ((timeRemaining = cargs.AdjustTimeout(ref lastTime))) { wb.parker.Reset(); } // // Avoid a release-followed-by-acquire hazard. // Interlocked.Exchange(ref wb.request, ACQUIRE); } while (true); }
// // Tries to enter the write lock, activating the specified // cancellers. // public bool TryEnterWrite(StCancelArgs cargs) { int tid = Thread.CurrentThread.ManagedThreadId; if (!isReentrant) { if (tid == writer) { throw new StLockRecursionException("Recursive enter write not allowed"); } if (rdCounts.Lookup(tid) != null) { throw new StLockRecursionException("Write after read not allowed"); } } else { // // If this is a recursive enter, increment the recursive acquisition // counter and return success. // if (tid == writer) { wrCount++; return true; } } // // Acquire the spinlock that protects the r/w lock shared state. // slock.Enter(); // // If the write lock can be entered - this is, there are no lock // readers, no lock writer or upgrader or the current thread is the // upgrader -, enter the write lock, release the spinlock and // return success. // if (readers == 0 && writer == UNOWNED && (upgrader == tid || upgrader == UNOWNED)) { writer = tid; slock.Exit(); wrCount = 1; return true; } // // If the current thread isn't the current upgrader but is reader, // release the spinlock and throw the appropriate exception. // if (tid != upgrader && rdCounts.Lookup(tid) != null) { slock.Exit(); throw new StLockRecursionException("Write after read not allowed"); } // // The write lock can't be entered immediately. So, if a null timeout // was specified, release the spinlock and return failure. // if (cargs.Timeout == 0) { slock.Exit(); return false; } // // Create a wait node and insert it in the writers queue. // If the current thread isn't the current upgrader, the wait // node is inserted in the writer's queue; otherwise, the wait // node becomes referenced by the *upgradeToWriteWaiter* field. // int sc; WaitNode wn = new WaitNode(tid); if (tid == upgrader) { upgToWrWaiter = wn; sc = spinCount; } else { sc = wrQueue.IsEmpty ? spinCount : 0; wrQueue.Enqueue(wn); } // // Release spin the lock and park the current thread, activating // the specified cancellers and spinning, if appropriate. // slock.Exit(); int ws = wn.Park(sc, cargs); // // If the thread entered the write lock, initialize the recursive // acquisition counter and return success. // if (ws == StParkStatus.Success) { wrCount = 1; return true; } // // The enter attempted was cancelled. So, if the wait node was // already remove from the respective queue, report the failure // appropriately. Otherwise, unlink the wait node and, if appropriate, // taking into account the other waiters. // if (wn.next == wn) { goto ReportFailure; } slock.Enter(); if (wn.next != wn) { if (wn == upgToWrWaiter) { upgToWrWaiter = null; } else { wrQueue.Remove(wn); // // If the writers queue becomes empty, it is possible that there // is a waiting upgrader or waiting reader threads that can now // proceed. // if (writer == UNOWNED && upgrader == UNOWNED && wrQueue.IsEmpty && TryWakeupUpgraderAndReaders()) { goto ReportFailure; } } } slock.Exit(); ReportFailure: StCancelArgs.ThrowIfException(ws); return false; }
/// <summary> /// Waits until all of the specified waitables can be acquired, /// activating the specified cancellers. /// </summary> /// <param name="ws"></param> /// <param name="cargs"></param> /// <returns></returns> public static bool WaitAll(StWaitable[] ws, StCancelArgs cargs) { return WaitAllInternal(ws, null, cargs); }
internal static bool WaitAllInternal(StWaitable[] ws, WaitHandle[] hs, StCancelArgs cargs) { if (ws == null) { throw new ArgumentNullException("ws"); } int nevts; int len = ws.Length; StWaitable[] sws = new StWaitable[len]; WaitHandle[] shs = null; int waitHint = SortAndCheckAllowAcquire(ws, sws, out nevts); if (waitHint < 0) { throw new ArgumentException("There are duplicate waitables", "ws"); } if (hs != null) { shs = Sort(hs); if (shs == null) { throw new ArgumentException("There are duplicate wait handles", "hs"); } } if (waitHint != 0 && shs != null && !WaitHandle.WaitAll(shs, 0)) { waitHint = 0; } // // Return success if all synchronizers are notification events and are set. // if (waitHint != 0 && nevts == 0) { return(true); } if (waitHint == 0 && cargs.Timeout == 0) { return(false); } // // If a timeout was specified, get the current time in order // to adjust the timeout value later, if we re-wait. // int lastTime = (cargs.Timeout != Timeout.Infinite) ? Environment.TickCount : 0; WaitBlock[] wbs = null; WaitBlock[] hints = null; do { if (waitHint == 0) { // // Create the wait block arrays if this is the first time // that we execute the acquire-all prologue. // if (wbs == null) { wbs = new WaitBlock[len]; hints = new WaitBlock[len]; } // // Create a parker for cooperative release, specifying as many // releasers as the number of waitables. The parker because is // not reused because other threads may have references to it. // StParker pk = shs != null ? new StParker(len, EventBasedParkSpotFactory.Current. Create(new WaitAllBehavior(shs))) : new StParker(len); int gsc = 1; int sc = 0; for (int i = 0; i < len; i++) { if ((wbs[i] = sws[i]._WaitAllPrologue(pk, ref hints[i], ref sc)) == null) { if (pk.TryLock()) { pk.UnparkSelf(StParkStatus.StateChange); } } else if (gsc != 0) { if (sc == 0) { gsc = 0; } else if (sc > gsc) { gsc = sc; } } } int wst = pk.Park(gsc, cargs); // // If the wait was cancelled due to timeout, alert or interrupt, // cancel the acquire attempt on all waitables where we actually // inserted wait blocks. // if (wst != StParkStatus.StateChange) { for (int i = 0; i < len; i++) { WaitBlock wb = wbs[i]; if (wb != null) { sws[i]._CancelAcquire(wb, hints[i]); } } StCancelArgs.ThrowIfException(wst); return(false); } } // // All waitables where we inserted wait blocks seem to allow // an immediate acquire operation; so, try to acquire all of // them that are not notification events. // int idx; for (idx = 0; idx < nevts; idx++) { if (!sws[idx]._TryAcquire()) { break; } } // // If all synchronizers were acquired, return success. // if (idx == nevts) { return(true); } // // We failed to acquire all waitables, so undo the acquires // that we did above. // while (--idx >= 0) { sws[idx]._UndoAcquire(); } if (shs != null) { for (int i = 0; i < shs.Length; i++) { shs[i].UndoAcquire(); } } // // If a timeout was specified, adjust the timeout value // that will be used on the next wait. // if (!cargs.AdjustTimeout(ref lastTime)) { return(false); } waitHint = 0; } while (true); }
/// <summary> /// Waits until all of the specified waitables can be acquired, /// activating the specified cancellers. /// </summary> /// <param name="ws"></param> /// <param name="cargs"></param> /// <returns></returns> public static bool WaitAll(StWaitable[] ws, StCancelArgs cargs) { return(WaitAllInternal(ws, null, cargs)); }
public int Park(StCancelArgs cargs) { return(Park(0, cargs)); }
internal static bool WaitAllInternal(StWaitable[] ws, WaitHandle[] hs, StCancelArgs cargs) { if (ws == null) { throw new ArgumentNullException("ws"); } int nevts; int len = ws.Length; StWaitable[] sws = new StWaitable[len]; WaitHandle[] shs = null; int waitHint = SortAndCheckAllowAcquire(ws, sws, out nevts); if (waitHint < 0) { throw new ArgumentException("There are duplicate waitables", "ws"); } if (hs != null) { shs = Sort(hs); if (shs == null) { throw new ArgumentException("There are duplicate wait handles", "hs"); } } if (waitHint != 0 && shs != null && !WaitHandle.WaitAll(shs, 0)) { waitHint = 0; } // // Return success if all synchronizers are notification events and are set. // if (waitHint != 0 && nevts == 0) { return true; } if (waitHint == 0 && cargs.Timeout == 0) { return false; } // // If a timeout was specified, get the current time in order // to adjust the timeout value later, if we re-wait. // int lastTime = (cargs.Timeout != Timeout.Infinite) ? Environment.TickCount : 0; WaitBlock[] wbs = null; WaitBlock[] hints = null; do { if (waitHint == 0) { // // Create the wait block arrays if this is the first time // that we execute the acquire-all prologue. // if (wbs == null) { wbs = new WaitBlock[len]; hints = new WaitBlock[len]; } // // Create a parker for cooperative release, specifying as many // releasers as the number of waitables. The parker because is // not reused because other threads may have references to it. // StParker pk = shs != null ? new StParker(len, EventBasedParkSpotFactory.Current. Create(new WaitAllBehavior(shs))) : new StParker(len); int gsc = 1; int sc = 0; for (int i = 0; i < len; i++) { if ((wbs[i] = sws[i]._WaitAllPrologue(pk, ref hints[i], ref sc)) == null) { if (pk.TryLock()) { pk.UnparkSelf(StParkStatus.StateChange); } } else if (gsc != 0) { if (sc == 0) { gsc = 0; } else if (sc > gsc) { gsc = sc; } } } int wst = pk.Park(gsc, cargs); // // If the wait was cancelled due to timeout, alert or interrupt, // cancel the acquire attempt on all waitables where we actually // inserted wait blocks. // if (wst != StParkStatus.StateChange) { for (int i = 0; i < len; i++) { WaitBlock wb = wbs[i]; if (wb != null) { sws[i]._CancelAcquire(wb, hints[i]); } } StCancelArgs.ThrowIfException(wst); return false; } } // // All waitables where we inserted wait blocks seem to allow // an immediate acquire operation; so, try to acquire all of // them that are not notification events. // int idx; for (idx = 0; idx < nevts; idx++) { if (!sws[idx]._TryAcquire()) { break; } } // // If all synchronizers were acquired, return success. // if (idx == nevts) { return true; } // // We failed to acquire all waitables, so undo the acquires // that we did above. // while (--idx >= 0) { sws[idx]._UndoAcquire(); } if (shs != null) { for (int i = 0; i < shs.Length; i++) { shs[i].UndoAcquire(); } } // // If a timeout was specified, adjust the timeout value // that will be used on the next wait. // if (!cargs.AdjustTimeout(ref lastTime)) { return false; } waitHint = 0; } while (true); }
// // Signals the barrier and then waits until the current phase // completes, activating the specified cancellers. // public bool SignalAndWait(StCancelArgs cargs) { // // Get the current phase state. // PhaseState phs = phState; int s, partners, arrived; do { partners = (s = phs.state) >> PARTNERS_SHIFT; arrived = s & ARRIVED_MASK; if (arrived == partners) { throw new InvalidOperationException("Barrier partners exceeded"); } if (Interlocked.CompareExchange(ref phs.state, s + 1, s) == s) { if (arrived + 1 == partners) { // // This is the last partner thread. So, finish the current // phase and return success. // FinishPhase(); return(true); } break; } } while (true); // // WaitOne on the phase event, activating the specified cancelers. // int ws = phs.waitEvent.Wait(cargs); // // If the event was signalled (i.e., successful synchronization), // return appropiately. // if (ws == StParkStatus.Success) { if (pphActionEx != null) { throw new StBarrierPostPhaseException(pphActionEx); } return(true); } // // The wait was cancelled. So, try to decrement the counter of // arrived partners on our phase, if that is still possible. // do { // // If our partners of our phase already arrived, we must wait // unconditionally on the phase's event, postpone the cancellation // and return normally. // partners = (s = phs.state) >> PARTNERS_SHIFT; arrived = s & ARRIVED_MASK; if (arrived == partners) { phs.waitEvent.Wait(StCancelArgs.None); StCancelArgs.PostponeCancellation(ws); if (pphActionEx != null) { throw new StBarrierPostPhaseException(pphActionEx); } return(true); } // // Try to decrement the counter of arrived partners of our phase. // if (Interlocked.CompareExchange(ref phs.state, s - 1, s) == s) { // // We get out, so report the failure appropriately. // StCancelArgs.ThrowIfException(ws); return(false); } } while (true); }
// // Waits until enter the write lock, activating the specified // cancellers. // public bool TryEnterWrite(StCancelArgs cargs) { // // Try to enter the write lock and, if succeed, return success. // if (TryEnterWriteInternal()) { return true; } // // Return failure, if a null timeout was specified. // if (cargs.Timeout == 0) { return false; } // // Create a wait block and insert it in the r/w lock's queue. // WaitBlock wb = new WaitBlock(WaitType.WaitAny, ENTER_WRITE, StParkStatus.Success); int sc = EnqueueEnterWrite(wb); // // Park the current thread, activating the specified cancellers // and spinning if appropriate. // int ws = wb.parker.Park(sc, cargs); // // If we entered the write lock, return success. // if (ws == StParkStatus.Success) { return true; } // // The request was cancelled; so, cancel the enter write lock // attempt and report the failure appropriately. // CancelAcquire(wb); StCancelArgs.ThrowIfException(ws); return false; }
// // Tries to acquire a busy lock, activating the specified cancellers. // private bool SlowEnter(StCancelArgs cargs) { // // If a timeout was specified, get a time reference in order // to adjust the timeout value if the thread need to re-wait. // int lastTime = (cargs.Timeout != Timeout.Infinite) ? Environment.TickCount : 0; WaitBlock wb = null; do { // // First, try to acquire the lock spinning for the configured // number of cycles, but only if the wait queue is empty. // int sc = spinCount; do { if (state == FREE && Interlocked.CompareExchange(ref state, BUSY, FREE) == FREE) { return true; } if (top != null || sc-- <= 0) { break; } Platform.SpinWait(1); } while (true); // // The lock is busy; so, create a wait block or reset the // one previously created and insert it in the wait queue. // if (wb == null) { wb = new WaitBlock(ACQUIRE); } else { wb.parker.Reset(); } do { WaitBlock t; wb.next = (t = top); if (Interlocked.CompareExchange<WaitBlock>(ref top, wb, t) == t) { break; } } while (true); // // Since that the lock can become free after we inserted // the wait block, we must retry to acquire the lock, if it // seems free. // if (TryEnter()) { return true; } // // Park the current thread, activating the specified cancellers. // int ws = wb.parker.Park(cargs); // // If the acquire attempt was cancelled; so, report the // failure appropriately. // if (ws != StParkStatus.Success) { StCancelArgs.ThrowIfException(ws); return false; } // // Before adjust the timeout value, try to acquire the lock. // if (TryEnter()) { return true; } // // If a timeout was specified, adjust its value taking into // account the elapsed time. // if (!cargs.AdjustTimeout(ref lastTime)) { return false; } } while (true); }
// // Tries to acquire the lock, activating the specified // cancellers. // public bool Enter(StCancelArgs cargs) { if (TryEnter()) { return true; } return (cargs.Timeout != 0) ? SlowEnter(cargs) : false; }
// // Tries to enter the lock, activating the specifed cancellers. // public bool TryEnter(StCancelArgs cargs) { // // First check if the lock is free and, if so, try to acquire it. // int tid = Thread.CurrentThread.ManagedThreadId; if (nrlock.state == StLock.FREE && Interlocked.CompareExchange(ref nrlock.state, StLock.BUSY, StLock.FREE) == StLock.FREE) { // // Set the owner thread, since that a free lock has a zero // recursive acquisition count. // owner = tid; return true; } if (owner == tid) { // // Recursive enter, so increment the recursive acquisition // counter. // count++; return true; } if (cargs.Timeout != 0 && nrlock.Enter(cargs)) { owner = tid; return true; } // // The acquire attempt was cancelled, so return failure. // return false; }
private int SlowWait(StCancelArgs cargs, WaitBlock wb) { do { WaitBlock s; if ((s = state) == SET) { return StParkStatus.Success; } wb.next = s; if (Interlocked.CompareExchange(ref state, wb, s) == s) { break; } } while (true); int ws = wb.parker.Park(wb.next == null ? spinCount : 0, cargs); if (ws != StParkStatus.Success) { Unlink(wb); } return ws; }
// // Writes the specified number of data items to the // stream blocking queue, activating the specified cancellers. // public int Write(T[] buffer, int offset, int count, StCancelArgs cargs) { // // If this is a zero length write, return immediately. // if (count == 0) { return(0); } // // Initialize the local variables. // int remaining = count; WaitNodeQueue <T> wl = new WaitNodeQueue <T>(); int toCopy; // // Acquire the queue's lock. // slock.Enter(); // // If the queue's buffer is full, check if the current // thread must wait. // if (available == length) { goto CheckForWait; } // // If there are waiting readers (i.e., the buffer is empty), // transfer data items transferring directly to the waiting // readers' buffers. // if (!waitQueue.IsEmpty) { do { WaitNode <T> rdw = waitQueue.head; // // Compute the number of data items to transfer to the // waiting reader's buffer and perform the transfer. // if ((toCopy = rdw.remaining) > remaining) { toCopy = remaining; } Array.Copy(buffer, offset, rdw.buffer, rdw.offset, toCopy); rdw.remaining -= toCopy; rdw.offset += toCopy; remaining -= toCopy; offset += toCopy; // // If the waiting reader completes its read operation, // remove its wait node from the wait list and try to // lock the associated parker. // if (rdw.remaining == 0) { waitQueue.Dequeue(); if (rdw.TryLock() && !rdw.UnparkInProgress(StParkStatus.Success)) { wl.Add(rdw); } } else { // // The data items are not enough to satisfy the waiting // reader that is at front of wait queue, so break the loop. // break; } } while (remaining != 0 && !waitQueue.IsEmpty); } // // If we have still data items to write and there is free space // in the queue's buffer, transfer the appropriate number of data // items the queue's buffer. // if (remaining != 0 && available < length) { // // Compute the number of data items that can be copied // to the queue's buffer and perform the transfer. // if ((toCopy = remaining) > (length - available)) { toCopy = length - available; } int t = tail; int tillEnd; if ((tillEnd = length - t) >= toCopy) { Array.Copy(buffer, offset, items, t, toCopy); if ((t += toCopy) >= length) { t = 0; } } else { int fromBegin = toCopy - tillEnd; Array.Copy(buffer, offset, items, t, tillEnd); Array.Copy(buffer, offset + tillEnd, items, 0, fromBegin); t = fromBegin; } // // Update counters and indexes. // tail = t; available += toCopy; remaining -= toCopy; offset += toCopy; } CheckForWait: // // If there are still data items to write, the current thread must // wait if a null timeout wasn't specified. // WaitNode <T> wn = null; bool mustWait; if (mustWait = (remaining != 0 && cargs.Timeout != 0)) { waitQueue.Enqueue(wn = new WaitNode <T>(buffer, offset, remaining)); } // // Release the queue's lock and unpark the readers threads // release above. // slock.Exit(); wl.UnparkAll(); // // If the current thread doesn't need to wait, return the // number of written data items. // if (!mustWait) { return(count - remaining); } // // Park the current thread, activating the specified cancellers. // int ws = wn.Park(cargs); // // If the write was completed, return the number of written // data items. // if (ws == StParkStatus.Success) { return(count); } // // The write was cancelled due to timeout, alert or interrupt. // If the wait node is still inserted in the wait queue, acquire // the queue's lock and unlink it. // if (wn.next != wn) { slock.Enter(); waitQueue.Remove(wn); slock.Exit(); } // // If at least a data item was written, ignore the cancellation // and return the number of transferred data items. // int c; if ((c = count - wn.remaining) != 0) { StCancelArgs.PostponeCancellation(ws); return(c); } // // No data items were written; so, report the failure appropriately. // StCancelArgs.ThrowIfException(ws); return(0); }
// // Signals a waitable and waits on another as an atomic // operation, activating the specified cancellers. // public static bool SignalAndWait(StWaitable tos, StWaitable tow, StCancelArgs cargs) { // // Create a parker to execute the WaitAny prologue on the // *tow* waitable. // StParker pk = new StParker(); WaitBlock hint = null; int sc = 0; WaitBlock wb = tow._WaitAnyPrologue(pk, StParkStatus.Success, ref hint, ref sc); // // Signal the *tos* waitable. // if (!tos._Release()) { // // The signal operation failed. So, try to cancel the parker and, // if successful, cancel the acquire attempt; otherwise, wait until // the thread is unparked and, then, undo the acquire. // if (pk.TryCancel()) { tow._CancelAcquire(wb, hint); } else { pk.Park(); tow._UndoAcquire(); } // // Report the failure appropriately. // throw tos._SignalException; } // // Park the current thread, activating the specified cancellers // and spinning if appropriate. // int ws = pk.Park(sc, cargs); // // If we acquired, execute the WaitOne epilogue and return success. // if (ws == StParkStatus.Success) { tow._WaitEpilogue(); return true; } // // The acquire operation was cancelled; so, cancel the acquire // attempt and report the failure appropriately. // tow._CancelAcquire(wb, hint); StCancelArgs.ThrowIfException(ws); return false; }
/// <summary> /// Waits until one of the specified waitables can be acquired, /// activating the specified cancellers. /// </summary> /// <param name="ws">The array of Waitables.</param> /// <param name="cargs">The cancellation arguments.</param> /// <returns></returns> public static int WaitAny(StWaitable[] ws, StCancelArgs cargs) { if (ws == null) { throw new ArgumentNullException("ws"); } return WaitAnyInternal(ws, null, cargs); }
/// <summary> /// Waits until all of the specified waitables or wait handles can be /// acquired, activating the specified cancellers. /// </summary> /// <param name="ws"></param> /// <param name="hs"></param> /// <param name="cargs"></param> /// <returns></returns> public static bool WaitAll(StWaitable[] ws, WaitHandle[] hs, StCancelArgs cargs) { if (hs == null) { throw new ArgumentNullException("hs"); } if (cargs.Alerter != null) { throw new ArgumentException("Cancellation through the alerter mechanism is not supported", "cargs"); } return WaitAllInternal(ws, hs, cargs); }
public void Wait(StParker pk, StCancelArgs cargs) { bool interrupted = false; int lastTime = (cargs.Timeout != Timeout.Infinite) ? Environment.TickCount : 0; int ws; do { try { ws = waitBehavior.Park(psevent, cargs.Timeout); break; } catch (ThreadInterruptedException) { if (cargs.Interruptible) { ws = StParkStatus.Interrupted; break; } interrupted = true; cargs.AdjustTimeout(ref lastTime); } } while (true); // // If the wait was cancelled due to an internal canceller, try // to cancel the park operation. If we fail, wait unconditionally // until the park spot is signalled. // if (ws != StParkStatus.Success) { if (pk.TryCancel()) { pk.UnparkSelf(waitBehavior.ParkerCancelled(ws)); } else { if (ws == StParkStatus.Interrupted) { interrupted = true; } waitBehavior.ParkerNotCancelled(ws); do { try { psevent.WaitOne(); break; } catch (ThreadInterruptedException) { interrupted = true; } } while (true); } } // // If we were interrupted but can't return the *interrupted* // wait status, reassert the interrupt on the current thread. // if (interrupted) { Thread.CurrentThread.Interrupt(); } factory.Free(this); }
internal static int WaitAnyInternal(StWaitable[] ws, WaitHandle[] hs, StCancelArgs cargs) { int len = ws.Length; // // First, we scan the *ws* array trying to acquire one of the // synchronizers. // for (int i = 0; i < len; i++) { if (ws[i]._TryAcquire()) { return(StParkStatus.Success + i); } } if (cargs.Timeout == 0) { return(StParkStatus.Timeout); } // // Create a parker and execute the WaitAny prologue on all // waitables. We stop executing prologues as soon as we detect // that the acquire operation was accomplished. // StParker pk = hs != null ? new StParker(EventBasedParkSpotFactory.Current. Create(new WaitAnyBehavior(hs, len))) : new StParker(1); WaitBlock[] wbs = new WaitBlock[len]; WaitBlock[] hints = new WaitBlock[len]; int lv = -1; int sc = 0; int gsc = 0; for (int i = 0; !pk.IsLocked && i < len; i++) { StWaitable w = ws[i]; if ((wbs[i] = w._WaitAnyPrologue(pk, i, ref hints[i], ref sc)) == null) { if (pk.TryLock()) { pk.UnparkSelf(i); } else { w._UndoAcquire(); } break; } // // Adjust the global spin count. // if (gsc < sc) { gsc = sc; } lv = i; } int wst = pk.Park(gsc, cargs); StWaitable acq = wst >= StParkStatus.Success && wst < len ? ws[wst] : null; // // Cancel the acquire attempt on all waitables where we executed // the WaitAny prologue, except the one we acquired. // for (int i = 0; i <= lv; i++) { StWaitable w = ws[i]; if (w != acq) { w._CancelAcquire(wbs[i], hints[i]); } } if (wst >= StParkStatus.Success && wst < len + (hs != null ? hs.Length : 0)) { if (acq != null) { acq._WaitEpilogue(); } return(wst); } StCancelArgs.ThrowIfException(wst); return(StParkStatus.Timeout); }
// // Signals the barrier and then waits until the current phase // completes, activating the specified cancellers. // public bool SignalAndWait(StCancelArgs cargs) { // // Get the current phase state. // PhaseState phs = phState; int s, partners, arrived; do { partners = (s = phs.state) >> PARTNERS_SHIFT; arrived = s & ARRIVED_MASK; if (arrived == partners) { throw new InvalidOperationException("Barrier partners exceeded"); } if (Interlocked.CompareExchange(ref phs.state, s + 1, s) == s) { if (arrived + 1 == partners) { // // This is the last partner thread. So, finish the current // phase and return success. // FinishPhase(); return true; } break; } } while (true); // // WaitOne on the phase event, activating the specified cancelers. // int ws = phs.waitEvent.Wait(cargs); // // If the event was signalled (i.e., successful synchronization), // return appropiately. // if (ws == StParkStatus.Success) { if (pphActionEx != null) { throw new StBarrierPostPhaseException(pphActionEx); } return true; } // // The wait was cancelled. So, try to decrement the counter of // arrived partners on our phase, if that is still possible. // do { // // If our partners of our phase already arrived, we must wait // unconditionally on the phase's event, postpone the cancellation // and return normally. // partners = (s = phs.state) >> PARTNERS_SHIFT; arrived = s & ARRIVED_MASK; if (arrived == partners) { phs.waitEvent.Wait(StCancelArgs.None); StCancelArgs.PostponeCancellation(ws); if (pphActionEx != null) { throw new StBarrierPostPhaseException(pphActionEx); } return true; } // // Try to decrement the counter of arrived partners of our phase. // if (Interlocked.CompareExchange(ref phs.state, s - 1, s) == s) { // // We get out, so report the failure appropriately. // StCancelArgs.ThrowIfException(ws); return false; } } while (true); }
public int Park(int spinCount, StCancelArgs cargs) { do { if (state == 0) { return(waitStatus); } if (cargs.Alerter != null && cargs.Alerter.IsSet && TryCancel()) { return(StParkStatus.Alerted); } if (spinCount-- <= 0) { break; } Platform.SpinWait(1); } while (true); if (parkSpot == null) { parkSpot = ThreadExtensions.ForCurrentThread.ParkSpotFactory.Create(); } // // Try to clear the wait-in-progress bit. If the bit was already // cleared, the thread is unparked. // if (!TestAndClearInProgress()) { return(waitStatus); } // // If an alerter was specified, we register the parker with // the alerter before blocking the thread on the park spot. // bool unregister = false; if (cargs.Alerter != null) { if (!(unregister = cargs.Alerter.RegisterParker(this))) { // // The alerter is already set. So, we try to cancel the parker. // if (TryCancel()) { return(StParkStatus.Alerted); } // // We can't cancel the parker because someone else acquired // the count down lock. We must wait unconditionally until // the park spot is set. // cargs = StCancelArgs.None; } } parkSpot.Wait(this, cargs); if (unregister) { cargs.Alerter.DeregisterParker(this); } return(waitStatus); }
internal static int WaitAnyInternal(StWaitable[] ws, WaitHandle[] hs, StCancelArgs cargs) { int len = ws.Length; // // First, we scan the *ws* array trying to acquire one of the // synchronizers. // for (int i = 0; i < len; i++) { if (ws[i]._TryAcquire()) { return StParkStatus.Success + i; } } if (cargs.Timeout == 0) { return StParkStatus.Timeout; } // // Create a parker and execute the WaitAny prologue on all // waitables. We stop executing prologues as soon as we detect // that the acquire operation was accomplished. // StParker pk = hs != null ? new StParker(EventBasedParkSpotFactory.Current. Create(new WaitAnyBehavior(hs, len))) : new StParker(1); WaitBlock[] wbs = new WaitBlock[len]; WaitBlock[] hints = new WaitBlock[len]; int lv = -1; int sc = 0; int gsc = 0; for (int i = 0; !pk.IsLocked && i < len; i++) { StWaitable w = ws[i]; if ((wbs[i] = w._WaitAnyPrologue(pk, i, ref hints[i], ref sc)) == null) { if (pk.TryLock()) { pk.UnparkSelf(i); } else { w._UndoAcquire(); } break; } // // Adjust the global spin count. // if (gsc < sc) { gsc = sc; } lv = i; } int wst = pk.Park(gsc, cargs); StWaitable acq = wst >= StParkStatus.Success && wst < len ? ws[wst] : null; // // Cancel the acquire attempt on all waitables where we executed // the WaitAny prologue, except the one we acquired. // for (int i = 0; i <= lv; i++) { StWaitable w = ws[i]; if (w != acq) { w._CancelAcquire(wbs[i], hints[i]); } } if (wst >= StParkStatus.Success && wst < len + (hs != null ? hs.Length : 0)) { if (acq != null) { acq._WaitEpilogue(); } return wst; } StCancelArgs.ThrowIfException(wst); return StParkStatus.Timeout; }
// // Signals a waitable and waits on another as an atomic // operation, activating the specified cancellers. // public static bool SignalAndWait(StWaitable tos, StWaitable tow, StCancelArgs cargs) { // // Create a parker to execute the WaitAny prologue on the // *tow* waitable. // StParker pk = new StParker(); WaitBlock hint = null; int sc = 0; WaitBlock wb = tow._WaitAnyPrologue(pk, StParkStatus.Success, ref hint, ref sc); // // Signal the *tos* waitable. // if (!tos._Release()) { // // The signal operation failed. So, try to cancel the parker and, // if successful, cancel the acquire attempt; otherwise, wait until // the thread is unparked and, then, undo the acquire. // if (pk.TryCancel()) { tow._CancelAcquire(wb, hint); } else { pk.Park(); tow._UndoAcquire(); } // // Report the failure appropriately. // throw tos._SignalException; } // // Park the current thread, activating the specified cancellers // and spinning if appropriate. // int ws = pk.Park(sc, cargs); // // If we acquired, execute the WaitOne epilogue and return success. // if (ws == StParkStatus.Success) { tow._WaitEpilogue(); return(true); } // // The acquire operation was cancelled; so, cancel the acquire // attempt and report the failure appropriately. // tow._CancelAcquire(wb, hint); StCancelArgs.ThrowIfException(ws); return(false); }
/// <summary> /// Waits until one of the specified waitables or wait handles can be /// acquired, activating the specified cancellers. /// </summary> /// <param name="ws">The array of waitables.</param> /// <param name="hs">The array of wait handles.</param> /// <param name="cargs">The cancellation arguments.</param> /// <returns></returns> public static int WaitAny(StWaitable[] ws, WaitHandle[] hs, StCancelArgs cargs) { if (ws == null) { throw new ArgumentNullException("ws"); } if (hs == null) { throw new ArgumentNullException("hs"); } int len = ws.Length; for (int i = 0; i < hs.Length; i++) { if (hs[i].WaitOne(0)) { return StParkStatus.Success + len + i; } } return WaitAnyInternal(ws, hs, cargs); }
// // Tries to enter the read lock, activating the // specified cancellers. // public bool TryEnterRead(StCancelArgs cargs) { int tid = Thread.CurrentThread.ManagedThreadId; ReaderCounter rc = rdCounts.Lookup(tid); if (!isReentrant) { if (tid == writer) { throw new StLockRecursionException("Read after write not allowed"); } if (rc != null) { throw new StLockRecursionException("Recursive read not allowed"); } } else { // // If this is a recursive enter, increment the recursive // acquisition counter and return. // if (rc != null) { rc.count++; return true; } } // // Acquire the spinlock that protected the r/u/w lock shared state. // slock.Enter(); // // If the current thread is the upgrader, it can also enter // the read lock. So, add an entry to the readers table, // release the spinlock and return success. // if (tid == upgrader) { rdCounts.Add(tid); slock.Exit(); upgraderIsReader = true; return true; } // // The read lock can be entered, if the r/w lock isn't in write // mode and no thread is waiting to enter the writer mode. // If these conditions are met, increment the number of lock // readers, add an entry to the readers table, release the // spinlock and return success. // if (writer == UNOWNED && wrQueue.IsEmpty && upgToWrWaiter == null) { readers++; rdCounts.Add(tid); slock.Exit(); return true; } // // If the r/w lock is reentrant and the current thread is the // current writer, it can also to become a reader. So, increment // the number of lock readers, add an entry to the readers table, // release the spinlock and return success. // if (isReentrant && tid == writer) { readers++; rdCounts.Add(tid); slock.Exit(); return true; } // // The current thread can't enter the read lock immediately. // So, if a null timeout was specified, release the spinlock // and return failure. // if (cargs.Timeout == 0) { slock.Exit(); return false; } // // Create a wait node and insert it in the readers queue. // Compute also the amount of spinning. // int sc = rdQueue.IsEmpty ? spinCount : 0; WaitNode wn; rdQueue.Enqueue(wn = new WaitNode(tid)); // // Release the spinlock and park the current thread, activating // the specified cancellers and spinning if appropriate. // slock.Exit(); int ws = wn.Park(sc, cargs); // // If we entered the read lock, return success. // if (ws == StParkStatus.Success) { return true; } // // The enter attempt was cancelled. So, ensure that the wait node // is unlinked from the queue and report the failure appropriately. // if (wn.next != wn) { slock.Enter(); rdQueue.Remove(wn); slock.Exit(); } StCancelArgs.ThrowIfException(ws); return false; }
internal int Wait(StCancelArgs cargs) { return(state == SET ? StParkStatus.Success : cargs.Timeout == 0 ? StParkStatus.Timeout : SlowWait(cargs, new WaitBlock(WaitType.WaitAny))); }
// // Tries to enter the lock in upgrade read mode, activating // the specified cancellers. // public bool TryEnterUpgradeableRead(StCancelArgs cargs) { int tid = Thread.CurrentThread.ManagedThreadId; ReaderCounter rc = rdCounts.Lookup(tid); if (!isReentrant) { if (tid == upgrader) { throw new StLockRecursionException("Recursive upgrade not allowed"); } if (tid == writer) { throw new StLockRecursionException("Upgrade after write not allowed"); } if (rc != null) { throw new StLockRecursionException("Upgrade after read not allowed"); } } else { // // If the current thread is the current upgrader, increment the // recursive acquisition counter and return. // if (tid == upgrader) { upCount++; return true; } // // If the current thread is the current writer, it can also // becomes the upgrader. If it is also a reader, it will be // accounted as reader on the *upgraderIsReader* flag. // if (tid == writer) { upgrader = tid; upCount = 1; if (rc != null) { upgraderIsReader = true; } return true; } if (rc != null) { throw new StLockRecursionException("Upgrade after read not allowed"); } } // // Acquire the spinlock that protects the r/w lock shared state. // slock.Enter(); // // If the lock isn't in write or upgrade read mode, the // current thread becomes the current upgrader. Then, release // the spinlock and return success. // if (writer == UNOWNED && upgrader == UNOWNED) { upgrader = tid; slock.Exit(); upgraderIsReader = false; upCount = 1; return true; } // // The upgrade read lock can't be acquired immediately. // So, if a null timeout was specified, return failure. // if (cargs.Timeout == 0) { slock.Exit(); return false; } // // Create a wait node and insert it in the upgrader's queue. // int sc = (upQueue.IsEmpty && wrQueue.IsEmpty) ? spinCount : 0; WaitNode wn; upQueue.Enqueue(wn = new WaitNode(tid)); // // Release the spinlock and park the current thread activating // the specified cancellers and spinning, if appropriate. // slock.Exit(); int ws = wn.Park(sc, cargs); // // If we acquired the upgrade lock, initialize the recursive // acquisition count and the *upgraderIsReader flag and return // success. // if (ws == StParkStatus.Success) { upCount = 1; upgraderIsReader = false; return true; } // // The acquire attemptwas cancelled. So, ensure that the // wait node is unlinked from the wait queue and report // the failure appropriately. // if (wn.next != wn) { slock.Enter(); upQueue.Remove(wn); slock.Exit(); } StCancelArgs.ThrowIfException(ws); return false; }
// // Tries to acquire the lock, activating the specified // cancellers. // public bool Enter(StCancelArgs cargs) { return TryEnter() || (cargs.Timeout != 0 ? SlowEnter(cargs) : false); }
public static bool ExchangeAny(StExchanger <T>[] xchgs, T myData, out T yourData, StCancelArgs cargs) { int len = xchgs.Length; for (int i = 0; i < len; i++) { if (xchgs[i].TryExchange(myData, out yourData)) { return(true); } } yourData = default(T); if (cargs.Timeout == 0) { return(false); } var pk = new StParker(1); var wn = new WaitNode(pk, myData); int lv = -1; int gsc = 0; for (int i = 0; !pk.IsLocked && i < len; i++) { StExchanger <T> xchg = xchgs[i]; if (xchg.TryExchange(wn, myData, out yourData)) { break; } // // Adjust the global spin count. // int sc = xchg.spinCount; if (gsc < sc) { gsc = sc; } lv = i; } int wst = pk.Park(gsc, cargs); for (int i = 0; i <= lv; i++) { xchgs[i].CancelExchange(wn); } if (wst == StParkStatus.Success) { return(true); } StCancelArgs.ThrowIfException(wst); return(false); }
public int Park(int spinCount, StCancelArgs cargs) { do { if (state == 0) { return waitStatus; } if (cargs.Alerter != null && cargs.Alerter.IsSet && TryCancel()) { return StParkStatus.Alerted; } if (spinCount-- <= 0) { break; } Platform.SpinWait(1); } while (true); if (parkSpot == null) { parkSpot = ThreadExtensions.ForCurrentThread.ParkSpotFactory.Create(); } // // Try to clear the wait-in-progress bit. If the bit was already // cleared, the thread is unparked. // if (!TestAndClearInProgress()) { return waitStatus; } // // If an alerter was specified, we register the parker with // the alerter before blocking the thread on the park spot. // bool unregister = false; if (cargs.Alerter != null) { if (!(unregister = cargs.Alerter.RegisterParker(this))) { // // The alerter is already set. So, we try to cancel the parker. // if (TryCancel()) { return StParkStatus.Alerted; } // // We can't cancel the parker because someone else acquired // the count down lock. We must wait unconditionally until // the park spot is set. // cargs = StCancelArgs.None; } } parkSpot.Wait(this, cargs); if (unregister) { cargs.Alerter.DeregisterParker(this); } return waitStatus; }
public int Park(StCancelArgs cargs) { return Park(0, cargs); }
public static int Sleep(StCancelArgs cargs) { int ws = new StParker().Park(0, cargs); StCancelArgs.ThrowIfException(ws); return ws; }
public void Wait(StParker pk, StCancelArgs cargs) { bool interrupted = false; int lastTime = (cargs.Timeout != Timeout.Infinite) ? Environment.TickCount : 0; int ws; do { try { ws = waitBehavior.Park(psevent, cargs.Timeout); break; } catch (ThreadInterruptedException) { if (cargs.Interruptible) { ws = StParkStatus.Interrupted; break; } interrupted = true; cargs.AdjustTimeout(ref lastTime); } } while (true); // // If the wait was cancelled due to an internal canceller, try // to cancel the park operation. If we fail, wait unconditionally // until the park spot is signalled. // if (ws != StParkStatus.Success) { if (pk.TryCancel()) { pk.UnparkSelf(waitBehavior.ParkerCancelled(ws)); } else { if (ws == StParkStatus.Interrupted) { interrupted = true; } waitBehavior.ParkerNotCancelled(ws); do { try { psevent.WaitOne(); break; } catch (ThreadInterruptedException) { interrupted = true; } } while (true); } } // // If we were interrupted but can't return the *interrupted* // wait status, reassert the interrupt on the current thread. // if (interrupted) { Thread.CurrentThread.Interrupt(); } factory.Free(this); }
internal int Wait(StCancelArgs cargs) { return state == SET ? StParkStatus.Success : cargs.Timeout == 0 ? StParkStatus.Timeout : SlowWait(cargs, new WaitBlock(WaitType.WaitAny)); }
// // Waits until read the specified number of data items from // the stream queue, activating the specified cancellers. // public int Read(T[] buffer, int offset, int count, StCancelArgs cargs) { // // If this is a zero length read, return immediately. // if (count == 0) { return(0); } // // Initialize the local variables and acquire the queue's lock. // int remaining = count; WaitNodeQueue <T> wl = new WaitNodeQueue <T>(); int toCopy; slock.Enter(); // // If the queue's buffer is empty, check if the current thread // must wait. // if (available == 0) { goto CheckForWait; } // // Compute the number of data items that we can read // from the queue's buffer and perform the transfer. // if ((toCopy = remaining) > available) { toCopy = available; } int h = head; int tillEnd; if ((tillEnd = length - h) >= toCopy) { Array.Copy(items, h, buffer, offset, toCopy); if ((h += toCopy) >= length) { h = 0; } } else { int fromBegin = toCopy - tillEnd; Array.Copy(items, h, buffer, offset, tillEnd); Array.Copy(items, 0, buffer, offset + tillEnd, fromBegin); h = fromBegin; } // // Adjust counters and indexes. // head = h; available -= toCopy; remaining -= toCopy; offset += toCopy; // // If we have still data items to read and there are waiting // writers, transfer the data directly from our buffer to the // waiting writers' buffers. // if (remaining != 0 && !waitQueue.IsEmpty) { do { WaitNode <T> wrw = waitQueue.head; // // Compute the number of data items to transfer to the // waiting writer's buffer and perform the transfer. // if ((toCopy = remaining) > wrw.remaining) { toCopy = wrw.remaining; } Array.Copy(wrw.buffer, wrw.offset, buffer, offset, toCopy); wrw.remaining -= toCopy; wrw.offset += toCopy; remaining -= toCopy; offset += toCopy; // // If the write operation was completed, try to release // the writer thread. // if (wrw.remaining == 0) { waitQueue.Dequeue(); if (wrw.TryLock() && !wrw.UnparkInProgress(StParkStatus.Success)) { wl.Add(wrw); } } else { // // The read is completed, so break the loop. // break; } } while (remaining != 0 && !waitQueue.IsEmpty); } // // If there is available space in the queue's buffer and // waiting writers, try to fill the queue's buffer with // the data of the waiting writers. // if (available < length && !waitQueue.IsEmpty) { do { WaitNode <T> wrw = waitQueue.head; // // Compute the number of data items to copy from the writer's // buffer to the queue's buffer and perform the transfer. // if ((toCopy = wrw.remaining) > (length - available)) { toCopy = length - available; } int t = tail; if ((tillEnd = length - t) >= toCopy) { Array.Copy(wrw.buffer, wrw.offset, items, t, toCopy); if ((t += toCopy) >= length) { t = 0; } } else { int fromBegin = toCopy - tillEnd; Array.Copy(wrw.buffer, wrw.offset, items, t, tillEnd); Array.Copy(wrw.buffer, wrw.offset + tillEnd, items, 0, fromBegin); t = fromBegin; } // // Update counters and indexes. // tail = t; available += toCopy; wrw.remaining -= toCopy; wrw.offset += toCopy; // // If the writer completed its write, release it. // if (wrw.remaining == 0) { waitQueue.Dequeue(); if (wrw.TryLock() && !wrw.UnparkInProgress(StParkStatus.Success)) { wl.Add(wrw); } } else { // // The queue's buffer is full, so break the loop. // break; } } while (available < length && !waitQueue.IsEmpty); } CheckForWait: // // If the read operation was not completed, the current thread // must wait if it didn't read all data items and a null timeout // wasn't specified. // WaitNode <T> wn = null; bool mustWait; if (mustWait = (remaining != 0 && cargs.Timeout != 0)) { waitQueue.Enqueue(wn = new WaitNode <T>(buffer, offset, remaining)); } // // Release the queue's lock and unpark the released waiters. // slock.Exit(); wl.UnparkAll(); // // If the read was completed or the thread specified a null // timeout, return the number of read data items. // if (!mustWait) { return(count - remaining); } // // Park the current thread, activating the specified cancellers. // int ws = wn.Park(cargs); // // If succeed, return the number of data items transferred. // if (ws == StParkStatus.Success) { return(count); } // // The read was cancelled due to timeout, alert or interrupt. // If the wait block is still inserted in the wait queue, acquire // the queue's lock and remove it from the queue. // if (wn.next != wn) { slock.Enter(); waitQueue.Remove(wn); slock.Exit(); } int c; if ((c = count - wn.remaining) != 0) { StCancelArgs.PostponeCancellation(ws); return(c); } // // No data items were transferred, so report the failure // appropriately. // StCancelArgs.ThrowIfException(ws); return(0); }
// // 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; }