Example #1
0
        //
        // Executes the prologue of the TryTake operation.
        //

        internal override WaitNode TryTakePrologue(StParker pk, int key, out T di, ref WaitNode hint) {
            WaitNode wn = base.TryTakePrologue(pk, key, out di, ref hint);
            if (wn == null) {
                FreeSlot();
            }
            return wn;
        }
        public static void WaitNode()
        {
            var a = new WaitNode();
            var b = SerializationUtil.Reserialize(a);

            Assert.AreEqual(a, b);
        }
Example #3
0
        //
        // Tries to take a data item from the queue, activating the
        // specified cancellers.
        //

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

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

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

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

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

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

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

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

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

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

            CancelAddAttempt(wn, hint);
            StCancelArgs.ThrowIfException(ws);
            return(false);
        }
Example #5
0
        //
        // Tries to wakeup a waiting writer.
        //
        // NOTE: This method is called with the spinlock held
        //		 and when the r/w lock is in the NonEntered state.
        //       If a waiter is woken, the method releases the spin lock
        //       and returns true; otherwise, the method returns false and
        //       with the spinlock held.
        //

        private bool TryWakeupWriter()
        {
            while (!wrQueue.IsEmpty)
            {
                WaitNode w = wrQueue.Dequeue();
                if (w.TryLock())
                {
                    //
                    // Become the waiter the next owner of the write lock,
                    // release the spinlock, unpark the waiter and return true.
                    //

                    writer = w.tid;
                    slock.Exit();
                    w.Unpark(StParkStatus.Success);
                    return(true);
                }
            }

            //
            // No writer can be released; so, return false with the
            // spinlock held.
            //

            return(false);
        }
Example #6
0
        /**
         * Removes and signals all waiting threads, invokes done(), and
         * nulls out callable.
         */
        private void finishCompletion()
        {
            // assert state > COMPLETING;
            for (WaitNode q; (q = waiters) != null;)
            {
                if (Interlocked.CompareExchange(ref waiters, null, q) == q)
                {
                    for (;;)
                    {
                        Thread t = q.Thread;
                        if (t != null)
                        {
                            q.Thread = null;
                        }
                        WaitNode next = q.Next;
                        if (next == null)
                        {
                            break;
                        }
                        q.Next = null; // unlink to help gc
                        q      = next;
                    }
                    break;
                }
            }

            done();

            callable = null;        // to reduce footprint
        }
Example #7
0
        private void DoWait(Action <WaitNode> action)
        {
            int holdCount = Lock.HoldCount;

            if (holdCount == 0)
            {
                throw new SynchronizationLockException();
            }
            WaitNode n = new WaitNode();

            _wq.Enqueue(n);
            for (int i = holdCount; i > 0; i--)
            {
                Lock.Unlock();
            }
            try
            {
                action(n);
            }
            finally
            {
                for (int i = holdCount; i > 0; i--)
                {
                    Lock.Lock();
                }
            }
        }
Example #8
0
        private static void ParseWait(Node root, TokenStream stream)
        {
            var node = new WaitNode();

            root.AddChildNode(node);

            while (stream.GetCurrent().TokenType == SemanticTokenType.NodeParameter)
            {
                var parameter = stream.Pop();
                if (parameter.TokenValue == "time:")
                {
                    var value = stream.Pop();
                    if (value.TokenType == SemanticTokenType.DecimalLiteral16 ||
                        value.TokenType == SemanticTokenType.DecimalLiteral32 ||
                        value.TokenType == SemanticTokenType.DecimalLiteral8)
                    {
                        node.WaitTimeMilliseconds = Int32.Parse(value.TokenValue);
                    }
                    else
                    {
                        throw new Exception("Invalid token parameter value");
                    }
                }
                else
                {
                    throw new Exception("Unknown parameter:" + parameter.TokenValue);
                }
            }
        }
        internal override WaitNode TryTakePrologue(StParker pk, int key, out T di, ref WaitNode hint)
        {
            var localQueue = Current;

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

            var wn = new WaitNode(pk, key);

            waitQueue.Enqueue(wn);

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

                localQueue.TryAdd(di);
            }

            return(wn);
        }
