internal Pipe(Socket parent, YPipe<Frame> inpipe, YPipe<Frame> outpipe, int inHighWatermark, int outHighWatermark) : base(parent) { m_inpipe = inpipe; m_outpipe = outpipe; m_inActive = true; m_outActive = true; m_highWatermark = outHighWatermark; ComputeLowWatermark(inHighWatermark); m_delay = true; m_state = State.Active; }
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 = m_cpipe.Read(); Debug.Assert(cmd == null); m_active = false; m_name = name; }
// Constructor is private. Pipe can only be created using // pipepair function. private Pipe(ZObject parent, YPipe<Msg> inpipe, YPipe<Msg> outpipe, int inhwm, int outhwm, bool delay) : base(parent) { m_parent = parent; m_inpipe = inpipe; m_outpipe = outpipe; m_inActive = true; m_outActive = true; m_hwm = outhwm; m_lwm = ComputeLwm (inhwm); m_msgsRead = 0; m_msgsWritten = 0; m_peersMsgsRead = 0; m_peer = null ; m_sink = null ; m_state = State.Active; m_delay = delay; }
///<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; }
/// <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 dispose is already under way do nothing. if (m_state == State.Active) { // We'll drop the reference to the inpipe. From now on, the peer is // responsible for deallocating it. m_inpipe = null; // Create new inpipe. m_inpipe = new YPipe<Frame>(); m_inActive = true; // Notify the peer about the hiccup. CommandDispatcher.SendHiccup(m_peer, m_inpipe); } }
/// <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); }
/// <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> /// 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(); } }
/// <summary> /// Process the pipe-termination ack. /// </summary> 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(); while (m_inboundPipe.TryRead(out msg)) { msg.Close(); } m_inboundPipe = null; }
protected override void ProcessPipeTerm() { // This is the simple case of peer-induced termination. If there are no // more pending messages to read, or if the pipe was configured to drop // pending messages, we can move directly to the terminating state. // Otherwise we'll hang up in pending state till all the pending messages // are sent. if (m_state == State.Active) { if (!m_delay) { m_state = State.Terminating; m_outboundPipe = null; SendPipeTermAck(m_peer); } else m_state = State.Pending; return; } // Delimiter happened to arrive before the term command. Now we have the // term command as well, so we can move straight to terminating state. if (m_state == State.Delimited) { m_state = State.Terminating; m_outboundPipe = null; SendPipeTermAck(m_peer); return; } // This is the case where both ends of the pipe are closed in parallel. // We simply reply to the request by ack and continue waiting for our // own ack. if (m_state == State.Terminated) { m_state = State.DoubleTerminated; m_outboundPipe = null; SendPipeTermAck(m_peer); return; } // pipe_term is invalid in other states. Debug.Assert(false); }
/// <summary> /// This method is called to assign the specified pipe as a replacement for the outbound pipe that was being used. /// </summary> /// <param name="pipe">the pipe to use for writing</param> /// <remarks> /// A "Hiccup" occurs when an outbound pipe experiences something like a transient disconnect or for whatever other reason /// is no longer available for writing to. /// </remarks> protected override void ProcessHiccup(object pipe) { // Destroy old out-pipe. Note that the read end of the pipe was already // migrated to this thread. Debug.Assert(m_outboundPipe != null); m_outboundPipe.Flush(); var msg = new Msg(); while (m_outboundPipe.TryRead(out msg)) { msg.Close(); } // Plug in the new out-pipe. 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); }
public static Pipe[] PipePair([NotNull] ZObject[] parents, [NotNull] int[] highWaterMarks, [NotNull] int[] lowWaterMarks, [NotNull] bool[] delays) { // Creates two pipe objects. These objects are connected by two ypipes, // each to pass messages in one direction. var upipe1 = new YPipe<Msg>(Config.MessagePipeGranularity, "upipe1"); var upipe2 = new YPipe<Msg>(Config.MessagePipeGranularity, "upipe2"); var pipes = new[] { new Pipe(parents[0], upipe1, upipe2, highWaterMarks[1], highWaterMarks[0], lowWaterMarks[1], delays[0]), new Pipe(parents[1], upipe2, upipe1, highWaterMarks[0], highWaterMarks[1], lowWaterMarks[0], delays[1]) }; pipes[0].SetPeer(pipes[1]); pipes[1].SetPeer(pipes[0]); return pipes; }
internal override void Process(HiccupCommand command) { // Destroy old outpipe. Note that the read end of the pipe was already // migrated to this thread. m_outpipe.Flush(); Frame frame; // empty the outpipe while (m_outpipe.TryRead(out frame)) { if (!frame.More) m_messagesWritten--; frame.Close(); } // Plug in the new outpipe. m_outpipe = command.Pipe; m_outActive = true; // If appropriate, notify the user about the hiccup. if (m_state == State.Active) { var temp = Hiccuped; if (temp != null) { temp(this, new PipeEventArgs(this)); } } }
// Create a pipepair for bi-directional transfer of messages. // 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. // 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. public static void Pipepair(ZObject[] parents, Pipe[] pipes, int[] hwms, 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"); pipes [0] = new Pipe(parents [0], upipe1, upipe2, hwms [1], hwms [0], delays [0]); pipes [1] = new Pipe(parents [1], upipe2, upipe1, hwms [0], hwms [1], delays [1]); pipes [0].SetPeer (pipes [1]); pipes [1].SetPeer (pipes [0]); }
public static void SendHiccup(Pipe destination, YPipe<Frame> pipe) { var command = new HiccupCommand(destination, pipe); SendCommand(command); }
public HiccupCommand(BaseObject destination, YPipe<Frame> pipe) : base(destination) { Pipe = pipe; }
public static void CreatePair(Socket connectSocket, Socket bindSocket, int connetHighWatermark, int bindHighwatermark, out Pipe connectPipe, out Pipe bindPipe) { // Creates two pipe objects. These objects are connected by two ypipes, // each to pass messages in one direction. YPipe<Frame> upipe1 = new YPipe<Frame>(); YPipe<Frame> upipe2 = new YPipe<Frame>(); connectPipe = new Pipe(connectSocket, upipe1, upipe2, connetHighWatermark, bindHighwatermark); bindPipe = new Pipe(bindSocket, upipe2, upipe1, bindHighwatermark, connetHighWatermark); connectPipe.SetPeer(bindPipe); bindPipe.SetPeer(connectPipe); }
private void CompleteClose() { m_outpipe = null; m_state = State.Closed; // We'll deallocate the inbound pipe, the peer will deallocate the outbound // pipe (which is an inbound pipe from its point of view). // Delete all the unread messages in the pipe. We have to do it by // hand because Frame need to release buffer pool memory. Frame frame; while (m_inpipe.TryRead(out frame)) { frame.Close(); } // Notify the user that all the references to the pipe should be dropped. var temp = PipeClosed; if (temp != null) { temp(this, new PipeEventArgs(this)); } }