//
        // 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);
        }
        //
        // Executes the unpark callback.
        //

        private void UnparkCallback(int ws)
        {
            Debug.Assert(ws == StParkStatus.Success || ws == StParkStatus.Timeout ||
                         ws == StParkStatus.TakeCancelled);

            //
            // If the registered take was cancelled, cancel the take attempt
            // and return immediately.
            //

            if (ws == StParkStatus.TakeCancelled)
            {
                queue.CancelTakeAttempt(waitNode, hint);
                return;
            }

            //
            // Set state to *our busy*, grabing the current state.
            //

            StParker myBusy   = new SentinelParker();
            StParker oldState = Interlocked.Exchange <StParker>(ref state, myBusy);

            do
            {
                //
                // If the take operation succeeded, execute the take epilogue;
                // otherwise, cancel the take attempt.
                //

                if (ws == StParkStatus.Success)
                {
                    queue.TakeEpilogue();
                }
                else
                {
                    queue.CancelTakeAttempt(waitNode, hint);
                }

                //
                // Execute the user callback routine.
                //

                cbtid = Thread.CurrentThread.ManagedThreadId;
                callback(cbState, waitNode == null ? dataItem : waitNode.channel,
                         ws == StParkStatus.Timeout);
                cbtid = 0;

                //
                // If the registered take 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 queue.
                // So, initialize the parker and execute the TakeAny prologue.
                //

                cbparker.Reset();
                waitNode = queue.TryTakePrologue(cbparker, StParkStatus.Success, out dataItem,
                                                 ref hint);

                //
                // Enable the unpark callback.
                //

                if ((ws = cbparker.EnableCallback(timeout, toTimer)) == StParkStatus.Pending)
                {
                    //
                    // If the *state* field is still *my busy* set it to ACTIVE;
                    // anyway, return.
                    //

                    if (state == myBusy)
                    {
                        Interlocked.CompareExchange <StParker>(ref state, ACTIVE, myBusy);
                    }
                    return;
                }

                //
                // The take was already accomplished; so, to prevent uncontrolled
                // reentrancy execute the unpark callback inline.
                //
            } while (true);
        }
Beispiel #3
0
        //
        // Executes the timer callback
        //

        internal void TimerCallback(int ws)
        {
            Debug.Assert(ws == StParkStatus.Timeout || ws == StParkStatus.TimerCancelled);

            //
            // If the timer was cancelled, return immediately.
            //

            if (ws == StParkStatus.TimerCancelled)
            {
                return;
            }

            //
            // Set timer state to *our busy* state, grabing the current state and
            // execute the timer callback processing.
            //

            SentinelParker myBusy   = new SentinelParker();
            StParker       oldState = Interlocked.Exchange <StParker>(ref state, myBusy);

            do
            {
                //
                // Signals the timer's event.
                //

                tmrEvent.Signal();

                //
                // Call the user-defined callback, if specified.
                //

                if (callback != null)
                {
                    cbtid = Thread.CurrentThread.ManagedThreadId;
                    callback(cbState, true);
                    cbtid = 0;
                }

                //
                // If the  timer isn't periodic or if someone is trying to
                // cancel it, process cancellation.
                //

                if (period == 0 || !(oldState is SentinelParker))
                {
                    if (!(oldState is SentinelParker))
                    {
                        oldState.Unpark(StParkStatus.Success);
                    }
                    else
                    {
                        state = INACTIVE;
                    }
                    return;
                }

                //
                // Initialize the timer's parker.
                //

                cbparker.Reset();

                //
                // Compute the timer delay and enable the unpark callback.
                //

                int timeout;
                if (useDueTime)
                {
                    timeout    = dueTime;
                    useDueTime = false;
                }
                else
                {
                    timeout = period | (1 << 31);
                }
                if ((ws = cbparker.EnableCallback(timeout, timer)) == StParkStatus.Pending)
                {
                    if (state == myBusy)
                    {
                        Interlocked.CompareExchange <StParker>(ref state, ACTIVE, myBusy);
                    }
                    return;
                }

                //
                // The timer already expired. So, execute the timer
                // callback inline.
                //
            } while (true);
        }