Beispiel #1
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);
            }
Beispiel #2
0
            //
            // Unlinks the specified wait node from the queue.
            //

            private void Unlink(WaitNode wn, WaitNode pred)
            {
                while (pred.next == wn)
                {
                    //
                    // Remove the cancelled wait nodes that are at front
                    // of the queue.
                    //


                    WaitNode h, hn;
                    if ((hn = (h = head).next) != null && hn.IsLocked)
                    {
                        AdvanceHead(h, hn);
                        continue;
                    }

                    //
                    // If the queue is empty, return.
                    //

                    WaitNode t, tn;
                    if ((t = tail) == h)
                    {
                        return;
                    }

                    //
                    // If the queue isn't in a quiescent state, retry.
                    //

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

                    //
                    // If the wait node isn't at tail of the queue, try to
                    // unlink it and return if succeed.
                    //

                    if (wn != t)
                    {
                        WaitNode wnn;
                        if ((wnn = wn.next) == wn || pred.CasNext(wn, wnn))
                        {
                            return;
                        }
                    }

                    //
                    // Try unlinking previous cancelled wait block.
                    //

                    WaitNode dp;
                    if ((dp = toUnlink) != null)
                    {
                        WaitNode d, dn;
                        if ((d = dp.next) == dp ||
                            ((dn = d.next) != null && dp.CasNext(d, dn)))
                        {
                            CasToUnlink(dp, null);
                        }
                        if (dp == pred)
                        {
                            return;             // "wn" is an already saved node
                        }
                    }
                    else if (CasToUnlink(null, pred))
                    {
                        return;
                    }
                }
            }
Beispiel #3
0
            //
            // Receives a message, activativating the specified cancellers.
            //

            internal override bool Receive(out T request, out StRendezvousToken token,
                                           StCancelArgs cargs)
            {
                RecvWaitNode <T, R> wn = null;
                WaitNode            pred;

                do
                {
                    WaitNode h = head;
                    WaitNode t = tail;
                    WaitNode hn;
                    if ((hn = h.next) == null || hn.type == ReqType.Receive)
                    {
                        //
                        // The wait queue is empty or contains only receiver
                        // wait nodes. So, do the consistency checks in order to
                        // insert our wait node.
                        //

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

                        //
                        // Create a wait node, if we don't have one. However,
                        // return failure if a null timeout was specified.
                        //

                        if (wn == null)
                        {
                            if (cargs.Timeout == 0)
                            {
                                request = default(T);
                                token   = new StRendezvousToken(null);
                                return(false);
                            }
                            wn = new RecvWaitNode <T, R>();
                        }

                        //
                        // Try to enqueue the wait node.
                        //

                        if (t.CasNext(null, wn))
                        {
                            AdvanceTail(t, wn);
                            pred = t;
                            break;
                        }
                    }
                    else
                    {
                        //
                        // There is a sender wait node at the front of the queue.
                        // So, try to remove it to initiate the rendezvous.
                        //

                        if (AdvanceHead(h, hn))
                        {
                            if (hn.TryLock())
                            {
                                SendWaitNode <T, R> swn = (SendWaitNode <T, R>)hn;

                                //
                                // Get the request, then, If this is a send only
                                // request build a null rendezvous token and unpark
                                // the sender thread; otherwise, build a rendezvous token
                                // with the sender wait node.
                                //

                                request = swn.request;
                                if (swn.type == ReqType.SendOnly)
                                {
                                    token = new StRendezvousToken(null);
                                    swn.Unpark(StParkStatus.Success);
                                }
                                else
                                {
                                    token = new StRendezvousToken(swn);
                                }
                                return(true);
                            }
                        }
                    }
                } while (true);

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

                int ws = wn.Park(cargs);

                //
                // If succeed, retrive the request and the rendezvous token
                // from the wait node and return success.
                //

                if (ws == StParkStatus.Success)
                {
                    request = wn.request;
                    token   = new StRendezvousToken(wn.sender);
                    return(true);
                }

                //
                // The receive was cancelled; so, unlink our wait node from
                // the wait queue and report the failure appropriately.
                //

                Unlink(wn, pred);
                request = default(T);
                token   = default(StRendezvousToken);
                StCancelArgs.ThrowIfException(ws);
                return(false);
            }
