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); }
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); }
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); }
// // 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); }
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 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); }
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); }