//
        // Waits until the synchronizer allows the acquire, activating
        // the specified cancellers.
        //

        public bool WaitOne(StCancelArgs cargs)
        {
            if (_TryAcquire())
            {
                return(true);
            }

            if (cargs.Timeout == 0)
            {
                return(false);
            }

            var       pk   = new StParker();
            WaitBlock hint = null;
            int       sc   = 0;
            WaitBlock wb;

            if ((wb = _WaitAnyPrologue(pk, StParkStatus.Success, ref hint, ref sc)) == null)
            {
                return(true);
            }

            int ws = pk.Park(sc, cargs);

            if (ws == StParkStatus.Success)
            {
                _WaitEpilogue();
                return(true);
            }

            _CancelAcquire(wb, hint);
            StCancelArgs.ThrowIfException(ws);
            return(false);
        }
        //
        // Exchanges a data item, activating the specified cancellers.
        //

        public bool Exchange(T myData, out T yourData, StCancelArgs cargs)
        {
            if (TryExchange(myData, out yourData))
            {
                return(true);
            }

            var pk = new StParker();
            var wn = new WaitNode(pk, myData);

            if (TryExchange(wn, myData, out yourData))
            {
                return(true);
            }

            int ws = pk.Park(spinCount, cargs);

            if (ws == StParkStatus.Success)
            {
                yourData = wn.Channel;
                return(true);
            }

            CancelExchange(wn);
            StCancelArgs.ThrowIfException(ws);
            return(false);
        }
示例#3
0
        //
        // Tries to take a data item from the queue, activating the
        // specified cancellers.
        //

        public bool TryTake(out T di, StCancelArgs cargs)
        {
            if (TryTake(out di))
            {
                return(true);
            }
            if (cargs.Timeout == 0)
            {
                return(false);
            }
            StParker pk = new StParker();
            WaitNode wn, hint = null;

            if ((wn = TryTakePrologue(pk, StParkStatus.Success, out di, ref hint)) == null)
            {
                return(true);
            }
            int ws = pk.Park(cargs);

            if (ws == StParkStatus.Success)
            {
                TakeEpilogue();
                di = wn.channel;
                return(true);
            }

            //
            // The take was cancelled; so, cancel the take attempt and
            // report the failure appropriately.
            //

            CancelTakeAttempt(wn, hint);
            StCancelArgs.ThrowIfException(ws);
            return(false);
        }
示例#4
0
        /*++
         *
         * Generic API
         *
         * --*/

        //
        // Tries to add a data item to the queue, activating the specified
        // cancellers.
        //

        public bool TryAdd(T di, StCancelArgs cargs)
        {
            if (TryAdd(di))
            {
                return(true);
            }
            if (cargs.Timeout == 0)
            {
                return(false);
            }
            WaitNode hint = null;
            WaitNode wn;
            StParker pk = new StParker();

            if ((wn = TryAddPrologue(pk, StParkStatus.Success, di, ref hint)) == null)
            {
                return(true);
            }
            int ws = pk.Park(cargs);

            if (ws == StParkStatus.Success)
            {
                return(true);
            }

            //
            // The add operation was cancelled; so, cancel the add attempt
            // and report the failure appropriately.
            //

            CancelAddAttempt(wn, hint);
            StCancelArgs.ThrowIfException(ws);
            return(false);
        }
        private bool SlowTryInit(int spinCount)
        {
            StParker s;

            do
            {
                if ((s = state) == FREE &&
                    Interlocked.CompareExchange(ref state, BUSY, FREE) == FREE)
                {
                    return(true);
                }
                if (s == AVAILABLE)
                {
                    return(false);
                }
                if (spinCount-- <= 0)
                {
                    break;
                }
                Platform.SpinWait(1);
            } while (true);

            //
            // The initialization is taking place. So, create a locked parker
            // and insert it in the wait queue, if the lock remains busy.
            //

            var pk = new StParker(0);

            do
            {
                if ((s = state) == FREE &&
                    Interlocked.CompareExchange(ref state, BUSY, FREE) == FREE)
                {
                    return(true);
                }
                if (s == AVAILABLE)
                {
                    return(false);
                }

                pk.pnext = s;
                if (Interlocked.CompareExchange(ref state, pk, s) == s)
                {
                    break;
                }
            } while (true);

            return(pk.Park() == STATUS_INIT);
        }
