コード例 #1
0
        internal override WaitNode TryTakePrologue(StParker pk, int key, out T di, ref WaitNode hint)
        {
            var localQueue = Current;

            if (TryTake(out di, localQueue))
            {
                if (pk.TryLock())
                {
                    pk.UnparkSelf(key);
                }
                else
                {
                    localQueue.TryAdd(di);
                }
                return(null);
            }

            var wn = new WaitNode(pk, key);

            waitQueue.Enqueue(wn);

            if (!pk.IsLocked && TryTake(out di, localQueue))
            {
                if (pk.TryLock())
                {
                    waitQueue.Unlink(wn, hint);
                    pk.UnparkSelf(key);
                    return(null);
                }

                localQueue.TryAdd(di);
            }

            return(wn);
        }
コード例 #2
0
 internal WaitBlock(WaitType t, int r, int k)
 {
     parker   = new StParker();
     waitType = t;
     request  = r;
     waitKey  = k;
 }
コード例 #3
0
        //
        // 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);
        }
コード例 #4
0
        //
        // Executes the prologue of the TryTake operation.
        //

        internal override WaitNode TryTakePrologue(StParker pk, int key, out T di, ref WaitNode hint) {
            WaitNode wn = base.TryTakePrologue(pk, key, out di, ref hint);
            if (wn == null) {
                FreeSlot();
            }
            return wn;
        }
コード例 #5
0
 internal WaitBlock(StParker pk, WaitType t, int r, int k)
 {
     parker   = pk;
     waitType = t;
     request  = r;
     waitKey  = k;
 }
コード例 #6
0
        public static int Sleep(StCancelArgs cargs)
        {
            int ws = new StParker().Park(0, cargs);

            StCancelArgs.ThrowIfException(ws);
            return(ws);
        }
コード例 #7
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);
        }
コード例 #8
0
        internal WaitBlock WaitWithParker(StParker pk, WaitType type, int key, ref int sc)
        {
            WaitBlock wb = null;

            do
            {
                WaitBlock s;
                if ((s = state) == SET)
                {
                    return(null);
                }

                if (wb == null)
                {
                    wb = new WaitBlock(pk, type, 0, key);
                }

                wb.next = s;
                if (Interlocked.CompareExchange(ref state, wb, s) == s)
                {
                    sc = s == null ? spinCount : 0;
                    return(wb);
                }
            } while (true);
        }
コード例 #9
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);
        }
コード例 #10
0
        internal override WaitBlock _WaitAnyPrologue(StParker pk, int key,
                                                     ref WaitBlock hint, ref int sc)
        {
            WaitBlock wb = null;

            do
            {
                if (_TryAcquire())
                {
                    return(null);
                }

                if (wb == null)
                {
                    wb = new WaitBlock(pk, WaitType.WaitAny, ACQUIRE, key);
                }

                WaitBlock pred;
                if (EnqueueWaiter(wb, out pred))
                {
                    sc = ((hint = pred) == head) ? spinCount : 0;
                    return(wb);
                }
            } while (true);
        }
コード例 #11
0
        //
        // Registers the specified parker with the alerter.
        //

        internal bool RegisterParker(StParker pk)
        {
            do
            {
                StParker s;

                //
                // If the alerter is already set, return false.
                //

                if ((s = state) == ALERTED)
                {
                    return(false);
                }

                //
                // Try to insert the parker in the alert list.
                //

                pk.pnext = s;
                if (Interlocked.CompareExchange <StParker>(ref state, pk, s) == s)
                {
                    return(true);
                }
            } while (true);
        }
コード例 #12
0
        //
        // 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);
        }
コード例 #13
0
        internal override WaitBlock _WaitAllPrologue(StParker pk, ref WaitBlock hint,
                                                     ref int sc)
        {
            WaitBlock wb = null;

            if (_AllowsAcquire)
            {
                return(null);
            }

            if (wb == null)
            {
                wb = new WaitBlock(pk, WaitType.WaitAll, ACQUIRE, StParkStatus.StateChange);
            }

            WaitBlock pred;

            if (EnqueueWaiter(wb, out pred))
            {
                sc = ((hint = pred) == head) ? spinCount : 0;
                return(wb);
            }

            return(null);
        }
コード例 #14
0
        //
        // Executes the prologue of the TryAdd operation.
        //

        internal override WaitNode TryAddPrologue(StParker pk, int key, T di, ref WaitNode ignored)
        {
            if (pk.TryLock())
            {
                pk.UnparkSelf(key);
            }
            AddWorker(di);
            return(null);
        }