Example #10
0
 /// <summary>
 /// Tries to unlink a timed-out or interrupted wait node to avoid
 /// accumulating garbage.  Internal nodes are simply unspliced
 /// without CAS since it is harmless if they are traversed anyway
 /// by releasers.  To avoid effects of unsplicing from already
 /// removed nodes, the list is retraversed in case of an apparent
 /// race.  This is slow when there are a lot of nodes, but we don't
 /// expect lists to be long enough to outweigh higher-overhead
 /// schemes.
 /// </summary>
 private void RemoveWaiter(WaitNode node)
 {
     if (node != null)
     {
         node.Thread = null;
         for (;;)                 // restart on removeWaiter race
         {
             for (WaitNode pred = null, q = Waiters, s; q != null; q = s)
             {
                 s = q.next;
                 if (q.thread != null)
                 {
                     pred = q;
                 }
                 else if (pred != null)
                 {
                     pred.next = s;
                     if (pred.thread == null)                             // check for race
                     {
                         goto retryContinue;
                     }
                 }
                 else if (!UNSAFE.compareAndSwapObject(this, WaitersOffset, q, s))
                 {
                     goto retryContinue;
                 }
             }
             break;
             retryContinue :;
         }
         retryBreak :;
     }
 }
        //
        // 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 #12
0
            //
            // Enqueues the specified wait node.
            //

            internal override WaitNode Enqueue(WaitNode wn)
            {
                do
                {
                    WaitNode t  = tail;
                    WaitNode tn = t.next;

                    //
                    // If the queue is in the intermediate state, try to advance
                    // the its tail.
                    //

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

                    //
                    // Queue in quiescent state, so try to insert the new node.
                    //

                    if (t.CasNext(null, wn))
                    {
                        //
                        // Advance the tail and return the previous wait block.
                        //

                        AdvanceTail(t, wn);
                        return(t);
                    }
                } while (true);
            }
Example #13
0
        /// <summary>
        /// Removes and signals all waiting threads, invokes done(), and
        /// nulls out callable.
        /// </summary>
        private void FinishCompletion()
        {
            // assert state > COMPLETING;
            for (WaitNode q; (q = Waiters) != null;)
            {
                if (UNSAFE.compareAndSwapObject(this, WaitersOffset, q, null))
                {
                    for (;;)
                    {
                        Thread t = q.thread;
                        if (t != null)
                        {
                            q.thread = null;
                            LockSupport.Unpark(t);
                        }
                        WaitNode next = q.next;
                        if (next == null)
                        {
                            break;
                        }
                        q.next = null;                         // unlink to help gc
                        q      = next;
                    }
                    break;
                }
            }

            Done();

            Callable = null;             // to reduce footprint
        }
        /// <summary>
        /// 移除等待节点
        /// </summary>
        /// <param name="node"></param>
        private void removeWaiter(WaitNode node)
        {
            if (node != null)
            {
                node.thread = null;
retry:
                for (; ;)
                {          // restart on removeWaiter race
                    for (WaitNode pred = null, q = waiters, s; q != null; q = s)
                    {
                        s = q.next;
                        if (q.thread != null)
                        {
                            pred = q;
                        }
                        else if (pred != null)
                        {
                            pred.next = s;
                            if (pred.thread == null) // check for race
                            {
                                goto retry;
                            }
                        }
                        if (!(Interlocked.CompareExchange <WaitNode>(ref waiters, s, q) == q))
                        {
                            goto retry;
                        }
                    }
                    break;
                }
            }
        }
Example #15
0
        protected override IEnumerator ExecuteStep()
        {
            WaitNode.UnwaitGroupId(GroupId);

            Router.FireEvent(EndEventName);
            yield return(null);
        }
Example #16
0
 public void TakeOver(WaitNode node)
 {
     lock (this)
     {
         Debug.Assert(_holds == 1 && _owner == Thread.CurrentThread);
         _owner = node.Owner;
     }
 }
Example #17
0
        internal Task <bool> ForceReplicationAsync(TimeSpan timeout, CancellationToken token)
        {
            var waiter = new WaitNode();

            ImmutableInterlocked.Enqueue(ref replicationQueue, waiter);
            forcedReplication.Set(true);
            return(waiter.Task.WaitAsync(timeout, token));
        }
Example #18
0
            //
            // Enqueues a wait node at the front of the queue.
            //

            internal void EnqueueHead(WaitNode wn)
            {
                if ((wn.next = head) == null)
                {
                    tail = wn;
                }
                head = wn;
            }
    static public void CreateWaitNodeOfMenu( )
    {
        Transform parentNodeTra = (Selection.activeGameObject != null) ? Selection.activeGameObject.transform : null;

        WaitNode node = ViNoToolUtil.AddViNodeGameObject <WaitNode>("Wait", parentNodeTra);

        EditorGUIUtility.PingObject(node.gameObject);
    }
        /// <summary>
        /// This method visits a wait node
        /// First assigns a string that prints delay, and then accepts the amount of time and the time modifier
        /// Then closes the parenthesis
        /// </summary>
        /// <param name="waitNode">The name of the node</param>
        /// <returns>It returns delay(Time amount and modifier)</returns>
        public override object Visit(WaitNode waitNode)
        {
            string delay = "delay(";

            delay += waitNode.TimeAmount.Accept(this);
            delay += waitNode.TimeModifier.Accept(this);
            delay += ");";
            return(delay);
        }
