public bool Acquire(int id, StCancelArgs cargs) { m.Enter(); try { if (permits >= id) { permits -= id; return(true); } while (true) { int lastTime = Environment.TickCount; cv.Wait(cargs); if (permits >= id) { permits -= id; return(true); } if (!cargs.AdjustTimeout(ref lastTime)) { return(false); } } } finally { m.Exit(); } }
public bool Offer(T data, StCancelArgs cargs) { m.WaitOne(); try { if (buffer.Count < capacity) { buffer.Enqueue(data); nonEmpty.Pulse(); return(true); } while (true) { int lastTime = Environment.TickCount; nonFull.Wait(cargs); if (buffer.Count < capacity) { buffer.Enqueue(data); nonEmpty.Pulse(); return(true); } if (!cargs.AdjustTimeout(ref lastTime)) { return(false); } } } finally { m.Exit(); } }
public bool Poll(out T di, StCancelArgs cargs) { m.WaitOne(); try { if (buffer.Count > 0) { di = buffer.Dequeue(); nonFull.Pulse(); return(true); } while (true) { int lastTime = Environment.TickCount; nonEmpty.Wait(cargs); if (buffer.Count > 0) { di = buffer.Dequeue(); nonFull.Pulse(); return(true); } if (!cargs.AdjustTimeout(ref lastTime)) { di = default(T); return(false); } } } finally { m.Exit(); } }
internal bool SlowEnter (StCancelArgs cargs) { int lastTime = (cargs.Timeout != Timeout.Infinite) ? Environment.TickCount : 0; StWaitBlock wb = null; do { int sc = spinCount; #if NET_4_0 var spinWait = new SpinWait (); #endif do { if (state == FREE && Interlocked.CompareExchange (ref state, BUSY, FREE) == FREE) { return true; } if (top != null || sc-- <= 0) { break; } #if NET_4_0 spinWait.SpinOnce (); #else Thread.SpinWait (1); #endif } while (true); if (wb == null) { wb = new StWaitBlock (1); } else { wb.parker.Reset (); } do { StWaitBlock t; wb.next = t = top; if (Interlocked.CompareExchange (ref top, wb, t) == t) { break; } } while (true); if (TryEnter ()) { wb.parker.SelfCancel (); return true; } int ws = wb.parker.Park (cargs); if (ws != StParkStatus.Success) { cargs.ThrowIfException (ws); return false; } if (TryEnter ()) { return true; } if (!cargs.AdjustTimeout (ref lastTime)) { return false; } } while (true); }
internal static bool WaitAll (StWaitable[] ws, StCancelArgs cargs) { if (ws == null) { throw new ArgumentNullException ("ws"); } int nevts; int len = ws.Length; var sws = new StWaitable [len]; int waitHint = SortAndCheckAllowAcquire (ws, sws, out nevts); if (waitHint < 0) { throw new DuplicateWaitObjectException (); } /* * Return success if all synchronizers are notification events and are set. */ if (waitHint != 0) { if (nevts == 0) { return true; } } else if (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; StWaitBlock[] wbs = null; StWaitBlock[] hints = null; do { int inflated = 0; AbandonedMutexException ame = null; if (waitHint == 0) { if (wbs == null) { wbs = new StWaitBlock [len]; hints = new StWaitBlock [len]; } /* * Create a parker for cooperative release, specifying as many * releasers as the number of waitables. The parker is not reused * because other threads may have references to it. */ var pk = new StParker (len); int inflatedCount = 0; 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 (hints [i] == INFLATED) { inflated |= 1 << i; inflatedCount += 1; } else if (pk.TryLock ()) { pk.UnparkSelf (StParkStatus.StateChange); } } else if (gsc != 0) { if (sc == 0) { gsc = 0; } else if (sc > gsc) { gsc = sc; } } } if (inflatedCount > 0 && pk.TryLock (inflatedCount)) { pk.UnparkSelf (StParkStatus.StateChange); } int wst = pk.Park (gsc, cargs); /* * We opt for a less efficient but simpler implementation instead * of using the same approach as the WaitAny operation, because: * - When parking, the thread would have to call into the park spot * even if it was already unparked, since we have to wait for the * other handles as well; * - We would have to deal with cancellation in a different way, * relying on interrupts instead of the TryCancel/Unpark pair; * - The Unpark operation might not wake the target thread, which * could lead to bugs. */ if (wst == StParkStatus.StateChange && inflatedCount > 0) { if (!cargs.AdjustTimeout (ref lastTime)) { return false; } wst = InflatedWaitMultiple (ws, true, inflated, inflatedCount, cargs); } if (wst != StParkStatus.StateChange) { for (int i = 0; i < len; i++) { StWaitBlock wb = wbs [i]; if (wb != null) { sws [i]._CancelAcquire (wb, hints [i]); } } if (wst == StParkStatus.Inflated) { waitHint = 0; continue; } cargs.ThrowIfException (wst); return false; } } /* * All waitables where we inserted wait blocks seem to allow an * immediate acquire operation; so, try to acquire all non-inflated * waitables that are not notification events. */ int idx; for (idx = 0; idx < nevts; idx++) { try { if ((inflated & (1 << idx)) == 0 && !sws[idx]._TryAcquire()) { break; } } catch (AbandonedMutexException e) { ame = e; ame.MutexIndex = idx; } } if (idx == nevts) { if (ame != null) { throw ame; } return true; } /* * We failed to acquire all waitables, so undo the acquires * that we did above. */ for (int i = idx + 1; i < nevts; ++i) { if ((inflated & (1 << idx)) != 0) { sws[i]._UndoAcquire (); } } while (--idx >= 0) { sws[idx]._UndoAcquire (); } if (!cargs.AdjustTimeout (ref lastTime)) { return false; } waitHint = 0; } while (true); }