/// <summary> /// This method is used to post calls to the parent engine by the Localnode class /// </summary> internal void PostMessageToParent(LocalCallDescriptor callDescriptor, bool waitForCompletion) { nodeCommandQueue.Enqueue(callDescriptor); try { if (waitForCompletion) { // We should not be on the running on the callback writer thread ErrorUtilities.VerifyThrow(Thread.CurrentThread != writerThread, "Should never call this function from the writer thread"); // We need to block until the event we posted has been processed, but if the writer thread // exit due to an error the shared memory is no longer valid so there is no way to send the message while (!writerThreadHasExited && nodeCommandQueue.Count > 0) { nodeCommandQueue.QueueEmptyEvent.WaitOne(1000, false); // Check if the communication threads are supposed to exit if (exitCommunicationThreads.WaitOne(0, false)) { break; } } } } catch (Exception e) { // Clear the current queue since something in the queue has caused a problem nodeCommandQueue.Clear(); // Try to send the exception back to the parent localNode.ReportNonFatalCommunicationError(e); } }
/// <summary> /// Given a non-void call descriptor, calls it and retrieves the return value. /// </summary> /// <param name="callDescriptor"></param> /// <returns></returns> private object GetReplyForCallDescriptor(LocalCallDescriptor callDescriptor) { // ReplyFromParentArrived is a TLS field, so initialize it if it's empty if (replyFromParentArrived == null) { replyFromParentArrived = new ManualResetEvent(false); } replyFromParentArrived.Reset(); int requestingCallNumber = callDescriptor.CallNumber; ReplyData replyData = new ReplyData(); replyData.waitEvent = replyFromParentArrived; // Register our wait event for the call id lock (repliesFromParent) { repliesFromParent[requestingCallNumber] = replyData; } nodeCommandQueue.Enqueue(callDescriptor); replyFromParentArrived.WaitOne(); LocalCallDescriptor reply = null; // Unregister the wait event lock (repliesFromParent) { // Get the reply reply = replyData.reply; ErrorUtilities.VerifyThrow(reply != null, "We must have a reply if the wait event was set"); repliesFromParent.Remove(requestingCallNumber); } return(reply.GetReplyData()); }
/// <summary> /// Given a non-void call descriptor, calls it and retrieves the return value. /// </summary> /// <param name="callDescriptor"></param> /// <returns></returns> private object GetReplyForCallDescriptor(LocalCallDescriptor callDescriptor) { // ReplyFromParentArrived is a TLS field, so initialize it if it's empty if (replyFromParentArrived == null) { replyFromParentArrived = new ManualResetEvent(false); } replyFromParentArrived.Reset(); int requestingCallNumber = callDescriptor.CallNumber; ReplyData replyData = new ReplyData(); replyData.waitEvent = replyFromParentArrived; // Register our wait event for the call id lock (repliesFromParent) { repliesFromParent[requestingCallNumber] = replyData; } nodeCommandQueue.Enqueue(callDescriptor); replyFromParentArrived.WaitOne(); LocalCallDescriptor reply = null; // Unregister the wait event lock (repliesFromParent) { // Get the reply reply = replyData.reply; ErrorUtilities.VerifyThrow(reply != null, "We must have a reply if the wait event was set"); repliesFromParent.Remove(requestingCallNumber); } return reply.GetReplyData(); }