示例#6
0
        //
        // The timer thread.
        //

        private static void TimerThread()
        {
            //
            // The timer thread is a background thread.
            //

            Thread.CurrentThread.IsBackground = true;
            Thread.CurrentThread.Name         = "StTimers";

            do
            {
                //
                // Acquire the timer list lock.
                //

                _lock.Enter();

                //
                // If the limit timer was activated, remove it from the timer list.
                //

                if (limitTimer.next != limitTimer)
                {
                    if (limitTimer.next != timerListHead)
                    {
                        limitTimer.next.delay += limitTimer.delay;
                    }
                    RemoveTimerFromList(limitTimer);
                    limitTimer.next = limitTimer;
                }

                //
                // Adjust the base time and the timer list and process
                // expired timers.
                //

                AdjustBaseTime();

                //
                // Initializes the parker and compute the time at which the
                // front timer must expire.
                //

                parker.Reset(1);

                //
                // If the first timer ...
                //

                RawTimer first = timerListHead.next;
                int      btime = baseTime;
                int      delay;

                if ((delay = first.delay) > MAXIMUM_SLEEP_TIME)
                {
                    limitTimer.delay = MAXIMUM_SLEEP_TIME;
                    InsertHeadTimerList(timerListHead, limitTimer);
                    if (first != timerListHead)
                    {
                        first.delay -= MAXIMUM_SLEEP_TIME;
                    }
                    delay = MAXIMUM_SLEEP_TIME;
                }

                //
                // Get the fired timers list and empty it.
                //

                RawTimer fired = TimerList.firedTimers;
                TimerList.firedTimers = null;

                //
                // Release the timer list's lock.
                //

                _lock.Exit();

                //
                // Call unpark method on the expired timer's parkers.
                //

                while (fired != null)
                {
                    RawTimer next = fired.prev;
                    fired.parker.Unpark(StParkStatus.Timeout);
                    fired = next;
                }

                //
                // Since that the timer thread can take significant time to execute
                // the timer's callbacks, we must ajust the *delay*, if needed.
                //

                int sliding;
                if ((sliding = Environment.TickCount - btime) != 0)
                {
                    delay = (sliding >= delay) ? 0 : (delay - sliding);
                }

                //
                // Park the timer thread until the next timer expires or a new
                // timer is inserted at front of the timer list.
                //

                parker.Park(new StCancelArgs(delay));
            } while (true);

            //
            // We never get here!
            //
        }
        public static bool ExchangeAny(StExchanger <T>[] xchgs, T myData, out T yourData, StCancelArgs cargs)
        {
            int len = xchgs.Length;

            for (int i = 0; i < len; i++)
            {
                if (xchgs[i].TryExchange(myData, out yourData))
                {
                    return(true);
                }
            }

            yourData = default(T);

            if (cargs.Timeout == 0)
            {
                return(false);
            }

            var pk  = new StParker(1);
            var wn  = new WaitNode(pk, myData);
            int lv  = -1;
            int gsc = 0;

            for (int i = 0; !pk.IsLocked && i < len; i++)
            {
                StExchanger <T> xchg = xchgs[i];

                if (xchg.TryExchange(wn, myData, out yourData))
                {
                    break;
                }

                //
                // Adjust the global spin count.
                //

                int sc = xchg.spinCount;
                if (gsc < sc)
                {
                    gsc = sc;
                }

                lv = i;
            }

            int wst = pk.Park(gsc, cargs);

            for (int i = 0; i <= lv; i++)
            {
                xchgs[i].CancelExchange(wn);
            }

            if (wst == StParkStatus.Success)
            {
                return(true);
            }

            StCancelArgs.ThrowIfException(wst);
            return(false);
        }
        //
        // 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);
        }
        //
        // 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);
        }
        internal static bool WaitAllInternal(StWaitable[] ws, WaitHandle[] hs, StCancelArgs cargs)
        {
            if (ws == null)
            {
                throw new ArgumentNullException("ws");
            }

            int nevts;
            int len = ws.Length;

            StWaitable[] sws = new StWaitable[len];
            WaitHandle[] shs = null;

            int waitHint = SortAndCheckAllowAcquire(ws, sws, out nevts);

            if (waitHint < 0)
            {
                throw new ArgumentException("There are duplicate waitables", "ws");
            }

            if (hs != null)
            {
                shs = Sort(hs);
                if (shs == null)
                {
                    throw new ArgumentException("There are duplicate wait handles", "hs");
                }
            }

            if (waitHint != 0 && shs != null && !WaitHandle.WaitAll(shs, 0))
            {
                waitHint = 0;
            }

            //
            // Return success if all synchronizers are notification events and are set.
            //

            if (waitHint != 0 && nevts == 0)
            {
                return(true);
            }

            if (waitHint == 0 && cargs.Timeout == 0)
            {
                return(false);
            }

            //
            // If a timeout was specified, get the current time in order
            // to adjust the timeout value later, if we re-wait.
            //

            int lastTime = (cargs.Timeout != Timeout.Infinite) ? Environment.TickCount : 0;

            WaitBlock[] wbs   = null;
            WaitBlock[] hints = null;
            do
            {
                if (waitHint == 0)
                {
                    //
                    // Create the wait block arrays if this is the first time
                    // that we execute the acquire-all prologue.
                    //

                    if (wbs == null)
                    {
                        wbs   = new WaitBlock[len];
                        hints = new WaitBlock[len];
                    }

                    //
                    // Create a parker for cooperative release, specifying as many
                    // releasers as the number of waitables. The parker because is
                    // not reused because other threads may have references to it.
                    //

                    StParker pk = shs != null
                                ? new StParker(len, EventBasedParkSpotFactory.Current.
                                               Create(new WaitAllBehavior(shs)))
                                : new StParker(len);

                    int gsc = 1;
                    int sc  = 0;
                    for (int i = 0; i < len; i++)
                    {
                        if ((wbs[i] = sws[i]._WaitAllPrologue(pk, ref hints[i], ref sc)) == null)
                        {
                            if (pk.TryLock())
                            {
                                pk.UnparkSelf(StParkStatus.StateChange);
                            }
                        }
                        else if (gsc != 0)
                        {
                            if (sc == 0)
                            {
                                gsc = 0;
                            }
                            else if (sc > gsc)
                            {
                                gsc = sc;
                            }
                        }
                    }

                    int wst = pk.Park(gsc, cargs);

                    //
                    // If the wait was cancelled due to timeout, alert or interrupt,
                    // cancel the acquire attempt on all waitables where we actually
                    // inserted wait blocks.
                    //

                    if (wst != StParkStatus.StateChange)
                    {
                        for (int i = 0; i < len; i++)
                        {
                            WaitBlock wb = wbs[i];
                            if (wb != null)
                            {
                                sws[i]._CancelAcquire(wb, hints[i]);
                            }
                        }

                        StCancelArgs.ThrowIfException(wst);
                        return(false);
                    }
                }

                //
                // All waitables where we inserted wait blocks seem to allow
                // an immediate acquire operation; so, try to acquire all of
                // them that are not notification events.
                //

                int idx;
                for (idx = 0; idx < nevts; idx++)
                {
                    if (!sws[idx]._TryAcquire())
                    {
                        break;
                    }
                }

                //
                // If all synchronizers were acquired, return success.
                //

                if (idx == nevts)
                {
                    return(true);
                }

                //
                // We failed to acquire all waitables, so undo the acquires
                // that we did above.
                //

                while (--idx >= 0)
                {
                    sws[idx]._UndoAcquire();
                }

                if (shs != null)
                {
                    for (int i = 0; i < shs.Length; i++)
                    {
                        shs[i].UndoAcquire();
                    }
                }

                //
                // If a timeout was specified, adjust the timeout value
                // that will be used on the next wait.
                //

                if (!cargs.AdjustTimeout(ref lastTime))
                {
                    return(false);
                }

                waitHint = 0;
            } 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);
        }
