// // 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); }
// // Receives a message, activating the specified cancellers. // internal override bool Receive(out T request, out StRendezvousToken token, StCancelArgs cargs) { RecvWaitNode <T, R> wn = null; do { WaitNode t = top; if (t == null || t.type == ReqType.Receive) { // // The stack is empty or the wait note at the top of the // stack belongs to a receiver thread. In this case, we must // create a wait node and push it onto the stack. // if (wn == null) { if (cargs.Timeout == 0) { request = default(T); token = new StRendezvousToken(null); return(false); } wn = new RecvWaitNode <T, R>(); } wn.next = t; if (Interlocked.CompareExchange <WaitNode>(ref top, wn, t) == t) { break; } } else { // // The top wait node belongs to a sender thread; so, try to // pop it from the stack. // if (Interlocked.CompareExchange <WaitNode>(ref top, t.next, t) == t) { // // Try to lock the associated parker and, if succeed, initiate // the rendezvous with its owner thread. // if (t.TryLock()) { SendWaitNode <T, R> swn = (SendWaitNode <T, R>)t; 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 from the wait node, build a // rendezvous token and return success. // if (ws == StParkStatus.Success) { request = wn.request; token = new StRendezvousToken(wn.sender); return(true); } // // The receive was cancelled; so, unlink the wait node from // the wait queue and return the failure approriately. // Unlink(wn); request = default(T); token = new StRendezvousToken(null); 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); }
// // 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; bool enableCancel = true; do { WaitNode t; if ((t = top) == null || t.type != ReqType.Receive) { // // The stack is empty or the first wait node belongs // to a sender thread. // if (wn == null) { if (cargs.Timeout == 0) { response = default(R); return(false); } wn = new SendWaitNode <T, R>(type, request); } wn.next = t; if (Interlocked.CompareExchange <WaitNode>(ref top, wn, t) == t) { break; } } else { // // The top wait node belongs to a receiver thread; // so, try to pop it from the stack. // if (Interlocked.CompareExchange <WaitNode>(ref top, t.next, t) == t) { // // Try to lock the associated parker and, if succeed, initiate // the rendezvous with its owner thread. // if (t.TryLock()) { RecvWaitNode <T, R> rwn = (RecvWaitNode <T, R>)t; rwn.request = request; if (type == ReqType.SendOnly) { rwn.sender = null; rwn.Unpark(StParkStatus.Success); response = default(R); return(true); } if (wn == null) { wn = new SendWaitNode <T, R>(ReqType.SendWaitReply); } rwn.sender = wn; wn.SelfCancel(); rwn.Unpark(StParkStatus.Success); enableCancel = false; break; } } } } while (true); // // Park the current thread, activating the specified cancellers, // but only if the rendezvous wasn't initiated. // int ws; if (enableCancel) { ws = wn.Park(cargs); } else { wn.Park(); ws = StParkStatus.Success; } // // If succeed, retrive the response 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); response = default(R); StCancelArgs.ThrowIfException(ws); return(false); }