// // 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 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); }
/*++ * * 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); }
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); }
// // The timer thread. // private static void TimerThread() { // // The timer thread is a background thread. // Thread.CurrentThread.IsBackground = true; Thread.CurrentThread.Name = "StTimers"; do { // // Acquire the timer list lock. // _lock.Enter(); // // If the limit timer was activated, remove it from the timer list. // if (limitTimer.next != limitTimer) { if (limitTimer.next != timerListHead) { limitTimer.next.delay += limitTimer.delay; } RemoveTimerFromList(limitTimer); limitTimer.next = limitTimer; } // // Adjust the base time and the timer list and process // expired timers. // AdjustBaseTime(); // // Initializes the parker and compute the time at which the // front timer must expire. // parker.Reset(1); // // If the first timer ... // RawTimer first = timerListHead.next; int btime = baseTime; int delay; if ((delay = first.delay) > MAXIMUM_SLEEP_TIME) { limitTimer.delay = MAXIMUM_SLEEP_TIME; InsertHeadTimerList(timerListHead, limitTimer); if (first != timerListHead) { first.delay -= MAXIMUM_SLEEP_TIME; } delay = MAXIMUM_SLEEP_TIME; } // // Get the fired timers list and empty it. // RawTimer fired = TimerList.firedTimers; TimerList.firedTimers = null; // // Release the timer list's lock. // _lock.Exit(); // // Call unpark method on the expired timer's parkers. // while (fired != null) { RawTimer next = fired.prev; fired.parker.Unpark(StParkStatus.Timeout); fired = next; } // // Since that the timer thread can take significant time to execute // the timer's callbacks, we must ajust the *delay*, if needed. // int sliding; if ((sliding = Environment.TickCount - btime) != 0) { delay = (sliding >= delay) ? 0 : (delay - sliding); } // // Park the timer thread until the next timer expires or a new // timer is inserted at front of the timer list. // parker.Park(new StCancelArgs(delay)); } while (true); // // We never get here! // }
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); }
// // Unregisters the registered take. // public bool Unregister() { // // If the unregister is being called from the callback method, // we just set the *onlyOnce* to *true* and return. // if (cbtid == Thread.CurrentThread.ManagedThreadId) { executeOnce = true; return(true); } // // If the take is registered, we try to unregister it, and return // only after the wait is actually unregistered. // If the take was already unregistered or an unregister is taking // place, this method returns false. // StSpinWait spinner = new StSpinWait(); StParker pk = new StParker(0); StParker oldState; do { if ((oldState = state) == INACTIVE) { return(false); } if (oldState == ACTIVE) { if (Interlocked.CompareExchange <StParker>(ref state, pk, ACTIVE) == ACTIVE) { break; } } else if (!(oldState is SentinelParker)) { return(false); } spinner.SpinOnce(); } while (true); // // Try to cancel the callback parker. If we succeed, call the unpark // with status cancelled. Otherwise, a callback is taking place and // we must wait until its completion. // if (cbparker.TryCancel()) { cbparker.Unpark(StParkStatus.TakeCancelled); } else { pk.Park(BUSY_SPINS, StCancelArgs.None); } // // Set the registered take object to inactive and return success. // state = INACTIVE; return(true); }
// // 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); }
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); }
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); }
// // Cancels the timer. // public bool Cancel() { // // If the timer is being cancelled from the user callback function, // set the period to zero and return success. The timer will be // cancelled on return from the callback function. // if (cbtid == Thread.CurrentThread.ManagedThreadId) { period = 0; return(true); } // // If the timer is active we must try to cancel the timer // and return only after the timer is actually cancelled. // if the timer is already inactive or a cancel or a set is taking // place, this function returns FALSE. // StSpinWait spinner = new StSpinWait(); StParker pk = new StParker(0); StParker oldState; do { if ((oldState = state) == INACTIVE) { return(false); } if (oldState == ACTIVE) { if (Interlocked.CompareExchange <StParker>(ref state, pk, ACTIVE) == ACTIVE) { break; } } if (!(oldState is SentinelParker)) { return(false); } spinner.SpinOnce(); } while (true); // // Try to cancel the timer's callback parker. If we can't // park the current thread until the timer callback finishes // execution. // if (cbparker.TryCancel()) { cbparker.Unpark(StParkStatus.TimerCancelled); } else { pk.Park(100, StCancelArgs.None); } // // Set the timer state to inactive and return success. // state = INACTIVE; return(true); }
// // Sets the timer. // public bool Set(int dueTime, int period, WaitOrTimerCallback callback, object cbState) { // // If the timer is being set from the user callback function, // we just save the new settings and return success. // if (cbtid == Thread.CurrentThread.ManagedThreadId) { this.dueTime = dueTime; this.period = period; useDueTime = true; this.callback = callback; this.cbState = cbState; return(true); } // // The timer is being set externally. So, we must first cancel the // timer. If the timer is already being set or cancelled, we return // failure. // StSpinWait spinner = new StSpinWait(); StParker pk = new StParker(0); StParker oldState; do { if ((oldState = state) == INACTIVE) { if (Interlocked.CompareExchange <StParker>(ref state, SETTING, INACTIVE) == INACTIVE) { goto SetTimer; } } else if (oldState == ACTIVE) { if (Interlocked.CompareExchange <StParker>(ref state, pk, ACTIVE) == ACTIVE) { break; } } else if (!(oldState is SentinelParker)) { return(false); } spinner.SpinOnce(); } while (true); // // Try to cancel the timer's callback parker. If succeed, // call the unpark method; otherwise, the timer callback is // taking place, so we must synchronize with its end. // if (cbparker.TryCancel()) { cbparker.Unpark(StParkStatus.TimerCancelled); } else { pk.Park(100, StCancelArgs.None); } // // Here, we know that the timer is cancelled and no one else // is trying to set or cancel the timer. // So, set the timer state to *our busy state* and start it with // the new settings. // state = SETTING; SetTimer: this.dueTime = dueTime; this.period = period; useDueTime = false; this.callback = callback; this.cbState = cbState; StNotificationEvent nev = tmrEvent as StNotificationEvent; if (nev != null) { nev.Reset(); } else { ((StSynchronizationEvent)tmrEvent).Reset(); } // // Initialize the timer's parker, set the timer state to ACTIVE // and enable the unpark callback. // cbparker.Reset(); state = ACTIVE; int ws = cbparker.EnableCallback(dueTime, timer); if (ws != StParkStatus.Pending) { // // If the timer already fired or cancelled, call the unpark // callback inline. // TimerCallback(ws); } return(true); }
// // Tries to take a data item from the specified subset of queues, // defined by offset and count, activating the specified cancellers. // public static int TryTakeAny(StBlockingQueue <T>[] qs, int offset, int count, out T di, StCancelArgs cargs) { int def = 0; int len = qs.Length; // // Try to take a data item immediately from one of the specified queues. // for (int j = offset, i = 0; i < count; i++) { StBlockingQueue <T> q = qs[j]; if (q != null) { if (q.TryTake(out di)) { return(StParkStatus.Success + j); } def++; } if (++j >= len) { j = 0; } } // // If the *qs* array contains only null references, throw the // ArgumentException. // if (def == 0) { throw new ArgumentException("qs: array contains only null references"); } // // None of the specified queues allows an immediate take operation. // So, return failure if a null timeout was specified. // di = default(T); if (cargs.Timeout == 0) { return(StParkStatus.Timeout); } // // Create a parker and execute the take-any prologue on the // queues; the loop is exited when we detect that the take-any // operation was satisfied. // StParker pk = new StParker(); WaitNode[] wns = new WaitNode[len]; WaitNode[] hints = new WaitNode[len]; int lv = -1; for (int j = offset, i = 0; !pk.IsLocked && i < count; i++) { StBlockingQueue <T> q = qs[j]; if (q != null) { if ((wns[j] = q.TryTakePrologue(pk, (StParkStatus.Success + j), out di, ref hints[j])) == null) { break; } lv = j; } if (++j >= len) { j = 0; } } // // Park the current thread, activating the specified cancellers. // int ws = pk.Park(cargs); // // If the take-any operation succeed, compute the index of the // queue where we the data item was taken, retrive the data item // and execute the take epilogue, if needed. // int ti = -1; if (ws >= StParkStatus.Success) { ti = ws - StParkStatus.Success; if (wns[ti] != null) { di = wns[ti].channel; qs[ti].TakeEpilogue(); } } // // Cancel the take attempt on all queues where we inserted // wait blocks, except the one where we retrieved the data item. // for (int j = offset, i = 0; i < count; i++) { WaitNode wn; if (j != ti && (wn = wns[j]) != null) { qs[j].CancelTakeAttempt(wn, hints[j]); } if (j == lv) { break; } if (++j >= len) { j = 0; } } // // Return success or failure appropriately. // if (ti != -1) { return(ws); } StCancelArgs.ThrowIfException(ws); return(StParkStatus.Timeout); }