Beispiel #4
0
            //
            // Sends a message, activating the specified cancellers.
            //

            internal override bool Send(ReqType type, T request, out R response,
                                        StCancelArgs cargs)
            {
                SendWaitNode <T, R> wn   = null;
                WaitNode            pred = null;
                bool enableCancel        = true;

                do
                {
                    WaitNode h = head;
                    WaitNode t = tail;
                    WaitNode hn;
                    if ((hn = h.next) == null || hn.type != ReqType.Receive)
                    {
                        //
                        // The wait queue is empty or contains only sender
                        // wait nodes. So, do the consistency checks in order
                        // to insert our wait node.
                        //

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

                        //
                        // Create a wait node, if we don't have one. However,
                        // if a null timeout was specified, return failure.
                        //

                        if (wn == null)
                        {
                            if (cargs.Timeout == 0)
                            {
                                response = default(R);
                                return(false);
                            }
                            wn = new SendWaitNode <T, R>(type, request);
                        }

                        //
                        // Try to enqueue the wait node.
                        //

                        if (t.CasNext(null, wn))
                        {
                            //
                            // Set the new tail, save the predecessor wait node
                            // and break the loop.
                            //

                            AdvanceTail(t, wn);
                            pred = t;
                            break;
                        }
                    }
                    else
                    {
                        //
                        // It seems that the wait node that is at front of the queue
                        // belongs to a receive thread; so, try to remove it and
                        // to initiate the rendezvous with the underlying thread.
                        //

                        if (AdvanceHead(h, hn))
                        {
                            if (hn.TryLock())
                            {
                                //
                                // We locked the receiver's wait node. So, get
                                // the request message.
                                //

                                RecvWaitNode <T, R> rwn = (RecvWaitNode <T, R>)hn;
                                rwn.request = request;

                                //
                                // If this a send only request, sets the sender to null,
                                // unpark the receiver thread and return success.
                                //

                                if (type == ReqType.SendOnly)
                                {
                                    rwn.sender = null;
                                    rwn.Unpark(StParkStatus.Success);
                                    response = default(R);
                                    return(true);
                                }

                                //
                                // This is a send and reply request. So, create a wait
                                // node in order to park the current thread and pass the
                                // wait node to the receiver through the rendezvous token.
                                //

                                if (wn == null)
                                {
                                    wn = new SendWaitNode <T, R>(ReqType.SendWaitReply);
                                }
                                rwn.sender = wn;
                                wn.SelfCancel();

                                //
                                // Unpark the receiver thread and go to wait until
                                // reply. After the rendezvous is initiated the
                                // cancellers are deactivated.
                                //

                                rwn.Unpark(StParkStatus.Success);
                                enableCancel = false;
                                break;
                            }
                        }
                    }
                } while (true);

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

                int ws;

                if (enableCancel)
                {
                    ws = wn.Park(cargs);
                }
                else
                {
                    wn.Park();
                    ws = StParkStatus.Success;
                }

                //
                // If succeed, retrieve the response from the wait node
                // and return success.
                //

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

                //
                // The send was cancelled; so unlink the wait node from
                // the wait queue and report the failure appropriately.
                //

                Unlink(wn, pred);
                response = default(R);
                StCancelArgs.ThrowIfException(ws);
                return(false);
            }
Beispiel #5
0
            //
            // Unlinks the specified wait block from the queue.
            //

            internal override void Unlink(WaitNode wn, WaitNode pred)
            {
                while (pred.next == wn)
                {
                    //
                    // Remove all locked wait nodes that are at the front of
                    // the queue.
                    //

                    WaitNode h, hn;
                    if ((hn = (h = head).next) != null && hn.parker.IsLocked)
                    {
                        AdvanceHead(h, hn);
                        continue;
                    }

                    //
                    // If the queue is already empty, return.
                    //

                    WaitNode t;
                    if ((t = tail) == h)
                    {
                        return;
                    }

                    //
                    // If the queue's state changed underneath us, retry.
                    //

                    WaitNode tn = t.next;
                    if (t != tail)
                    {
                        continue;
                    }

                    //
                    // If an insert is in progress, advance the tail and retry.
                    //

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

                    //
                    // If the wait node is not at the tail of the queue, try
                    // to unlink it.
                    //

                    if (wn != t)
                    {
                        WaitNode wnn;
                        if ((wnn = wn.next) == wn || pred.CasNext(wn, wnn))
                        {
                            return;
                        }
                    }

                    //
                    // The wait node is at the tail of the queue,take into
                    // account the *toUnlink* wait node.
                    //

                    WaitNode dp;
                    if ((dp = toUnlink) != null)
                    {
                        //
                        // Try unlinking previous cancelled wait block.
                        //

                        WaitNode d, dn;
                        if ((d = dp.next) == dp ||
                            ((dn = d.next) != null && dp.CasNext(d, dn)))
                        {
                            CasToUnlink(dp, null);
                        }
                        if (dp == pred)
                        {
                            return;             // wn is an already saved node
                        }
                    }
                    else if (CasToUnlink(null, pred))
                    {
                        return;
                    }
                }
            }