private void Cleanup(WaitBlock toRemove)
        {
            WaitBlock prev;
            WaitBlock wb = (prev = head).next;
            WaitBlock t  = tail;

            while (wb != null && wb != t)
            {
                if (wb == toRemove || wb.parker.IsLocked)
                {
                    if (prev == head)
                    {
                        head = prev = wb;
                    }
                    else
                    {
                        prev.next = wb.next;
                    }
                }
                else
                {
                    prev = wb;
                }

                wb = wb.next;
            }
        }
예제 #2
0
 internal Mutant(bool initialState, int sc) {
     head = tail = new WaitBlock();
     if (initialState) {
         head.next = SET;
     }
     spinCount = Platform.IsMultiProcessor ? sc : 0;
 }
예제 #3
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);
        }
        //
        // Waits until acquire the specified number of permits, activating
        // the specified cancellers.
        //

        public bool Wait(int acquireCount, StCancelArgs cargs)
        {
            if (acquireCount <= 0 || acquireCount > maximumCount)
            {
                throw new ArgumentException("acquireCount");
            }

            if (TryAcquireInternal(acquireCount))
            {
                return(true);
            }

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

            var wb = new WaitBlock(WaitType.WaitAny, acquireCount);
            int sc = EnqueueAcquire(wb, acquireCount);

            int ws = wb.parker.Park(sc, cargs);

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

            CancelAcquire(wb);
            StCancelArgs.ThrowIfException(ws);
            return(false);
        }
예제 #5
0
        private int SlowWait(StCancelArgs cargs, WaitBlock wb)
        {
            do
            {
                WaitBlock s;
                if ((s = state) == SET)
                {
                    return(StParkStatus.Success);
                }

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

            int ws = wb.parker.Park(wb.next == null ? spinCount : 0, cargs);

            if (ws != StParkStatus.Success)
            {
                Unlink(wb);
            }

            return(ws);
        }
		//
		// Waits until acquire the specified number of permits, activating
		// the specified cancellers.
		//

		public bool Wait(int acquireCount, StCancelArgs cargs) {
			if (acquireCount <= 0 || acquireCount > maximumCount) {
				throw new ArgumentException("acquireCount");
			}

			if (TryAcquireInternal(acquireCount)) {
				return true;
			}

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

			var wb = new WaitBlock(WaitType.WaitAny, acquireCount);
			int sc = EnqueueAcquire(wb, acquireCount);

			int ws = wb.parker.Park(sc, cargs);
			if (ws == StParkStatus.Success) {
				return true;
			}

			CancelAcquire(wb);
			StCancelArgs.ThrowIfException(ws);
			return false;
		}
예제 #7
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);
        }
예제 #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
        internal void SetHeadAndUnlock(WaitBlock nh)
        {
            //
            // First, remove the cancelled wait blocks that follow the
            // new queue's head.
            //

            do
            {
                WaitBlock w;
                if ((w = nh.next) == null || !w.parker.IsLocked || w.request < 0)
                {
                    break;
                }
                nh.next = nh;   // Mark old head wait block as unlinked.
                nh      = w;
            } while (true);

            //
            // Set the new head and release the queue lock, making
            // the lock and queue changes visible to all processors.
            //

            head = nh;
            Interlocked.Exchange(ref qlock, FREE);
        }
예제 #10
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);
        }
예제 #11
0
        private bool EnqueueWaiter(WaitBlock wb, out WaitBlock pred)
        {
            do
            {
                WaitBlock t, tn;
                if ((tn = (t = tail).next) == SET)
                {
                    pred = null;
                    return(false);
                }

                if (tn != null)
                {
                    AdvanceTail(t, tn);
                    continue;
                }

                if (Interlocked.CompareExchange(ref t.next, wb, null) == null)
                {
                    AdvanceTail(t, wb);
                    pred = t;
                    return(true);
                }
            } while (true);
        }
예제 #12
0
 private void AdvanceTail(WaitBlock t, WaitBlock nt)
 {
     if (t == tail)
     {
         Interlocked.CompareExchange(ref tail, nt, t);
     }
 }
