Example #1
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);
        }
Example #2
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);
        }
Example #3
0
        public static int Sleep(StCancelArgs cargs)
        {
            int ws = new StParker().Park(0, cargs);

            StCancelArgs.ThrowIfException(ws);
            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;
		}
        //
        // 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);
        }
        //
        // 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);
        }
Example #8
0
        //
        // Tries to enter the read lock, activating the specified
        // cancellers.
        //

        public bool TryEnterRead(StCancelArgs cargs) {
            OwnerEntry hint;
            int tid;

            if (FastTryEnterRead((tid = Thread.CurrentThread.ManagedThreadId), out hint)) {
                return true;
            }

            //
            // The current thread isn't a read lock owner. So, allocate an
            // entry on the lock owner table, before acquire the non-reentrant
            // r/w lock.
            //

            hint = readOwner.AllocateEntry(tid, hint);

            if (rwlock.TryEnterRead(cargs)) {
                return true;
            }

            //
            // The specified timeout expired, so remove our entry
            // from the lock owner table and return failure.
            //

            hint.Free();
            return false;
        }
Example #9
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);
        }
Example #10
0
        //
        // Tries to acquire the lock, activating the specified
        // cancellers.
        //

        public bool Enter(StCancelArgs cargs)
        {
            if (TryEnter())
            {
                return(true);
            }
            return((cargs.Timeout != 0) ? SlowEnter(cargs) : false);
        }
        /// <summary>
        /// Waits until one of the specified waitables can be acquired,
        /// activating the specified cancellers.
        /// </summary>
        /// <param name="ws">The array of Waitables.</param>
        /// <param name="cargs">The cancellation arguments.</param>
        /// <returns></returns>
        public static int WaitAny(StWaitable[] ws, StCancelArgs cargs)
        {
            if (ws == null)
            {
                throw new ArgumentNullException("ws");
            }

            return(WaitAnyInternal(ws, null, cargs));
        }
        public StCancelArgs(int timeout, StAlerter alerter, bool interruptible) {
            if (timeout < -1) {
                throw new ArgumentOutOfRangeException("timeout", timeout, "Wrong timeout value");
            }

            this = new StCancelArgs();
            Timeout = timeout;
            Alerter = alerter;
            Interruptible = interruptible;
        }
Example #13
0
        //
        // Waits until the future's value is available, activating the
        // specified cancellers.
        //

        public bool Wait(out T result, StCancelArgs cargs)
        {
            if (waitEvent.Wait(cargs) == StParkStatus.Success)
            {
                result = _value;
                return(true);
            }

            result = default(T);
            return(false);
        }
        public StCancelArgs(int timeout, StAlerter alerter, bool interruptible)
        {
            if (timeout < -1)
            {
                throw new ArgumentOutOfRangeException("timeout", timeout, "Wrong timeout value");
            }

            this          = new StCancelArgs();
            Timeout       = timeout;
            Alerter       = alerter;
            Interruptible = interruptible;
        }
        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);
        }
Example #16
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);
        }
        /// <summary>
        /// Waits until all of the specified waitables or wait handles can be
        /// acquired, activating the specified cancellers.
        /// </summary>
        /// <param name="ws"></param>
        /// <param name="hs"></param>
        /// <param name="cargs"></param>
        /// <returns></returns>
        public static bool WaitAll(StWaitable[] ws, WaitHandle[] hs, StCancelArgs cargs)
        {
            if (hs == null)
            {
                throw new ArgumentNullException("hs");
            }

            if (cargs.Alerter != null)
            {
                throw new ArgumentException("Cancellation through the alerter mechanism is not supported", "cargs");
            }

            return(WaitAllInternal(ws, hs, cargs));
        }
        //
        // Tries to enter the lock, activating the specifed cancellers.
        //

        public bool TryEnter(StCancelArgs cargs)
        {
            //
            // First check if the lock is free and, if so, try to acquire it.
            //

            int tid = Thread.CurrentThread.ManagedThreadId;

            if (nrlock.state == StLock.FREE &&
                Interlocked.CompareExchange(ref nrlock.state, StLock.BUSY,
                                            StLock.FREE) == StLock.FREE)
            {
                //
                // Set the owner thread, since that a free lock has a zero
                // recursive acquisition count.
                //

                owner = tid;
                return(true);
            }
            if (owner == tid)
            {
                //
                // Recursive enter, so increment the recursive acquisition
                // counter.
                //

                count++;
                return(true);
            }

            if (cargs.Timeout != 0 && nrlock.Enter(cargs))
            {
                owner = tid;
                return(true);
            }

            //
            // The acquire attempt was cancelled, so return failure.
            //

            return(false);
        }