コード例 #15
0
        //
        // Constructor: registers a take with a blocking queue.
        //

        internal StRegisteredTake(StBlockingQueue <T> queue, StTakeCallback <T> callback,
                                  object cbState, int timeout, bool executeOnce)
        {
            //
            // Validate the arguments.
            //

            if (timeout == 0)
            {
                throw new ArgumentOutOfRangeException("\"timeout\" can not be zero");
            }
            if (callback == null)
            {
                throw new ArgumentOutOfRangeException("\"callback\" must be specified");
            }

            //
            // Initialize the registered take fields.
            //

            this.queue = queue;
            cbparker   = new CbParker(UnparkCallback);
            if ((this.timeout = timeout) != Timeout.Infinite)
            {
                toTimer = new RawTimer(cbparker);
            }
            this.executeOnce = executeOnce;
            this.callback    = callback;
            this.cbState     = cbState;

            //
            // Execute the TryTakePrologue prologue on the queue.
            //

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

            //
            // Set the state to active and enable the unpark callback.
            //

            state = ACTIVE;
            int ws;

            if ((ws = cbparker.EnableCallback(timeout, toTimer)) != StParkStatus.Pending)
            {
                //
                // The take operation was already accomplished. To prevent
                // uncontrolled reentrancy, the unpark callback is executed inline.
                //

                UnparkCallback(ws);
            }
        }
コード例 #16
0
        //
        // Executes the prologue of the Waitable.WaitAny method.
        //

        internal override WaitBlock _WaitAnyPrologue(StParker pk, int key,
                                                     ref WaitBlock ignored, ref int sc)
        {
            if (TryEnterWriteInternal())
            {
                return(null);
            }

            var wb = new WaitBlock(pk, WaitType.WaitAny, ENTER_WRITE, key);

            sc = EnqueueEnterWrite(wb);
            return(wb);
        }
コード例 #17
0
        internal override WaitBlock _WaitAnyPrologue(StParker pk, int key,
                                                     ref WaitBlock ignored, ref int sc)
        {
            if (TryAcquireInternal(1))
            {
                return(null);
            }

            var wb = new WaitBlock(pk, WaitType.WaitAny, 1, key);

            sc = EnqueueAcquire(wb, 1);
            return(wb);
        }
コード例 #18
0
        //
        // Executes the prologue of the Waitable.WaitAll method.
        //

        internal override WaitBlock _WaitAllPrologue(StParker pk,
                                                     ref WaitBlock ignored, ref int sc)
        {
            if (_AllowsAcquire)
            {
                return(null);
            }

            var wb = new WaitBlock(pk, WaitType.WaitAll, ENTER_WRITE, StParkStatus.StateChange);

            sc = EnqueueEnterWrite(wb);
            return(wb);
        }
コード例 #19
0
        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);
        }
コード例 #20
0
        //
        // Deregisters the specified parker from the alerter.
        //

        internal void DeregisterParker(StParker pk)
        {
            //
            // Very often there is only a parker inserted in the alerter
            // list. So, consider first this case.
            //

            if (pk.pnext == null &&
                Interlocked.CompareExchange <StParker>(ref state, null, pk) == pk)
            {
                return;
            }
            SlowDeregisterParker(pk);
        }
コード例 #21
0
        //
        // Deregisters the specified parker when it isn't the only
        // parker in the alerter list.
        //

        private void SlowDeregisterParker(StParker pk)
        {
            //
            // Absorb the locked parkers at top of the stack.
            //

            StParker p;

            do
            {
                if ((p = state) == null || p == ALERTED)
                {
                    return;
                }
                if (p.IsLocked)
                {
                    Interlocked.CompareExchange <StParker>(ref state, p.pnext, p);
                }
                else
                {
                    break;
                }
            } while (true);

            //
            // Compute a entry ahead the parker that we want to unlink,
            // and try to unsplice it.
            //

            StParker past;

            if ((past = pk.pnext) != null && past.IsLocked)
            {
                past = past.pnext;
            }

            while (p != null && p != past)
            {
                StParker n = p.pnext;
                if (n != null && n.IsLocked)
                {
                    p.CasNext(n, n.pnext);
                }
                else
                {
                    p = n;
                }
            }
        }
コード例 #22
0
        //
        // Exits the lock.
        //

        public void Exit()
        {
            //
            // Since that atomic operations on references are more
            // expensive than on integers, we optimize the release when
            // the spin lock's wait queue is empty. However, when the queue
            // seems empty before the lock is released, but it's seen
            // non-empty after the lock is released, our algorithm resorts
            // to two atomic instructions.
            //

            if (top == null)
            {
                Interlocked.Exchange(ref state, FREE);
                if (top == null)
                {
                    return;
                }
            }
            else
            {
                state = FREE;
            }

            //
            // Unpark all waiting threads.
            //
            // NOTE: Since that the spin lock's queue is implemented with
            //       a stack, we build another stack in order to unpark the
            //       waiting thread according to its arrival order.
            //

            StParker p = Interlocked.Exchange <StParker>(ref top, null);
            StParker ws = null, n;

            while (p != null)
            {
                n       = p.pnext;
                p.pnext = ws;
                ws      = p;
                p       = n;
            }
            while (ws != null)
            {
                n = ws.pnext;
                ws.Unpark(StParkStatus.Success);
                ws = n;
            }
        }