예제 #13
0
        internal bool Set()
        {
            if (state == SET)
            {
                return(true);
            }

            WaitBlock p = Interlocked.Exchange(ref state, SET);

            //
            // If the event queue is empty, return the previous state of the event.
            //

            if (p == null || p == SET)
            {
                return(p == SET);
            }

            StParker pk;

            //
            // If spinning is configured and there is more than one thread in the
            // wait queue, we first release the thread that is spinning. As only
            // one thread spins, we maximize the chances of unparking that thread
            // before it blocks.
            //

            if (spinCount != 0 && p.next != null)
            {
                WaitBlock pv = p;
                WaitBlock n;

                while ((n = pv.next).next != null)
                {
                    pv = n;
                }

                pv.next = null;

                if ((pk = n.parker).TryLock())
                {
                    pk.Unpark(n.waitKey);
                }
            }

            do
            {
                if ((pk = p.parker).TryLock())
                {
                    pk.Unpark(p.waitKey);
                }
            } while ((p = p.next) != null);

            //
            // Return the previous state of the event.
            //

            return(false);
        }
예제 #14
0
        //
        // Enqueues the specified wait block in the wait queue as a locked
        // acquire request. This is used to implement wait morphing. When
        // the method is called the mutant is non-signalled.
        //

        internal void EnqueueLockedWaiter(WaitBlock wb)
        {
            wb.request = LOCKED_ACQUIRE;
            wb.next    = null;
            WaitBlock pred;

            EnqueueWaiter(wb, out pred);
        }
예제 #15
0
 internal Mutant(bool initialState, int sc)
 {
     head = tail = new WaitBlock();
     if (initialState)
     {
         head.next = SET;
     }
     spinCount = Platform.IsMultiProcessor ? sc : 0;
 }
예제 #16
0
 private bool TryAdvanceHead(WaitBlock h, WaitBlock nh)
 {
     if (h == head && Interlocked.CompareExchange(ref head, nh, h) == h)
     {
         h.next = h; // Mark the old head as unlinked.
         return(true);
     }
     return(false);
 }
예제 #17
0
        //
        // Cancels an enter lock attempt.
        //

        private void CancelAcquire(WaitBlock wb)
        {
            WaitBlock wbn;

            if ((wbn = wb.next) != wb && wbn != null && queue.TryLock())
            {
                queue.Unlink(wb);
                ReleaseWaitersAndUnlockQueue();
            }
        }
예제 #18
0
 internal void Enqueue(WaitBlock wb)
 {
     if (head == null)
     {
         head = wb;
     }
     else
     {
         tail.next = wb;
     }
     tail = wb;
 }
예제 #19
0
        //
        // Waits until enter the write lock, activating the specified
        // cancellers.
        //

        public bool TryEnterWrite(StCancelArgs cargs)
        {
            //
            // Try to enter the write lock and, if succeed, return success.
            //

            if (TryEnterWriteInternal())
            {
                return(true);
            }

            //
            // Return failure, if a null timeout was specified.
            //

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

            //
            // Create a wait block and insert it in the r/w lock's queue.
            //

            WaitBlock wb = new WaitBlock(WaitType.WaitAny, ENTER_WRITE, StParkStatus.Success);
            int       sc = EnqueueEnterWrite(wb);

            //
            // Park the current thread, activating the specified cancellers
            // and spinning if appropriate.
            //

            int ws = wb.parker.Park(sc, cargs);

            //
            // If we entered the write lock, return success.
            //

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

            //
            // The request was cancelled; so, cancel the enter write lock
            // attempt and report the failure appropriately.
            //

            CancelAcquire(wb);
            StCancelArgs.ThrowIfException(ws);
            return(false);
        }
        private bool SlowEnter(StCancelArgs cargs)
        {
            int       lastTime      = cargs.Timeout != Timeout.Infinite ? Environment.TickCount : 0;
            bool      timeRemaining = true;
            WaitBlock wb            = EnqueueWaiter();

            do
            {
                if (TryEnter())
                {
                    Cleanup(wb);
                    return(true);
                }

                if (!timeRemaining)
                {
                    return(false);
                }

                int ws = wb.parker.Park(head.next == wb ? spinCount : 0, cargs);

                if (ws != StParkStatus.Success)
                {
                    StCancelArgs.ThrowIfException(ws);
                    return(false);
                }

                if (TryEnter())
                {
                    Cleanup(wb);
                    return(true);
                }

                //
                // We failed to acquire the lock so we must clear the current
                // thread as the candidate owner. After doing so we must recheck
                // the state of lock. If the wait timed out, we exit the loop
                // before parking again.
                //

                if ((timeRemaining = cargs.AdjustTimeout(ref lastTime)))
                {
                    wb.parker.Reset();
                }

                //
                // Avoid a release-followed-by-acquire hazard.
                //

                Interlocked.Exchange(ref wb.request, ACQUIRE);
            } while (true);
        }