Example #19
0
        //
        // Tries to enter the write lock, activating the specified
        // cancellers.
        //

        public bool TryEnterWrite(StCancelArgs cargs) {
            int tid;
            if (FastTryEnterWrite(tid = Thread.CurrentThread.ManagedThreadId)) {
                return true;
            }

            //
            // We are not the current writer; so, try to enter the write
            // on the associated non-reentrant r/w lock.
            //

            if (rwlock.TryEnterWrite(cargs)) {
                writer = tid;
                count = 1;
                return true;
            }

            //
            // The specified timeout expired, so return failure.
            //

            return false;
        }
        /// <summary>
        /// Waits until one of the specified waitables or wait handles can be
        /// acquired, activating the specified cancellers.
        /// </summary>
        /// <param name="ws">The array of waitables.</param>
        /// <param name="hs">The array of wait handles.</param>
        /// <param name="cargs">The cancellation arguments.</param>
        /// <returns></returns>
        public static int WaitAny(StWaitable[] ws, WaitHandle[] hs, StCancelArgs cargs)
        {
            if (ws == null)
            {
                throw new ArgumentNullException("ws");
            }

            if (hs == null)
            {
                throw new ArgumentNullException("hs");
            }

            int len = ws.Length;

            for (int i = 0; i < hs.Length; i++)
            {
                if (hs[i].WaitOne(0))
                {
                    return(StParkStatus.Success + len + i);
                }
            }

            return(WaitAnyInternal(ws, hs, cargs));
        }
        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);
        }
        //
        // Tries to enter the write lock, activating the specified
        // cancellers.
        //

        public bool TryEnterWrite(StCancelArgs cargs) {
            int tid = Thread.CurrentThread.ManagedThreadId;
            if (!isReentrant) {
                if (tid == writer) {
                    throw new StLockRecursionException("Recursive enter write not allowed");
                }
                if (rdCounts.Lookup(tid) != null) {
                    throw new StLockRecursionException("Write after read not allowed");
                }
            } else {

                //
                // If this is a recursive enter, increment the recursive acquisition
                // counter and return success.
                //

                if (tid == writer) {
                    wrCount++;
                    return true;
                }
            }

            //
            // Acquire the spinlock that protects the r/w lock shared state.
            //

            slock.Enter();

            //
            // If the write lock can be entered - this is, there are no lock
            // readers, no lock writer or upgrader or the current thread is the
            // upgrader -, enter the write lock, release the spinlock and
            // return success.
            //

            if (readers == 0 && writer == UNOWNED && (upgrader == tid || upgrader == UNOWNED)) {
                writer = tid;
                slock.Exit();
                wrCount = 1;
                return true;
            }

            //
            // If the current thread isn't the current upgrader but is reader,
            // release the spinlock and throw the appropriate exception.
            //

            if (tid != upgrader && rdCounts.Lookup(tid) != null) {
                slock.Exit();
                throw new StLockRecursionException("Write after read not allowed");
            }

            //
            // The write lock can't be entered immediately. So, if a null timeout
            // was specified, release the spinlock and return failure.
            //

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

            //
            // Create a wait node and insert it in the writers queue.
            // If the current thread isn't the current upgrader, the wait
            // node is inserted in the writer's queue; otherwise, the wait
            // node becomes referenced by the *upgradeToWriteWaiter* field.
            //

            int sc;
            WaitNode wn = new WaitNode(tid);
            if (tid == upgrader) {
                upgToWrWaiter = wn;
                sc = spinCount;
            } else {
                sc = wrQueue.IsEmpty ? spinCount : 0;
                wrQueue.Enqueue(wn);
            }

            //
            // Release spin the lock and park the current thread, activating
            // the specified cancellers and spinning, if appropriate.
            //

            slock.Exit();
            int ws = wn.Park(sc, cargs);

            //
            // If the thread entered the write lock, initialize the recursive
            // acquisition counter and return success.
            //

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

            //
            // The enter attempted was cancelled. So, if the wait node was
            // already remove from the respective queue, report the failure
            // appropriately. Otherwise, unlink the wait node and, if appropriate,
            // taking into account the other waiters.
            //

            if (wn.next == wn) {
                goto ReportFailure;
            }
            slock.Enter();
            if (wn.next != wn) {
                if (wn == upgToWrWaiter) {
                    upgToWrWaiter = null;
                } else {
                    wrQueue.Remove(wn);

                    //
                    // If the writers queue becomes empty, it is possible that there
                    // is a waiting upgrader or waiting reader threads that can now
                    // proceed.
                    //

                    if (writer == UNOWNED && upgrader == UNOWNED && wrQueue.IsEmpty &&
                        TryWakeupUpgraderAndReaders()) {
                        goto ReportFailure;
                    }
                }
            }
            slock.Exit();
 
         ReportFailure:
            StCancelArgs.ThrowIfException(ws);
            return false;
        }
 /// <summary>
 /// Waits until all of the specified waitables can be acquired,
 /// activating the specified cancellers.
 /// </summary>
 /// <param name="ws"></param>
 /// <param name="cargs"></param>
 /// <returns></returns>
 public static bool WaitAll(StWaitable[] ws, StCancelArgs cargs) {
     return WaitAllInternal(ws, null, cargs);
 }
        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);
        }
 /// <summary>
 /// Waits until all of the specified waitables can be acquired,
 /// activating the specified cancellers.
 /// </summary>
 /// <param name="ws"></param>
 /// <param name="cargs"></param>
 /// <returns></returns>
 public static bool WaitAll(StWaitable[] ws, StCancelArgs cargs)
 {
     return(WaitAllInternal(ws, null, cargs));
 }
