// // 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); }
// // 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; } } }
// // 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); }
// // 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); }
// // 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; } } }