//
        // 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);
        }
Пример #2
0
        //
        // 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);
        }