Example #26
0
 public int Park(StCancelArgs cargs)
 {
     return(Park(0, cargs));
 }
        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);
        }
        //
        // Signals the barrier and then waits until the current phase
        // completes, activating the specified cancellers.
        //

        public bool SignalAndWait(StCancelArgs cargs)
        {
            //
            // Get the current phase state.
            //

            PhaseState phs = phState;
            int        s, partners, arrived;

            do
            {
                partners = (s = phs.state) >> PARTNERS_SHIFT;
                arrived  = s & ARRIVED_MASK;
                if (arrived == partners)
                {
                    throw new InvalidOperationException("Barrier partners exceeded");
                }
                if (Interlocked.CompareExchange(ref phs.state, s + 1, s) == s)
                {
                    if (arrived + 1 == partners)
                    {
                        //
                        // This is the last partner thread. So, finish the current
                        // phase and return success.
                        //

                        FinishPhase();
                        return(true);
                    }
                    break;
                }
            } while (true);

            //
            // WaitOne on the phase event, activating the specified cancelers.
            //

            int ws = phs.waitEvent.Wait(cargs);

            //
            // If the event was signalled (i.e., successful synchronization),
            // return appropiately.
            //

            if (ws == StParkStatus.Success)
            {
                if (pphActionEx != null)
                {
                    throw new StBarrierPostPhaseException(pphActionEx);
                }
                return(true);
            }

            //
            // The wait was cancelled. So, try to decrement the counter of
            // arrived partners on our phase, if that is still possible.
            //

            do
            {
                //
                // If our partners of our phase already arrived, we must wait
                // unconditionally on the phase's event, postpone the cancellation
                // and return normally.
                //

                partners = (s = phs.state) >> PARTNERS_SHIFT;
                arrived  = s & ARRIVED_MASK;
                if (arrived == partners)
                {
                    phs.waitEvent.Wait(StCancelArgs.None);
                    StCancelArgs.PostponeCancellation(ws);
                    if (pphActionEx != null)
                    {
                        throw new StBarrierPostPhaseException(pphActionEx);
                    }
                    return(true);
                }

                //
                // Try to decrement the counter of arrived partners of our phase.
                //

                if (Interlocked.CompareExchange(ref phs.state, s - 1, s) == s)
                {
                    //
                    // We get out, so report the failure appropriately.
                    //

                    StCancelArgs.ThrowIfException(ws);
                    return(false);
                }
            } while (true);
        }
        //
		// 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;
        }
Example #30
0
        //
        // Tries to acquire a busy lock, activating the specified cancellers.
        //

        private bool SlowEnter(StCancelArgs cargs) {

	        //
	        // If a timeout was specified, get a time reference in order
            // to adjust the timeout value if the thread need to re-wait.
	        //

	        int lastTime = (cargs.Timeout != Timeout.Infinite) ? Environment.TickCount : 0;
            WaitBlock wb = null;
            do {
		        //
		        // First, try to acquire the lock spinning for the configured
                // number of cycles, but only if the wait queue is empty.
		        //
		    
                int sc = spinCount;
		        do {
			        if (state == FREE &&
                        Interlocked.CompareExchange(ref state, BUSY, FREE) == FREE) {
                        return true;
                    }
                    if (top != null || sc-- <= 0) {
                        break;
                    }
                    Platform.SpinWait(1);
                } while (true);

                //
		        // The lock is busy; so, create a wait block or reset the
                // one previously created and insert it in the wait queue.
		        //

                if (wb == null) {
                    wb = new WaitBlock(ACQUIRE);
                } else {
                    wb.parker.Reset();
                }
                do {
                    WaitBlock t;
                    wb.next = (t = top);
                    if (Interlocked.CompareExchange<WaitBlock>(ref top, wb, t) == t) {
                        break;
                    }
                } while (true);

                //
                // Since that the lock can become free after we inserted
                // the wait block, we must retry to acquire the lock, if it
                // seems free.
                //

                if (TryEnter()) {
                    return true;
                }

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

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

                //
                // If the acquire attempt was cancelled; so, report the
                // failure appropriately.
                //

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

                //
                // Before adjust the timeout value, try to acquire the lock.
                //

			    if (TryEnter()) {
                    return true;
                }
            
		        //
		        // If a timeout was specified, adjust its value taking into
                // account the elapsed time.
		        //

                if (!cargs.AdjustTimeout(ref lastTime)) {
                    return false;
                }
            } while (true);
        }
