// // 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); }
// // Executes the unpark callback. // private void UnparkCallback(int ws) { Debug.Assert(ws == StParkStatus.Success || ws == StParkStatus.Timeout || ws == StParkStatus.WaitCancelled); // // If the registered wait was cancelled, cancel the acquire // attempt and return immediately. // if (ws == StParkStatus.WaitCancelled) { waitable._CancelAcquire(waitBlock, hint); return; } // // Set state to *our busy* grabing the current state, and execute // the unpark callback processing. // StParker myBusy = new SentinelParker(); StParker oldState = Interlocked.Exchange <StParker>(ref state, myBusy); do { // // If the acquire operation was cancelled, cancel the acquire // attempt on the waitable. // if (ws != StParkStatus.Success) { waitable._CancelAcquire(waitBlock, hint); } // // Execute the user callback routine. // cbtid = Thread.CurrentThread.ManagedThreadId; callback(cbState, ws == StParkStatus.Timeout); cbtid = 0; // // If the registered wait was configured to execute once or // there is an unregister in progress, set the state to INACTIVE. // If a thread is waiting to unregister, unpark it. // if (executeOnce || !(oldState is SentinelParker)) { if (!(oldState is SentinelParker)) { oldState.Unpark(StParkStatus.Success); } else { state = INACTIVE; } return; } // // We must re-register with the Waitable. // So, initialize the parker and execute the WaitAny prologue. // cbparker.Reset(1); int ignored = 0; waitBlock = waitable._WaitAnyPrologue(cbparker, StParkStatus.Success, ref hint, ref ignored); // // Enable the unpark callback. // ws = cbparker.EnableCallback(timeout, toTimer); if (ws == StParkStatus.Pending) { // // If the *state* field constains still *my busy* set it to ACTIVE. // if (state == myBusy) { Interlocked.CompareExchange <StParker>(ref state, ACTIVE, myBusy); } return; } // // The waitable was already signalled. So, execute the unpark // callback inline. // } 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 specified acquire attempt. // internal override void _CancelAcquire(WaitBlock wb, WaitBlock hint) { tmrEvent._CancelAcquire(wb, hint); }