コード例 #23
0
        //
        // Constructors.
        //

        public StTimer(bool notificationTimer)
        {
            if (notificationTimer)
            {
                tmrEvent = new StNotificationEvent();
            }
            else
            {
                tmrEvent = new StSynchronizationEvent();
            }

            state    = INACTIVE;
            cbparker = new CbParker(TimerCallback);
            timer    = new RawTimer(cbparker);
        }
コード例 #24
0
        //
        // Tries to unregister the callback. This method is thread-safe.
        //

        public bool Unregister()
        {
            StParker p = parker;

            if (p == null)
            {
                return(false);
            }

            parker = null;

            if (p.TryCancel())
            {
                p.Unpark(StParkStatus.WaitCancelled);
                return(true);
            }
            return(false);
        }
コード例 #25
0
        //
        // Executes the prologue of the TryAdd operation.
        //

        internal override WaitNode TryAddPrologue(StParker pk, int key, T di, ref WaitNode hint) {
            if (TryReserveSlot()) {
                if (pk.TryLock()) {
                    AddWorker(di);
                    pk.UnparkSelf(key);
                } else {
                    FreeSlot();
                }
                return null;
            }

            //
            // ...
            //

            WaitNode wn;
            hint = waitQueue.Enqueue(wn = new WaitNode(pk, key, di));

            //
            // As a slot could have been free after the check done
            // above, but before we insert the wait block in the wait queue,
            // we must retry to reserve a free slot.
            //

            if (TryReserveSlot()) {
                if (pk.TryLock()) {
                    AddWorker(di);
                    pk.UnparkSelf(key);
                } else {
                    waitQueue.Unlink(wn, hint);
                    FreeSlot();
                }
                return null;
            }
            return wn;
        }
コード例 #26
0
        static TimerList()
        {
            //
            // Create the objects.
            //

            _lock         = new SpinLock(TIMER_LIST_LOCK_SPINS);
            timerListHead = new RawTimer(null);
            limitTimer    = new RawTimer(null);
            parker        = new StParker(1);

            //
            // Initialize the limit timer as unlinked.
            //

            limitTimer.next = limitTimer;

            //
            // Initialize the timer list as empty.
            //

            timerListHead.next = timerListHead.prev = timerListHead;

            //
            // Set the start base time e set the *delay* sentinel.
            //

            baseTime            = Environment.TickCount;
            timerListHead.delay = Int32.MaxValue;

            //
            // Create and start the timer thread.
            //

            new Thread(TimerThread).Start();
        }
コード例 #27
0
        //
        // Frees the lock and selects a candidate owner from the queue
        // of waiting threads.
        //

        public void Exit()
        {
            WaitBlock wb     = head;
            bool      unpark = false;
            StParker  pk     = null;

            while ((wb = wb.next) != null && wb.request != CANDIDATE)
            {
                pk = wb.parker;
                if (pk.TryLock())
                {
                    wb.request = CANDIDATE;
                    unpark     = true;
                    break;
                }
            }

            state = FREE;

            if (unpark)
            {
                pk.Unpark(StParkStatus.Success);
            }
        }
コード例 #28
0
        //
        // Constructors.
        //

        public SpinLock(int sc)
        {
            state     = FREE;
            top       = null;
            spinCount = Platform.IsMultiProcessor ? sc : 0;
        }
コード例 #29
0
        //
        // Slow path to acquire the spin lock.
        //

        private void SlowEnter()
        {
            StParker pk = null;

            do
            {
                //
                // First, try to acquire the spin lock, spinning for the
                // specified number of cycles, if the wait queue is empty.
                //

                int sc = spinCount;
                do
                {
                    if (state == FREE &&
                        Interlocked.CompareExchange(ref state, BUSY, FREE) == FREE)
                    {
                        return;
                    }
                    if (top != null || sc-- <= 0)
                    {
                        break;
                    }
                    Platform.SpinWait(1);
                } while (true);

                //
                // The spin lock is busy. So, create, or reset, a parker and
                // insert it in the wait queue.
                //

                if (pk == null)
                {
                    pk = new StParker(0);
                }
                else
                {
                    pk.Reset(0);
                }
                do
                {
                    StParker t;
                    pk.pnext = (t = top);
                    if (Interlocked.CompareExchange <StParker>(ref top, pk, t) == t)
                    {
                        break;
                    }
                } while (true);

                //
                // Since that the lock can become free after the parker is
                // inserted in the wait queue, we must retry to acquire the spinlock
                // if it seems free.
                //
                // NOTE: We don't remove the parker from the wait queue, because
                //       it will be surely removed next time the lock is release.
                //

                if (state == FREE &&
                    Interlocked.CompareExchange(ref state, BUSY, FREE) == FREE)
                {
                    return;
                }

                //
                // Park the current thread and, after release, retry the
                // spin lock acquire.
                //

                pk.Park();
            } while (true);
        }
コード例 #30
0
 internal override WaitBlock _WaitAllPrologue(StParker pk, ref WaitBlock hint, ref int sc)
 {
     return(waitEvent.WaitWithParker(pk, WaitType.WaitAll, StParkStatus.StateChange, ref sc));
 }