Example #31
0
        //
        // Tries to acquire the lock, activating the specified
        // cancellers.
        //

        public bool Enter(StCancelArgs cargs) {
            if (TryEnter()) {
                return true;
            }
            return (cargs.Timeout != 0) ? SlowEnter(cargs) : false;
        }
        //
        // Tries to enter the lock, activating the specifed cancellers.
        //

        public bool TryEnter(StCancelArgs cargs) {

            //
            // First check if the lock is free and, if so, try to acquire it.
            //

            int tid = Thread.CurrentThread.ManagedThreadId;
            if (nrlock.state == StLock.FREE &&
                Interlocked.CompareExchange(ref nrlock.state, StLock.BUSY,
                                            StLock.FREE) == StLock.FREE) {

                //
                // Set the owner thread, since that a free lock has a zero
                // recursive acquisition count.
                //

                owner = tid;
                return true;
            }
            if (owner == tid) {

                //
                // Recursive enter, so increment the recursive acquisition
                // counter.
                //

                count++;
                return true;
            }

            if (cargs.Timeout != 0 && nrlock.Enter(cargs)) {
                owner = tid;
                return true;
            }

            //
            // The acquire attempt was cancelled, so return failure.
            //

            return false;
        }
        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;
        }
        //
        // Writes the specified number of data items to the
        // stream blocking queue, activating the specified cancellers.
        //

        public int Write(T[] buffer, int offset, int count, StCancelArgs cargs)
        {
            //
            // If this is a zero length write, return immediately.
            //

            if (count == 0)
            {
                return(0);
            }

            //
            // Initialize the local variables.
            //

            int remaining        = count;
            WaitNodeQueue <T> wl = new WaitNodeQueue <T>();
            int toCopy;

            //
            // Acquire the queue's lock.
            //

            slock.Enter();

            //
            // If the queue's buffer is full, check if the current
            // thread must wait.
            //

            if (available == length)
            {
                goto CheckForWait;
            }

            //
            // If there are waiting readers (i.e., the buffer is empty),
            // transfer data items transferring directly to the waiting
            // readers' buffers.
            //

            if (!waitQueue.IsEmpty)
            {
                do
                {
                    WaitNode <T> rdw = waitQueue.head;

                    //
                    // Compute the number of data items to transfer to the
                    // waiting reader's buffer and perform the transfer.
                    //

                    if ((toCopy = rdw.remaining) > remaining)
                    {
                        toCopy = remaining;
                    }
                    Array.Copy(buffer, offset, rdw.buffer, rdw.offset, toCopy);
                    rdw.remaining -= toCopy;
                    rdw.offset    += toCopy;
                    remaining     -= toCopy;
                    offset        += toCopy;

                    //
                    // If the waiting reader completes its read operation,
                    // remove its wait node from the wait list and try to
                    // lock the associated parker.
                    //

                    if (rdw.remaining == 0)
                    {
                        waitQueue.Dequeue();
                        if (rdw.TryLock() && !rdw.UnparkInProgress(StParkStatus.Success))
                        {
                            wl.Add(rdw);
                        }
                    }
                    else
                    {
                        //
                        // The data items are not enough to satisfy the waiting
                        // reader that is at front of wait queue, so break the loop.
                        //

                        break;
                    }
                } while (remaining != 0 && !waitQueue.IsEmpty);
            }

            //
            // If we have still data items to write and there is free space
            // in the queue's buffer, transfer the appropriate number of data
            // items the queue's buffer.
            //

            if (remaining != 0 && available < length)
            {
                //
                // Compute the number of data items that can be copied
                // to the queue's buffer and perform the transfer.
                //

                if ((toCopy = remaining) > (length - available))
                {
                    toCopy = length - available;
                }
                int t = tail;
                int tillEnd;
                if ((tillEnd = length - t) >= toCopy)
                {
                    Array.Copy(buffer, offset, items, t, toCopy);
                    if ((t += toCopy) >= length)
                    {
                        t = 0;
                    }
                }
                else
                {
                    int fromBegin = toCopy - tillEnd;
                    Array.Copy(buffer, offset, items, t, tillEnd);
                    Array.Copy(buffer, offset + tillEnd, items, 0, fromBegin);
                    t = fromBegin;
                }

                //
                // Update counters and indexes.
                //

                tail       = t;
                available += toCopy;
                remaining -= toCopy;
                offset    += toCopy;
            }

CheckForWait:

            //
            // If there are still data items to write, the current thread must
            // wait if a null timeout wasn't specified.
            //

            WaitNode <T> wn = null;
            bool mustWait;

            if (mustWait = (remaining != 0 && cargs.Timeout != 0))
            {
                waitQueue.Enqueue(wn = new WaitNode <T>(buffer, offset, remaining));
            }

            //
            // Release the queue's lock and unpark the readers threads
            // release above.
            //

            slock.Exit();
            wl.UnparkAll();

            //
            // If the current thread doesn't need to wait, return the
            // number of written data items.
            //

            if (!mustWait)
            {
                return(count - remaining);
            }

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

            int ws = wn.Park(cargs);

            //
            // If the write was completed, return the number of written
            // data items.
            //

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

            //
            // The write was cancelled due to timeout, alert or interrupt.
            // If the wait node is still inserted in the wait queue, acquire
            // the queue's lock and unlink it.
            //

            if (wn.next != wn)
            {
                slock.Enter();
                waitQueue.Remove(wn);
                slock.Exit();
            }

            //
            // If at least a data item was written, ignore the cancellation
            // and return the number of transferred data items.
            //

            int c;

            if ((c = count - wn.remaining) != 0)
            {
                StCancelArgs.PostponeCancellation(ws);
                return(c);
            }

            //
            // No data items were written; so, report the failure appropriately.
            //

            StCancelArgs.ThrowIfException(ws);
            return(0);
        }
        //
        // Signals a waitable and waits on another as an atomic
        // operation, activating the specified cancellers.
        //

        public static bool SignalAndWait(StWaitable tos, StWaitable tow, StCancelArgs cargs) {
    
            //
            // Create a parker to execute the WaitAny prologue on the
            // *tow* waitable.
            //

            StParker pk = new StParker();
            WaitBlock hint = null;
            int sc = 0;
            WaitBlock wb = tow._WaitAnyPrologue(pk, StParkStatus.Success, ref hint, ref sc);

            //
            // Signal the *tos* waitable.
            //

            if (!tos._Release()) {

                //
                // The signal operation failed. So, try to cancel the parker and,
                // if successful, cancel the acquire attempt; otherwise, wait until 
                // the thread is unparked and, then, undo the acquire.
                //

                if (pk.TryCancel()) {
                    tow._CancelAcquire(wb, hint);
                } else {
                    pk.Park();
                    tow._UndoAcquire();
                }

                //
                // Report the failure appropriately.
                //

                throw tos._SignalException;
            }

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

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

            //
            // If we acquired, execute the WaitOne epilogue and return success.
            //

            if (ws == StParkStatus.Success) {
                tow._WaitEpilogue();
                return true;
            }
    
            //
            // The acquire operation was cancelled; so, cancel the acquire
            // attempt and report the failure appropriately.
            //

            tow._CancelAcquire(wb, hint);
            StCancelArgs.ThrowIfException(ws);
            return false;
        }
        /// <summary>
        /// Waits until one of the specified waitables can be acquired,
        /// activating the specified cancellers. 
        /// </summary>
        /// <param name="ws">The array of Waitables.</param>
        /// <param name="cargs">The cancellation arguments.</param>
        /// <returns></returns>
        public static int WaitAny(StWaitable[] ws, StCancelArgs cargs) {
            if (ws == null) {
                throw new ArgumentNullException("ws");
            }

            return WaitAnyInternal(ws, null, cargs);
        }
        /// <summary>
        /// Waits until all of the specified waitables or wait handles can be 
        /// acquired, activating the specified cancellers.
        /// </summary>
        /// <param name="ws"></param>
        /// <param name="hs"></param>
        /// <param name="cargs"></param>
        /// <returns></returns>
        public static bool WaitAll(StWaitable[] ws, WaitHandle[] hs, StCancelArgs cargs) {
            if (hs == null) {
                throw new ArgumentNullException("hs");
            }

            if (cargs.Alerter != null) {
                throw new ArgumentException("Cancellation through the alerter mechanism is not supported", "cargs");
            }

            return WaitAllInternal(ws, hs, cargs);
        }
        public void Wait(StParker pk, StCancelArgs cargs) {
            bool interrupted = false;
            int lastTime = (cargs.Timeout != Timeout.Infinite) ? Environment.TickCount : 0;
            int ws;
            do {
                try {
                    ws = waitBehavior.Park(psevent, cargs.Timeout);
                    break;
                } catch (ThreadInterruptedException) {
                    if (cargs.Interruptible) {
                        ws = StParkStatus.Interrupted;
                        break;
                    }
                    interrupted = true;
                    cargs.AdjustTimeout(ref lastTime);
                }
            } while (true);

            //
            // If the wait was cancelled due to an internal canceller, try
            // to cancel the park operation. If we fail, wait unconditionally
            // until the park spot is signalled.
            //

            if (ws != StParkStatus.Success) {
                if (pk.TryCancel()) {
                    pk.UnparkSelf(waitBehavior.ParkerCancelled(ws));
                } else {
                    if (ws == StParkStatus.Interrupted) {
                        interrupted = true;
                    }

                    waitBehavior.ParkerNotCancelled(ws);

                    do {
                        try {
                            psevent.WaitOne();
                            break;
                        } catch (ThreadInterruptedException) {
                            interrupted = true;
                        }
                    } while (true);
                }
            }

            //
            // If we were interrupted but can't return the *interrupted*
            // wait status, reassert the interrupt on the current thread.
            //

            if (interrupted) {
                Thread.CurrentThread.Interrupt();
            }

            factory.Free(this);
        }
        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);
        }
        //
        // Signals the barrier and then waits until the current phase
        // completes, activating the specified cancellers.
        //

        public bool SignalAndWait(StCancelArgs cargs) {

            //
            // Get the current phase state.
            //

            PhaseState phs = phState;
            int s, partners, arrived;
            do {
                partners = (s = phs.state) >> PARTNERS_SHIFT;
                arrived = s & ARRIVED_MASK;
                if (arrived == partners) {
                    throw new InvalidOperationException("Barrier partners exceeded");
                }
                if (Interlocked.CompareExchange(ref phs.state, s + 1, s) == s) {
                    if (arrived + 1 == partners) {

                        //
                        // This is the last partner thread. So, finish the current
                        // phase and return success.
                        //

                        FinishPhase();
                        return true;
                    }
                    break;
                }
            } while (true);

            //
            // WaitOne on the phase event, activating the specified cancelers.
            //

            int ws = phs.waitEvent.Wait(cargs);

            //
            // If the event was signalled (i.e., successful synchronization),
            // return appropiately.
            //

            if (ws == StParkStatus.Success) {
                if (pphActionEx != null) {
                    throw new StBarrierPostPhaseException(pphActionEx);
                }
                return true;
            }

            //
            // The wait was cancelled. So, try to decrement the counter of
            // arrived partners on our phase, if that is still possible.
            //

            do {

                //
                // If our partners of our phase already arrived, we must wait
                // unconditionally on the phase's event, postpone the cancellation
                // and return normally.
                //

                partners = (s = phs.state) >> PARTNERS_SHIFT;
                arrived = s & ARRIVED_MASK;
                if (arrived == partners) {
                    phs.waitEvent.Wait(StCancelArgs.None);
                    StCancelArgs.PostponeCancellation(ws);
                    if (pphActionEx != null) {
                        throw new StBarrierPostPhaseException(pphActionEx);
                    }
                    return true;
                }

                //
                // Try to decrement the counter of arrived partners of our phase.
                //

                if (Interlocked.CompareExchange(ref phs.state, s - 1, s) == s) {

                    //
                    // We get out, so report the failure appropriately.
                    //

                    StCancelArgs.ThrowIfException(ws);
                    return false;
                }
            } while (true);
        }
