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