예제 #1
0
        //
        // 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);
        }
예제 #3
0
        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);
        }
예제 #4
0
        //
        // Cancels the specified acquire attempt.
        //

        internal override void _CancelAcquire(WaitBlock wb, WaitBlock hint)
        {
            tmrEvent._CancelAcquire(wb, hint);
        }