Example #41
0
        public int Park(int spinCount, StCancelArgs cargs)
        {
            do
            {
                if (state == 0)
                {
                    return(waitStatus);
                }
                if (cargs.Alerter != null && cargs.Alerter.IsSet && TryCancel())
                {
                    return(StParkStatus.Alerted);
                }
                if (spinCount-- <= 0)
                {
                    break;
                }
                Platform.SpinWait(1);
            } while (true);

            if (parkSpot == null)
            {
                parkSpot = ThreadExtensions.ForCurrentThread.ParkSpotFactory.Create();
            }

            //
            // Try to clear the wait-in-progress bit. If the bit was already
            // cleared, the thread is unparked.
            //

            if (!TestAndClearInProgress())
            {
                return(waitStatus);
            }

            //
            // If an alerter was specified, we register the parker with
            // the alerter before blocking the thread on the park spot.
            //

            bool unregister = false;

            if (cargs.Alerter != null)
            {
                if (!(unregister = cargs.Alerter.RegisterParker(this)))
                {
                    //
                    // The alerter is already set. So, we try to cancel the parker.
                    //

                    if (TryCancel())
                    {
                        return(StParkStatus.Alerted);
                    }

                    //
                    // We can't cancel the parker because someone else acquired
                    // the count down lock. We must wait unconditionally until
                    // the park spot is set.
                    //

                    cargs = StCancelArgs.None;
                }
            }

            parkSpot.Wait(this, cargs);

            if (unregister)
            {
                cargs.Alerter.DeregisterParker(this);
            }
            return(waitStatus);
        }
        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;
        }
        //
        // 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);
        }
        /// <summary>
        /// Waits until one of the specified waitables or wait handles can be 
        /// acquired, activating the specified cancellers. 
        /// </summary>
        /// <param name="ws">The array of waitables.</param>
        /// <param name="hs">The array of wait handles.</param>
        /// <param name="cargs">The cancellation arguments.</param>
        /// <returns></returns>
        public static int WaitAny(StWaitable[] ws, WaitHandle[] hs, StCancelArgs cargs) {
            if (ws == null) {
                throw new ArgumentNullException("ws");
            }

            if (hs == null) {
                throw new ArgumentNullException("hs");
            }

            int len = ws.Length;

            for (int i = 0; i < hs.Length; i++) {
                if (hs[i].WaitOne(0)) {
                    return StParkStatus.Success + len + i;
                }
            }

            return WaitAnyInternal(ws, hs, cargs);
        }
        //
        // Tries to enter the read lock, activating the
        // specified cancellers.
        //

        public bool TryEnterRead(StCancelArgs cargs) {
            int tid = Thread.CurrentThread.ManagedThreadId;
            ReaderCounter rc = rdCounts.Lookup(tid);
            if (!isReentrant) {
                if (tid == writer) {
                    throw new StLockRecursionException("Read after write not allowed");
                }
                if (rc != null) {
                    throw new StLockRecursionException("Recursive read not allowed");
                }
            } else {

                //
                // If this is a recursive enter, increment the recursive
                // acquisition counter and return.
                //

                if (rc != null) {
                    rc.count++;
                    return true;
                }
            }

            //
            // Acquire the spinlock that protected the r/u/w lock shared state.
            //

            slock.Enter();

            //
            // If the current thread is the upgrader, it can also enter
            // the read lock. So, add an entry to the readers table,
            // release the spinlock and return success.
            //

            if (tid == upgrader) {
                rdCounts.Add(tid);
                slock.Exit();
                upgraderIsReader = true;
                return true;
            }

            //
            // The read lock can be entered, if the r/w lock isn't in write
            // mode and no thread is waiting to enter the writer mode.
            // If these conditions are met, increment the number of lock
            // readers, add an entry to the readers table, release the
            // spinlock and return success.
            //

            if (writer == UNOWNED && wrQueue.IsEmpty && upgToWrWaiter == null) {
                readers++;
                rdCounts.Add(tid);
                slock.Exit();
                return true;
            }

            //
            // If the r/w lock is reentrant and the current thread is the
            // current writer, it can also to become a reader. So, increment
            // the number of lock readers, add an entry to the readers table,
            // release the spinlock and return success.
            //

            if (isReentrant && tid == writer) {
                readers++;
                rdCounts.Add(tid);
                slock.Exit();
                return true;
            }

            //
            // The current thread can't enter the read lock immediately.
            // So, if a null timeout was specified, release the spinlock
            // and return failure.
            //

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

            //
            // Create a wait node  and insert it in the readers queue.
            // Compute also the amount of spinning.
            //

            int sc = rdQueue.IsEmpty ? spinCount : 0;
            WaitNode wn;
            rdQueue.Enqueue(wn = new WaitNode(tid));

            //
            // Release the spinlock and park the current thread, activating
            // the specified cancellers and spinning if appropriate.
            //

            slock.Exit();
            int ws = wn.Park(sc, cargs);

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

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

            //
            // The enter attempt was cancelled. So, ensure that the wait node
            // is unlinked from the queue and report the failure appropriately.
            //

            if (wn.next != wn) {
                slock.Enter();
                rdQueue.Remove(wn);
                slock.Exit();
            }
            StCancelArgs.ThrowIfException(ws);
            return false;
        }