예제 #21
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);
        }
예제 #22
0
        //
        // Enqueues the specified wait block in the lock's queue.
        // When this method is called, the lock is owned by the
        // current thread.
        //

        void IMonitorLock.EnqueueWaiter(WaitBlock wb)
        {
            wb.request = LOCKED_ACQUIRE;
            do
            {
                WaitBlock t;
                wb.next = (t = top);
                if (Interlocked.CompareExchange(ref top, wb, t) == t)
                {
                    return;
                }
            } while (true);
        }
예제 #23
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);
        }
예제 #24
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);
        }
예제 #25
0
        //
        // Exits the lock.
        //

        public void Exit()
        {
            //
            // Because atomic operations on references are more expensive than
            // on integers, we try to optimize the release when the wait queue
            // is empty. However, when the wait queue is seen as non-empty after
            // the lock is released, our algorithm resorts to another atomic
            // instruction in order to unoark pending waiters.
            //

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

            //
            // Unpark all waiting threads. Because the spin lock's queue is implemented
            // as a stack, we build another one in order to unpark the waiting threads
            // according to their arrival order.
            //

            WaitBlock p = Interlocked.Exchange(ref top, null);
            WaitBlock ws = null, n;

            while (p != null)
            {
                n = p.next;
                if (p.request == LOCKED_ACQUIRE || p.parker.TryLock())
                {
                    p.next = ws;
                    ws     = p;
                }
                p = n;
            }

            while (ws != null)
            {
                n = ws.next;
                ws.parker.Unpark(StParkStatus.Success);
                ws = n;
            }
        }
예제 #26
0
        internal WaitBlock Dequeue()
        {
            WaitBlock wb;

            if ((wb = head) == null)
            {
                return(null);
            }

            if ((head = wb.next) == null)
            {
                tail = null;
            }
            return(wb);
        }
예제 #27
0
        private void CancelAcquire(WaitBlock wb)
        {
            //
            // If the wait block is still linked and it isn't the last wait block
            // in the queue and the queue's lock is free, unlink the wait block.
            //

            WaitBlock wbn;

            if ((wbn = wb.next) != wb && wbn != null && queue.TryLock())
            {
                queue.Unlink(wb);
                ReleaseWaitersAndUnlockQueue(null);
            }
        }
예제 #28
0
        internal void Unlink(WaitBlock wb)
        {
            //
            // We can return immediately if the queue is empty or if the WaitBlock
            // is the only one in it and we succeeded in removing it.
            //

            WaitBlock s;

            if ((s = state) == SET || s == null || (wb.next == null && s == wb &&
                                                    Interlocked.CompareExchange(ref state, null, s) == s))
            {
                return;
            }
            SlowUnlink(wb);
        }
예제 #29
0
        private int EnqueueAcquire(WaitBlock wb, int acquireCount)
        {
            bool isFirst = queue.Enqueue(wb);

            //
            // If the wait block was inserted at the front of the queue and
            // the current thread can now acquire the requested permits, try
            // to lock the queue and execute the release processing.
            //

            if (isFirst && state >= acquireCount && queue.TryLock())
            {
                ReleaseWaitersAndUnlockQueue(wb);
            }

            return(isFirst ? spinCount : 0);
        }
예제 #30
0
        internal void Remove(WaitBlock wb)
        {
            //
            // Return immediately if the wait block has been unlinked.
            //

            if (wb.next == wb)
            {
                return;
            }

            //
            // Compute the previous wait block and perform the removal.
            //

            WaitBlock p  = head;
            WaitBlock pv = null;

            while (p != null)
            {
                if (p == wb)
                {
                    if (pv == null)
                    {
                        if ((head = wb.next) == null)
                        {
                            tail = null;
                        }
                    }
                    else
                    {
                        if ((pv.next = wb.next) == null)
                        {
                            tail = pv;
                        }
                    }
                    wb.next = wb;
                    return;
                }
                pv = p;
                p  = p.next;
            }

            throw new InvalidOperationException();
        }