Example #21
0
            //
            // Advances the queue's head.
            //

            private bool AdvanceHead(WaitNode h, WaitNode nh)
            {
                if (head == h && Interlocked.CompareExchange <WaitNode>(ref head, nh, h) == h)
                {
                    h.next = h;     // mark the previous head wait node as unlinked.
                    return(true);
                }
                return(false);
            }
Example #22
0
        //
        // Executes the prologue of the TryAdd operation.
        //

        internal override WaitNode TryAddPrologue(StParker pk, int key, T di, ref WaitNode ignored)
        {
            if (pk.TryLock())
            {
                pk.UnparkSelf(key);
            }
            AddWorker(di);
            return(null);
        }
Example #23
0
 /// <summary>
 /// This method prints the waitNode and make an indentation
 /// It accepts a visit of TimeAmount and Timemodifier
 /// Then outdent
 /// </summary>
 /// <param name="waitNode">The node to print.</param>
 /// <returns>Returns null</returns>
 public override object Visit(WaitNode waitNode)
 {
     Print("WaitNode");
     Indent++;
     waitNode.TimeAmount.Accept(this);
     waitNode.TimeModifier.Accept(this);
     Indent--;
     return(null);
 }
Example #24
0
            //
            // Advances the queue's head.
            //

            private bool AdvanceHead(WaitNode h, WaitNode nh)
            {
                if (head == h && Interlocked.CompareExchange <WaitNode>(ref head, nh, h) == h)
                {
                    h.next = h;     // Forget next.
                    return(true);
                }
                return(false);
            }
Example #25
0
        //
        // Cancels the specified take operation.
        //

        internal override void  CancelTakeAttempt(WaitNode wn, WaitNode ignored)
        {
            if (wn.next != wn)
            {
                qlock.Enter();
                waitQueue.Remove(wn);
                qlock.Exit();
            }
        }
Example #26
0
            //
            // Unlinks the specified wait node from the stack.
            //

            internal override void Unlink(WaitNode wn, WaitNode ignored)
            {
                //
                // Absorb the cancelled wait nodes at the top of the stack.
                //

                WaitNode p;

                do
                {
                    if ((p = top) == null)
                    {
                        return;
                    }
                    if (p.parker.IsLocked &&
                        Interlocked.CompareExchange <WaitNode>(ref top, p.next, p) == p)
                    {
                        //
                        // If the wait block was at the top of the stack, return.
                        //

                        if (p == wn)
                        {
                            return;
                        }
                    }
                    else
                    {
                        break;
                    }
                } while (true);

                //
                // Compute a wait node that follows "wn" and try to unsplice
                // the wait node.
                //

                WaitNode past;

                if ((past = wn.next) != null && past.parker.IsLocked)
                {
                    past = past.next;
                }
                while (p != null && p != past)
                {
                    WaitNode n = p.next;
                    if (n != null && n.parker.IsLocked)
                    {
                        p.CasNext(n, n.next);
                    }
                    else
                    {
                        p = n;
                    }
                }
            }
Example #27
0
            internal override void Insert(WaitNode w)
            {
                int idx = (System.Int32)Thread.CurrentThread.Priority - (int)System.Threading.ThreadPriority.Lowest;

                cells_[idx].Insert(w);
                if (idx > maxIndex_)
                {
                    maxIndex_ = idx;
                }
            }
            //
            // Unparks all the wait nodes in the queue.
            //

            internal void UnparkAll()
            {
                WaitNode <Q> p = head;

                while (p != null)
                {
                    p.Unpark(StParkStatus.Success);
                    p = p.next;
                }
            }
            public WorkQueueLocals(CustomWorkQueueBase <TWorkItem> workQueue)
            {
                _workQueue = workQueue;

                Random    = new FastRandom(Thread.CurrentThread.ManagedThreadId);
                Queue     = new WorkStealingQueue <TWorkItem>();
                Semaphore = new SemaphoreSlim(0, 1);
                WaitNode  = new WaitNode(Semaphore);

                WorkStealingQueueList.Add(ref _workQueue._localQueues, Queue);
            }
            //
            // Dequeues a wait node from a non-empty queue.
            //

            internal WaitNode <Q> Dequeue()
            {
                WaitNode <Q> n = head;

                if ((head = n.next) == null)
                {
                    tail = null;
                }
                n.next = n;     // Mark the wait node as unlinked.
                return(n);
            }
