//
        // 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 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;
        }
        //
        // 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;
        }
Exemplo n.º 4
0
        //
        // 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);
        }
Exemplo n.º 5
0
        //
        // 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);
        }
Exemplo n.º 6
0
        //
        // 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);
        }