Example #46
0
 internal int Wait(StCancelArgs cargs)
 {
     return(state == SET ? StParkStatus.Success
          : cargs.Timeout == 0 ? StParkStatus.Timeout
          : SlowWait(cargs, new WaitBlock(WaitType.WaitAny)));
 }
        //
        // Tries to enter the lock in upgrade read mode, activating
        // the specified cancellers.
        // 

        public bool TryEnterUpgradeableRead(StCancelArgs cargs) {
            int tid = Thread.CurrentThread.ManagedThreadId;
            ReaderCounter rc = rdCounts.Lookup(tid);
            if (!isReentrant) {
                if (tid == upgrader) {
                    throw new StLockRecursionException("Recursive upgrade not allowed");
                }
                if (tid == writer) {
                    throw new StLockRecursionException("Upgrade after write not allowed");
                }
                if (rc != null) {
                    throw new StLockRecursionException("Upgrade after read not allowed");
                }
            } else {

                //
                // If the current thread is the current upgrader, increment the
                // recursive acquisition counter and return.
                //

                if (tid == upgrader) {
                    upCount++;
                    return true;
                }

                //
                // If the current thread is the current writer, it can also
                // becomes the upgrader. If it is also a reader, it will be
                // accounted as reader on the *upgraderIsReader* flag.
                //

                if (tid == writer) {
                    upgrader = tid;
                    upCount = 1;
                    if (rc != null) {
                        upgraderIsReader = true;
                    }
                    return true;
                }
                if (rc != null) {
                    throw new StLockRecursionException("Upgrade after read not allowed");
                }
            }

            //
            // Acquire the spinlock that protects the r/w lock shared state.
            //

            slock.Enter();

            //
            // If the lock isn't in write or upgrade read mode, the
            // current thread becomes the current upgrader. Then, release
            // the spinlock and return success.
            //

            if (writer == UNOWNED && upgrader == UNOWNED) {
                upgrader = tid;
                slock.Exit();
                upgraderIsReader = false;
                upCount = 1;
                return true;
            }

            //
            // The upgrade read lock can't be acquired immediately.
            // So, if a null timeout was specified, return failure.
            //

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

            //
            // Create a wait node and insert it in the upgrader's queue.
            //

            int sc = (upQueue.IsEmpty && wrQueue.IsEmpty) ? spinCount : 0;
            WaitNode wn;
            upQueue.Enqueue(wn = new WaitNode(tid));

            // 
            // Release the spinlock and park the current thread activating
            // the specified cancellers and spinning, if appropriate.
            //

            slock.Exit();
            int ws = wn.Park(sc, cargs);

            //
            // If we acquired the upgrade lock, initialize the recursive
            // acquisition count and the *upgraderIsReader flag and return
            // success.
            //

            if (ws == StParkStatus.Success) {
                upCount = 1;
                upgraderIsReader = false;
                return true;
            }

            //
            // The acquire attemptwas cancelled. So, ensure that the
            // wait node is unlinked from the wait queue and report
            // the failure appropriately.
            //

            if (wn.next != wn) {
                slock.Enter();
                upQueue.Remove(wn);
                slock.Exit();
            }
            StCancelArgs.ThrowIfException(ws);
            return false;
        }
        //
        // Tries to acquire the lock, activating the specified
        // cancellers.
        //

        public bool Enter(StCancelArgs cargs) {
            return TryEnter() || (cargs.Timeout != 0 ? SlowEnter(cargs) : false);
        }
        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);
        }
        public int Park(int spinCount, StCancelArgs cargs) {
            do {
                if (state == 0) {
                    return waitStatus;
                }
                if (cargs.Alerter != null && cargs.Alerter.IsSet && TryCancel()) {
                    return StParkStatus.Alerted;
                }
                if (spinCount-- <= 0) {
                    break;
                }
                Platform.SpinWait(1);
            } while (true);

            if (parkSpot == null) {
                parkSpot = ThreadExtensions.ForCurrentThread.ParkSpotFactory.Create();
            }

            //
            // Try to clear the wait-in-progress bit. If the bit was already
            // cleared, the thread is unparked. 
            //

            if (!TestAndClearInProgress()) {
                return waitStatus;
            }

            //
            // If an alerter was specified, we register the parker with
            // the alerter before blocking the thread on the park spot.
            //

            bool unregister = false;
            if (cargs.Alerter != null) {
                if (!(unregister = cargs.Alerter.RegisterParker(this))) {

                    //
                    // The alerter is already set. So, we try to cancel the parker.
                    //

                    if (TryCancel()) {
                        return StParkStatus.Alerted;
                    }

                    //
                    // We can't cancel the parker because someone else acquired 
                    // the count down lock. We must wait unconditionally until
                    // the park spot is set.
                    //

                    cargs = StCancelArgs.None;
                }
            }

            parkSpot.Wait(this, cargs);

            if (unregister) {
                cargs.Alerter.DeregisterParker(this);
            }
            return waitStatus;
        }
 public int Park(StCancelArgs cargs) {
     return Park(0, cargs);
 }
 public static int Sleep(StCancelArgs cargs) {
     int ws = new StParker().Park(0, cargs);
     StCancelArgs.ThrowIfException(ws);
     return ws;
 }
        public void Wait(StParker pk, StCancelArgs cargs)
        {
            bool interrupted = false;
            int  lastTime    = (cargs.Timeout != Timeout.Infinite) ? Environment.TickCount : 0;
            int  ws;

            do
            {
                try {
                    ws = waitBehavior.Park(psevent, cargs.Timeout);
                    break;
                } catch (ThreadInterruptedException) {
                    if (cargs.Interruptible)
                    {
                        ws = StParkStatus.Interrupted;
                        break;
                    }
                    interrupted = true;
                    cargs.AdjustTimeout(ref lastTime);
                }
            } while (true);

            //
            // If the wait was cancelled due to an internal canceller, try
            // to cancel the park operation. If we fail, wait unconditionally
            // until the park spot is signalled.
            //

            if (ws != StParkStatus.Success)
            {
                if (pk.TryCancel())
                {
                    pk.UnparkSelf(waitBehavior.ParkerCancelled(ws));
                }
                else
                {
                    if (ws == StParkStatus.Interrupted)
                    {
                        interrupted = true;
                    }

                    waitBehavior.ParkerNotCancelled(ws);

                    do
                    {
                        try {
                            psevent.WaitOne();
                            break;
                        } catch (ThreadInterruptedException) {
                            interrupted = true;
                        }
                    } while (true);
                }
            }

            //
            // If we were interrupted but can't return the *interrupted*
            // wait status, reassert the interrupt on the current thread.
            //

            if (interrupted)
            {
                Thread.CurrentThread.Interrupt();
            }

            factory.Free(this);
        }
 internal int Wait(StCancelArgs cargs) {
     return state == SET ? StParkStatus.Success
          : cargs.Timeout == 0 ? StParkStatus.Timeout
          : SlowWait(cargs, new WaitBlock(WaitType.WaitAny));
 }
        //
        // Waits until read the specified number of data items from
        // the stream queue, activating the specified cancellers.
        //

        public int Read(T[] buffer, int offset, int count, StCancelArgs cargs)
        {
            //
            // If this is a zero length read, return immediately.
            //

            if (count == 0)
            {
                return(0);
            }

            //
            // Initialize the local variables and acquire the queue's lock.
            //

            int remaining        = count;
            WaitNodeQueue <T> wl = new WaitNodeQueue <T>();
            int toCopy;

            slock.Enter();

            //
            // If the queue's buffer is empty, check if the current thread
            // must wait.
            //

            if (available == 0)
            {
                goto CheckForWait;
            }

            //
            // Compute the number of data items that we can read
            // from the queue's buffer and perform the transfer.
            //

            if ((toCopy = remaining) > available)
            {
                toCopy = available;
            }
            int h = head;
            int tillEnd;

            if ((tillEnd = length - h) >= toCopy)
            {
                Array.Copy(items, h, buffer, offset, toCopy);
                if ((h += toCopy) >= length)
                {
                    h = 0;
                }
            }
            else
            {
                int fromBegin = toCopy - tillEnd;
                Array.Copy(items, h, buffer, offset, tillEnd);
                Array.Copy(items, 0, buffer, offset + tillEnd, fromBegin);
                h = fromBegin;
            }

            //
            // Adjust counters and indexes.
            //

            head       = h;
            available -= toCopy;
            remaining -= toCopy;
            offset    += toCopy;

            //
            // If we have still data items to read and there are waiting
            // writers, transfer the data directly from our buffer to the
            // waiting writers' buffers.
            //

            if (remaining != 0 && !waitQueue.IsEmpty)
            {
                do
                {
                    WaitNode <T> wrw = waitQueue.head;

                    //
                    // Compute the number of data items to transfer to the
                    // waiting writer's buffer and perform the transfer.
                    //

                    if ((toCopy = remaining) > wrw.remaining)
                    {
                        toCopy = wrw.remaining;
                    }
                    Array.Copy(wrw.buffer, wrw.offset, buffer, offset, toCopy);
                    wrw.remaining -= toCopy;
                    wrw.offset    += toCopy;
                    remaining     -= toCopy;
                    offset        += toCopy;

                    //
                    // If the write operation was completed, try to release
                    // the writer thread.
                    //

                    if (wrw.remaining == 0)
                    {
                        waitQueue.Dequeue();
                        if (wrw.TryLock() && !wrw.UnparkInProgress(StParkStatus.Success))
                        {
                            wl.Add(wrw);
                        }
                    }
                    else
                    {
                        //
                        // The read is completed, so break the loop.
                        //

                        break;
                    }
                } while (remaining != 0 && !waitQueue.IsEmpty);
            }

            //
            // If there is available space in the queue's buffer and
            // waiting writers, try to fill the queue's buffer with
            // the data of the waiting writers.
            //

            if (available < length && !waitQueue.IsEmpty)
            {
                do
                {
                    WaitNode <T> wrw = waitQueue.head;

                    //
                    // Compute the number of data items to copy from the writer's
                    // buffer to the queue's buffer and perform the transfer.
                    //

                    if ((toCopy = wrw.remaining) > (length - available))
                    {
                        toCopy = length - available;
                    }

                    int t = tail;
                    if ((tillEnd = length - t) >= toCopy)
                    {
                        Array.Copy(wrw.buffer, wrw.offset, items, t, toCopy);
                        if ((t += toCopy) >= length)
                        {
                            t = 0;
                        }
                    }
                    else
                    {
                        int fromBegin = toCopy - tillEnd;
                        Array.Copy(wrw.buffer, wrw.offset, items, t, tillEnd);
                        Array.Copy(wrw.buffer, wrw.offset + tillEnd, items, 0, fromBegin);
                        t = fromBegin;
                    }

                    //
                    // Update counters and indexes.
                    //

                    tail           = t;
                    available     += toCopy;
                    wrw.remaining -= toCopy;
                    wrw.offset    += toCopy;

                    //
                    // If the writer completed its write, release it.
                    //

                    if (wrw.remaining == 0)
                    {
                        waitQueue.Dequeue();
                        if (wrw.TryLock() && !wrw.UnparkInProgress(StParkStatus.Success))
                        {
                            wl.Add(wrw);
                        }
                    }
                    else
                    {
                        //
                        // The queue's buffer is full, so break the loop.
                        //

                        break;
                    }
                } while (available < length && !waitQueue.IsEmpty);
            }

CheckForWait:

            //
            // If the read operation was not completed, the current thread
            // must wait if it didn't read all data items and a null timeout
            // wasn't specified.
            //

            WaitNode <T> wn = null;
            bool mustWait;

            if (mustWait = (remaining != 0 && cargs.Timeout != 0))
            {
                waitQueue.Enqueue(wn = new WaitNode <T>(buffer, offset, remaining));
            }

            //
            // Release the queue's lock and unpark the released waiters.
            //

            slock.Exit();
            wl.UnparkAll();

            //
            // If the read was completed or the thread specified a null
            // timeout, return the number of read data items.
            //

            if (!mustWait)
            {
                return(count - remaining);
            }

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

            int ws = wn.Park(cargs);

            //
            // If succeed, return the number of data items transferred.
            //

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

            //
            // The read was cancelled due to timeout, alert or interrupt.
            // If the wait block is still inserted in the wait queue, acquire
            // the queue's lock and remove it from the queue.
            //

            if (wn.next != wn)
            {
                slock.Enter();
                waitQueue.Remove(wn);
                slock.Exit();
            }
            int c;

            if ((c = count - wn.remaining) != 0)
            {
                StCancelArgs.PostponeCancellation(ws);
                return(c);
            }

            //
            // No data items were transferred, so report the failure
            // appropriately.
            //

            StCancelArgs.ThrowIfException(ws);
            return(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;
        }