Example #31
0
 internal override void Insert(WaitNode w)
 {
     int idx = (System.Int32) Thread.CurrentThread.Priority - (int) System.Threading.ThreadPriority.Lowest;
     cells_[idx].Insert(w);
     if (idx > maxIndex_)
         maxIndex_ = idx;
 }
Example #32
0
 /// <summary>
 /// assumed not to block
 /// </summary>
 internal abstract void Insert(WaitNode w);
Example #33
0
 internal override void Insert(WaitNode w)
 {
     if (tail_ == null)
         head_ = tail_ = w;
     else
     {
         tail_.next = w;
         tail_ = w;
     }
 }
Example #34
0
 internal override WaitNode Extract()
 {
     if (head_ == null)
         return null;
     else
     {
         WaitNode w = head_;
         head_ = w.next;
         if (head_ == null)
             tail_ = null;
         w.next = null;
         return w;
     }
 }
Example #35
0
 /// <summary>
 /// clone
 /// </summary>
 /// <returns></returns>
 public IBehaviourNode Clone()
 {
     var behaviourNode = new WaitNode(this.duration, this.variation);
     base.CopyTo(behaviourNode);
     return behaviourNode;
 }
            //
            // Enqueues a wait node at the tail of the queue.
            //

            internal void Enqueue(WaitNode wn) {
                if (head == null) {
                    head = wn;
                } else {
                    tail.next = wn;
                }
                tail = wn;
            }
            //
            // Removes the specified wait node from the queue.
            //

            internal void Remove(WaitNode wn) {

                //
                // If the wait node was already removed, return.
                //

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

                //
                // Compute the previous wait node and perform the remove.
                //

                WaitNode p = head;
                WaitNode pv = null;
                while (p != null) {
                    if (p == wn) {
                        if (pv == null) {
                            if ((head = wn.next) == null) {
                                tail = null;
                            }
                        } else {
                            if ((pv.next = wn.next) == null)
                                tail = pv;
                        }
                        return;
                    }
                    pv = p;
                    p = p.next;
                }
                throw new InvalidOperationException("WaitOne node not found in the queue!");
            }
            //
            // Dequeues a wait node from a non-empty queue.
            //

            internal WaitNode Dequeue() {
                WaitNode wn;
                if ((head = (wn = head).next) == null) {
                    tail = null;
                }
                wn.next = wn;       // mark wait node as unlinked.
                return wn;
            }
            /*++
             * 
             * The following methods are used when the queue is used as a
             * wake up list holding locked wait nodes.
             *
             --*/

            //
            // Adds the wait node at the tail of the queue.
            //

            internal void AddToWakeList(WaitNode wn) {
                if (!wn.UnparkInProgress(StParkStatus.Success)) {
                    if (head == null) {
                        head = wn;
                    } else {
                        tail.next = wn;
                    }
                    wn.next = null;
                    tail = wn;
                }
            }
        //
        // 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;
        }
        //
        // Exits the read lock.
        //

        public void ExitRead() {
            int tid = Thread.CurrentThread.ManagedThreadId;
            ReaderCounter rc = rdCounts.Lookup(tid);
            if (rc == null) {
                throw new StSynchronizationLockException("Mismatched read");
            }

            //
            // If this is a recursive exit of the read lock, decrement
            // the recursive acquisition count and return.
            //

            if (--rc.count > 0) {
                return;
            }

            //
            // The read lock was exited by the current thread. So, if the current
            // thread is also the upgrader clear the *upgraderIsReader* flag
            // and return, because no other waiter thread can be released.
            //

            if (tid == upgrader) {
                upgraderIsReader = false;
                return;
            }

            //
            // Acquire the spinlock that protecteds the r/u/w lock shared state.
            // Then, decrement the number of active readers; if this is not the
            // unique lock reader, release the spin lock and return.
            //

            slock.Enter();
            if (--readers > 0) {
                slock.Exit();
                return;
            }

            //
            // Here, we know that the r/u/w lock doesn't have readers.
            // First, check the current upgarder is waiting to enter the write lock,
            // and, if so, try to release it.
            //

            WaitNode w;
            if ((w = upgToWrWaiter) != null) {
                upgToWrWaiter = null;
                if (w.TryLock()) {
                    writer = w.tid;
                    slock.Exit();
                    w.Unpark(StParkStatus.Success);
                    return;
                }
            }

            //
            // If the r/w lock isn't in the upgrade read mode nor in write
            // mode, try to wake up a waiting writer; failing that, try to
            // wake up a waiting upgrader and/or all waiting readers.
            //

            if (!(upgrader == UNOWNED && writer == UNOWNED &&
                 (TryWakeupWriter() || TryWakeupUpgraderAndReaders()))) {
                slock.Exit();
            }
        }
        //
        // 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;
        }