예제 #31
0
        //
        // Enqueues an enter write lock attempt.
        //

        private int EnqueueEnterWrite(WaitBlock wb)
        {
            //
            // Enqueue the wait block in the r/w lock queue.
            //

            bool isFirst = queue.Enqueue(wb);

            //
            // If the wait block was inserted at front of the queue, check if
            // we can acquire now; if so, execute the release processing.
            //

            if (isFirst && state == 0 && queue.TryLock())
            {
                ReleaseWaitersAndUnlockQueue();
            }
            return(isFirst ? spinCount : 0);
        }
        private WaitBlock EnqueueWaiter()
        {
            var wb = new WaitBlock(ACQUIRE);

            do
            {
                WaitBlock t, tn;
                if ((tn = (t = tail).next) != null)
                {
                    AdvanceTail(t, tn);
                    continue;
                }

                if (Interlocked.CompareExchange(ref t.next, wb, null) == null)
                {
                    AdvanceTail(t, wb);
                    return(wb);
                }
            } while (true);
        }
예제 #33
0
        //
        // Executes the prologue of the Waitable.WaitAll method.
        //

        internal override WaitBlock _WaitAllPrologue(StParker pk, ref WaitBlock hint,
                                                     ref int sc) {
            return tmrEvent._WaitAllPrologue(pk, ref hint, ref sc);
        }
        //
		// Waits until enter the write lock, activating the specified
        // cancellers.
		//

		public bool TryEnterWrite(StCancelArgs cargs) {

			//
			// Try to enter the write lock and, if succeed, return success.
			//

            if (TryEnterWriteInternal()) {
                return true;
            }
			
			//
			// Return failure, if a null timeout was specified.
			//

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

			//
			// Create a wait block and insert it in the r/w lock's queue.
			//

            WaitBlock wb = new WaitBlock(WaitType.WaitAny, ENTER_WRITE, StParkStatus.Success);
            int sc = EnqueueEnterWrite(wb);

            //
			// Park the current thread, activating the specified cancellers
            // and spinning if appropriate.
			//

			int ws = wb.parker.Park(sc, cargs);

            //
            // If we entered the write lock, return success.
            //

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

			//
			// The request was cancelled; so, cancel the enter write lock
            // attempt and report the failure appropriately.
			//

			CancelAcquire(wb);
            StCancelArgs.ThrowIfException(ws);
            return false;
        }
예제 #35
0
 private void AdvanceTail(WaitBlock t, WaitBlock nt) {
     if (tail == t) {
         Interlocked.CompareExchange(ref tail, nt, t);
     }
 }
예제 #36
0
        internal void SetHeadAndUnlock(WaitBlock nh) {

            //
            // First, remove the cancelled wait blocks that follow the
            // new queue's head.
            //

            do {
                WaitBlock w;
                if ((w = nh.next) == null || !w.parker.IsLocked || w.request < 0) {
                    break;
                }
                nh.next = nh;   // Mark old head wait block as unlinked.
                nh = w;
            } while (true);

            //
            // Set the new head and release the queue lock, making
            // the lock and queue changes visible to all processors.
            //

            head = nh;
            Interlocked.Exchange(ref qlock, FREE);
        }
예제 #37
0
 internal void Init() {
     head = tail = new WaitBlock();
 }
