/// <summary> Handles the delimiter read from the pipe. </summary> private void Delimit() { if (m_state == State.Active) { m_state = State.Delimited; return; } if (m_state == State.Pending) { m_outboundPipe = null; SendPipeTermAck(m_peer); m_state = State.Terminating; return; } // Delimiter in any other state is invalid. Debug.Assert(false); }
/// <summary> Create a pipe pair for bi-directional transfer of messages. </summary> /// <param name="parents">The parents.</param> /// <param name="highWaterMarks">First HWM is for messages passed from first pipe to the second pipe. /// Second HWM is for messages passed from second pipe to the first pipe.</param> /// <param name="delays">Delay specifies how the pipe behaves when the peer terminates. If true /// pipe receives all the pending messages before terminating, otherwise it /// terminates straight away.</param> /// <returns>A pipe pair for bi-directional transfer of messages. </returns> public static Pipe[] PipePair(ZObject[] parents, int[] highWaterMarks, bool[] delays) { // Creates two pipe objects. These objects are connected by two ypipes, // each to pass messages in one direction. YPipe <Msg> upipe1 = new YPipe <Msg>(Config.MessagePipeGranularity, "upipe1"); YPipe <Msg> upipe2 = new YPipe <Msg>(Config.MessagePipeGranularity, "upipe2"); var pipes = new Pipe[2]; pipes[0] = new Pipe(parents[0], upipe1, upipe2, highWaterMarks[1], highWaterMarks[0], delays[0]); pipes[1] = new Pipe(parents[1], upipe2, upipe1, highWaterMarks[0], highWaterMarks[1], delays[1]); pipes[0].SetPeer(pipes[1]); pipes[1].SetPeer(pipes[0]); return(pipes); }
/// <summary> Temporarily disconnects the inbound message stream and drops /// all the messages on the fly. Causes 'hiccuped' event to be generated in the peer. </summary> public void Hiccup() { // If termination is already under way do nothing. if (m_state != State.Active) { return; } // We'll drop the pointer to the in-pipe. From now on, the peer is // responsible for deallocating it. m_inboundPipe = null; // Create new in-pipe. m_inboundPipe = new YPipe <Msg>(Config.MessagePipeGranularity, "inpipe"); m_inActive = true; // Notify the peer about the hiccup. SendHiccup(m_peer, m_inboundPipe); }
///<remarks> Constructor is private as pipe can only be created using <see cref="PipePair"/> method. </remarks> private Pipe(ZObject parent, YPipe <Msg> inboundPipe, YPipe <Msg> outboundPipe, int inHighWatermark, int outHighWatermark, bool delay) : base(parent) { m_parent = parent; m_inboundPipe = inboundPipe; m_outboundPipe = outboundPipe; m_inActive = true; m_outActive = true; m_highWatermark = outHighWatermark; m_lowWatermark = ComputeLowWatermark(inHighWatermark); m_numberOfMessagesRead = 0; m_numberOfMessagesWritten = 0; m_peersMsgsRead = 0; m_peer = null; m_sink = null; m_state = State.Active; m_delay = delay; }
public Mailbox(String name) { m_cpipe = new YPipe <Command>(Config.CommandPipeGranularity, "mailbox"); m_sync = new object(); m_signaler = new Signaler(); // Get the pipe into passive state. That way, if the users starts by // polling on the associated file descriptor it will get woken up when // new command is posted. Command cmd = new Command(); bool ok = m_cpipe.Read(ref cmd); Debug.Assert(!ok); m_active = false; m_name = name; }
public IOThreadMailbox([CanBeNull] string name, [NotNull] Proactor proactor, [NotNull] IMailboxEvent mailboxEvent) { m_proactor = proactor; m_mailboxEvent = mailboxEvent; m_cpipe = new YPipe <Command>(Config.CommandPipeGranularity, "mailbox"); m_sync = new object(); // Get the pipe into passive state. That way, if the users starts by // polling on the associated file descriptor it will get woken up when // new command is posted. var cmd = new Command(); bool ok = m_cpipe.Read(ref cmd); Debug.Assert(!ok); m_name = name; m_disposed = false; }
protected override void ProcessHiccup(object pipe) { // Destroy old outpipe. Note that the read end of the pipe was already // migrated to this thread. Debug.Assert(m_outboundPipe != null); m_outboundPipe.Flush(); while (m_outboundPipe.Read() != null) { } // Plug in the new outpipe. Debug.Assert(pipe != null); m_outboundPipe = (YPipe <Msg>)pipe; m_outActive = true; // If appropriate, notify the user about the hiccup. if (m_state == State.Active) { m_sink.Hiccuped(this); } }
protected override void ProcessPipeTermAck() { // Notify the user that all the references to the pipe should be dropped. Debug.Assert(m_sink != null); m_sink.Terminated(this); // In terminating and double_terminated states there's nothing to do. // Simply deallocate the pipe. In terminated state we have to ack the // peer before deallocating this side of the pipe. All the other states // are invalid. if (m_state == State.Terminated) { m_outboundPipe = null; SendPipeTermAck(m_peer); } else { Debug.Assert(m_state == State.Terminating || m_state == State.DoubleTerminated); } // We'll deallocate the inbound pipe, the peer will deallocate the outbound // pipe (which is an inbound pipe from its point of view). // First, delete all the unread messages in the pipe. We have to do it by // hand because msg_t doesn't have automatic destructor. Then deallocate // the ypipe itself. var msg = new Msg(); if (m_inboundPipe != null) { while (m_inboundPipe.Read(ref msg)) { msg.Close(); } } m_inboundPipe = null; }
/// <summary> /// Ask pipe to terminate. The termination will happen asynchronously /// and user will be notified about actual deallocation by 'terminated' /// event. /// </summary> /// <param name="delay">if set to <c>true</c>, the pending messages will be processed /// before actual shutdown. </param> public void Terminate(bool delay) { // Overload the value specified at pipe creation. m_delay = delay; // If terminate was already called, we can ignore the duplicate invocation. if (m_state == State.Terminated || m_state == State.DoubleTerminated) { return; } // If the pipe is in the phase of async termination, it's going to // closed anyway. No need to do anything special here. if (m_state == State.Terminating) { return; } if (m_state == State.Active) { // The simple sync termination case. Ask the peer to terminate and wait // for the ack. SendPipeTerm(m_peer); m_state = State.Terminated; } else if (m_state == State.Pending && !m_delay) { // There are still pending messages available, but the user calls // 'terminate'. We can act as if all the pending messages were read. m_outboundPipe = null; SendPipeTermAck(m_peer); m_state = State.Terminating; } else if (m_state == State.Pending) { // If there are pending messages still available, do nothing. } else if (m_state == State.Delimited) { // We've already got delimiter, but not term command yet. We can ignore // the delimiter and ack synchronously terminate as if we were in // active state. SendPipeTerm(m_peer); m_state = State.Terminated; } else { // There are no other states. Debug.Assert(false); } // Stop outbound flow of messages. m_outActive = false; if (m_outboundPipe != null) { // Drop any unfinished outbound messages. Rollback(); // Write the delimiter into the pipe. Note that watermarks are not // checked; thus the delimiter can be written even when the pipe is full. var msg = new Msg(); msg.InitDelimiter(); m_outboundPipe.Write(ref msg, false); Flush(); } }