示例#12
0
        //
        // Cancels the timer.
        //

        public bool Cancel()
        {
            //
            // If the timer is being cancelled from the user callback function,
            // set the period to zero and return success. The timer will be
            // cancelled on return from the callback function.
            //

            if (cbtid == Thread.CurrentThread.ManagedThreadId)
            {
                period = 0;
                return(true);
            }

            //
            // If the timer is active we must try to cancel the timer
            // and return only after the timer is actually cancelled.
            // if the timer is already inactive or a cancel or a set is taking
            // place, this function 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;
                    }
                }
                if (!(oldState is SentinelParker))
                {
                    return(false);
                }
                spinner.SpinOnce();
            } while (true);

            //
            // Try to cancel the timer's callback parker. If we can't
            // park the current thread until the timer callback finishes
            // execution.
            //

            if (cbparker.TryCancel())
            {
                cbparker.Unpark(StParkStatus.TimerCancelled);
            }
            else
            {
                pk.Park(100, StCancelArgs.None);
            }

            //
            // Set the timer state to inactive and return success.
            //

            state = INACTIVE;
            return(true);
        }
示例#13
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);
        }
示例#14
0
        //
        // Tries to take a data item from the specified subset of queues,
        // defined by offset and count, activating the specified cancellers.
        //

        public static int TryTakeAny(StBlockingQueue <T>[] qs, int offset, int count,
                                     out T di, StCancelArgs cargs)
        {
            int def = 0;
            int len = qs.Length;

            //
            // Try to take a data item immediately from one of the specified queues.
            //

            for (int j = offset, i = 0; i < count; i++)
            {
                StBlockingQueue <T> q = qs[j];
                if (q != null)
                {
                    if (q.TryTake(out di))
                    {
                        return(StParkStatus.Success + j);
                    }
                    def++;
                }
                if (++j >= len)
                {
                    j = 0;
                }
            }

            //
            // If the *qs* array contains only null references, throw the
            // ArgumentException.
            //

            if (def == 0)
            {
                throw new ArgumentException("qs: array contains only null references");
            }

            //
            // None of the specified queues allows an immediate take operation.
            // So, return failure if a null timeout was specified.
            //

            di = default(T);
            if (cargs.Timeout == 0)
            {
                return(StParkStatus.Timeout);
            }

            //
            // Create a parker and execute the take-any prologue on the
            // queues; the loop is exited when we detect that the take-any
            // operation was satisfied.
            //

            StParker pk = new StParker();

            WaitNode[] wns   = new WaitNode[len];
            WaitNode[] hints = new WaitNode[len];
            int        lv    = -1;

            for (int j = offset, i = 0; !pk.IsLocked && i < count; i++)
            {
                StBlockingQueue <T> q = qs[j];
                if (q != null)
                {
                    if ((wns[j] = q.TryTakePrologue(pk, (StParkStatus.Success + j), out di,
                                                    ref hints[j])) == null)
                    {
                        break;
                    }
                    lv = j;
                }
                if (++j >= len)
                {
                    j = 0;
                }
            }

            //
            // Park the current thread, activating the specified cancellers.
            //

            int ws = pk.Park(cargs);

            //
            // If the take-any operation succeed, compute the index of the
            // queue where we the data item was taken, retrive the data item
            // and execute the take epilogue, if needed.
            //

            int ti = -1;

            if (ws >= StParkStatus.Success)
            {
                ti = ws - StParkStatus.Success;
                if (wns[ti] != null)
                {
                    di = wns[ti].channel;
                    qs[ti].TakeEpilogue();
                }
            }

            //
            // Cancel the take attempt on all queues where we inserted
            // wait blocks, except the one where we retrieved the data item.
            //

            for (int j = offset, i = 0; i < count; i++)
            {
                WaitNode wn;
                if (j != ti && (wn = wns[j]) != null)
                {
                    qs[j].CancelTakeAttempt(wn, hints[j]);
                }
                if (j == lv)
                {
                    break;
                }
                if (++j >= len)
                {
                    j = 0;
                }
            }

            //
            // Return success or failure appropriately.
            //

            if (ti != -1)
            {
                return(ws);
            }
            StCancelArgs.ThrowIfException(ws);
            return(StParkStatus.Timeout);
        }