예제 #38
0
        internal WaitBlock Dequeue() {
            WaitBlock wb;
            if ((wb = head) == null) {
                return null;
            }

            if ((head = wb.next) == null) {
                tail = null;
            }
            return wb;
        }
 internal override void _CancelAcquire(WaitBlock wb, WaitBlock hint) {
     flock._CancelAcquire(wb, hint);
 }
        //
        // Executes the prologue of the Waitable.WaitAny method.
        //

        internal override WaitBlock _WaitAnyPrologue(StParker pk, int key,
                                                     ref WaitBlock hint, ref int sc) {
            return FastTryEnterWrite(Thread.CurrentThread.ManagedThreadId) 
                 ? null 
                 : rwlock._WaitAnyPrologue(pk, key, ref hint, ref sc);
        }
        //
        // Adds a writer waiter to the waiting list.
        //
        // NOTE: When this method is called, we know that the write
        //       lock is owned by the current thread.
        //

        void IMonitorLock.EnqueueWaiter(WaitBlock wb) {
            ((IMonitorLock)rwlock).EnqueueWaiter(wb);
        }
        //
        // 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);
        }
        //
        // Constructor: registers a wait with a Waitable synchronizer.
        //

        internal StRegisteredWait(StWaitable waitObject,  WaitOrTimerCallback callback,
                                  object cbState, int timeout, bool executeOnce) {

        	//
	        // Validate the arguments.
	        //

            if (timeout == 0) {
                throw new ArgumentOutOfRangeException("\"timeout\" can't be zero");
            }
            if (callback == null) {
                throw new ArgumentOutOfRangeException("\"callback\" can't be null");
            }
            if ((waitObject is StReentrantFairLock) || (waitObject is StReentrantReadWriteLock)) {
                throw new InvalidOperationException("can't register waits on reentrant locks");
            }
            if ((waitObject is StNotificationEvent) && !executeOnce) {
                throw new InvalidOperationException("Notification event can't register waits"
                            + " to execute more than once");
            }

	        //
	        // Initialize the register wait fields
	        //

            waitable = waitObject;
            cbparker = new CbParker(UnparkCallback);
            toTimer = new RawTimer(cbparker);
	        this.timeout = timeout;
            this.executeOnce = executeOnce;
	        this.callback = callback;
	        this.cbState = (cbState != null) ? cbState : this;
        
            //
	        // Execute the WaitAny prologue on the waitable.
	        //
            int ignored = 0;
            waitBlock  = waitObject._WaitAnyPrologue(cbparker, StParkStatus.Success, ref hint,
                                                     ref ignored);

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

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

		        UnparkCallback(ws);
	        }
        }
예제 #44
0
		//
		// Only one thread act as a releaser at any given time.
		//

		private void ReleaseWaitersAndUnlockQueue(WaitBlock self) {
			do {
				WaitBlock qh = queue.head;
				WaitBlock w;

				while (state > 0 && (w = qh.next) != null) {
					StParker pk = w.parker;

					if (w.waitType == WaitType.WaitAny) {
						if (!TryAcquireInternalQueued(w.request)) {
							break;
						}

						if (pk.TryLock()) {
							if (w == self) {
								pk.UnparkSelf(w.waitKey);
							} else {
								pk.Unpark(w.waitKey);
							}
						} else {
							UndoAcquire(w.request);
						}
					} else if (pk.TryLock()) {
						if (w == self) {
							pk.UnparkSelf(w.waitKey);
						} else {
							pk.Unpark(w.waitKey);
						}
					}

					//
					// Remove the wait block from the semaphore's queue,
					// marking the previous head as unlinked, and advance 
					// the local queues's head.
					//

					qh.next = qh;
					qh = w;
				}

				//
				// It seems that no more waiters can be released; so,
				// set the new semaphore queue's head and unlock it.
				//

				queue.SetHeadAndUnlock(qh);

				//
				// If after the semaphore's queue is unlocked, it seems that
				// more waiters can be released, repeat the release processing.
				//

				if (!IsReleasePending) {
					return;
				}
			} while (true);
		}
예제 #45
0
 internal void Enqueue(WaitBlock wb) {
     if (head == null) {
         head = wb;
     } else {
         tail.next = wb;
     }
     tail = wb;
 }
        //
        // Enqueues the specified wait block in the lock's queue as a locked 
        // acquire request. When this method is callead the lock is owned by
        // the current thread.
        //

        void IMonitorLock.EnqueueWaiter(WaitBlock wb) {
            flock.EnqueueLockedWaiter(wb);
        }
예제 #47
0
        internal void Remove(WaitBlock wb) {

            //
            // Return immediately if the wait block has been unlinked.
            //

            if (wb.next == wb) {
                return;
            }

            //
            // Compute the previous wait block and perform the removal.
            //

            WaitBlock p = head;
            WaitBlock pv = null;
            while (p != null) {
                if (p == wb) {
                    if (pv == null) {
                        if ((head = wb.next) == null) {
                            tail = null;
                        }
                    } else {
                        if ((pv.next = wb.next) == null)
                            tail = pv;
                    }
                    wb.next = wb;
                    return;
                }
                pv = p;
                p = p.next;
            }
            
            throw new InvalidOperationException();
        }
 internal override WaitBlock _WaitAnyPrologue(StParker pk, int key,
                                              ref WaitBlock hint, ref int sc) {
     return _TryAcquire() ? null : flock._WaitAnyPrologue(pk, key, ref hint, ref sc);
 }
예제 #49
0
        internal bool Enqueue(WaitBlock wb) {
            do {
                WaitBlock t = tail;
                WaitBlock tn = t.next;

                //
                // Do the necessary consistency checks.
                //

                if (t != tail) {
                    continue;
                }
                if (tn != null) {
                    AdvanceTail(t, tn);
                    continue;
                }

                //
                // Queue in quiescent state, try to insert the wait block.
                //

                if (t.CasNext(null, wb)) {

                    //
                    // Enqueue succeed; So, try to swing the tail to the
                    // inserted wait block and return.
                    //

                    AdvanceTail(t, wb);
                    return t == head;
                }
            } while (true);
        }
 internal override WaitBlock _WaitAllPrologue(StParker pk, ref WaitBlock hint,
                                              ref int sc) {
     return _AllowsAcquire ? null : flock._WaitAllPrologue(pk, ref hint, ref sc);
 }
예제 #51
0
        internal void Unlink(WaitBlock wb) {
            if (wb.next == wb || wb == head) {
                return;
            }

            //
            // Remove the cancelled wait nodes from *head* till *wb*.
            //

            WaitBlock n;
            WaitBlock pv = head;
            while ((n = pv.next) != wb) {
                if (n.parker.IsLocked) {
                    pv.next = n.next;
                    n.next = n;
                } else {
                    pv = n;
                }
            }

            //
            // Remove the wait block *wb* and also the cancelled wait
            // blocks that follow it.
            //

            do {
                pv.next = n.next;
                n.next = n;
            } while ((n = pv.next).next != null && n.parker.IsLocked);
        }
예제 #52
0
		internal override void _CancelAcquire(WaitBlock wb, WaitBlock ignored) {
			CancelAcquire(wb);
		}
		//
		// Enqueue a locked enter write request in the r/w lock's queue.
		//

        void IMonitorLock.EnqueueWaiter(WaitBlock waitBlock) {
			waitBlock.request = LOCKED_ENTER_WRITE;
			queue.Enqueue(waitBlock);
		}
예제 #54
0
		internal override WaitBlock _WaitAllPrologue(StParker pk, ref WaitBlock ignored,
													 ref int sc) {
			if (_AllowsAcquire) {
				return null;
			}

			var wb = new WaitBlock(pk, WaitType.WaitAll, 1, StParkStatus.StateChange);
			sc = EnqueueAcquire(wb, 1);
			return wb;
		}
예제 #55
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;
		}
		//
		// 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;
		}
예제 #57
0
        //
        // Cancels the specified acquire attempt.
        //

        internal override void _CancelAcquire(WaitBlock wb, WaitBlock hint) {
            tmrEvent._CancelAcquire(wb, hint);
        }
예제 #58
0
        //
        // CASes on the *next* field.
        //

        internal bool CasNext(WaitBlock n, WaitBlock nn) {
            return (next == n && Interlocked.CompareExchange<WaitBlock>(ref next, nn, n) == n);
        }
예제 #59
0
		private void CancelAcquire(WaitBlock wb) {

			//
			// If the wait block is still linked and it isn't the last wait block
			// in the queue and the queue's lock is free, unlink the wait block.
			//

			WaitBlock wbn;
			if ((wbn = wb.next) != wb && wbn != null && queue.TryLock()) {
				queue.Unlink(wb);
				ReleaseWaitersAndUnlockQueue(null);
			}
		}
예제 #60
0
		private int EnqueueAcquire(WaitBlock wb, int acquireCount) {
			bool isFirst = queue.Enqueue(wb);

			//
			// If the wait block was inserted at the front of the queue and
			// the current thread can now acquire the requested permits, try 
			// to lock the queue and execute the release processing.
			//

			if (isFirst && state >= acquireCount && queue.TryLock()) {
				ReleaseWaitersAndUnlockQueue(wb);
			}

			return isFirst ? spinCount : 0;
		}