Exemple #1
0
        /// <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);
        }
Exemple #2
0
        /// <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);
        }
Exemple #3
0
        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);
        }
Exemple #4
0
 /// <summary>
 /// Create a new Pipe object with the given parent, and inbound and outbound YPipes.
 /// </summary>
 /// <remarks>
 /// Constructor is private as pipe can only be created using <see cref="PipePair"/> method.
 /// </remarks>
 private Pipe(
     [NotNull] ZObject parent, [NotNull] YPipe <Msg> inboundPipe, [NotNull] YPipe <Msg> outboundPipe,
     int inHighWatermark, int outHighWatermark, int predefinedLowWatermark)
     : base(parent)
 {
     m_parent                  = parent;
     m_inboundPipe             = inboundPipe;
     m_outboundPipe            = outboundPipe;
     m_inActive                = true;
     m_outActive               = true;
     m_highWatermark           = outHighWatermark;
     m_lowWatermark            = ComputeLowWatermark(inHighWatermark, predefinedLowWatermark);
     m_numberOfMessagesRead    = 0;
     m_numberOfMessagesWritten = 0;
     m_peersMsgsRead           = 0;
     m_peer  = null;
     m_sink  = null;
     m_state = State.Active;
     m_delay = true;
 }
Exemple #5
0
        /// <summary>
        /// Process the pipe-termination ack.
        /// </summary>
        protected override void ProcessPipeTermAck()
        {
            // Notify the user that all the references to the pipe should be dropped.
            Assumes.NotNull(m_sink);
            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;
                Assumes.NotNull(m_peer);
                SendPipeTermAck(m_peer);
            }
            else
            {
                Debug.Assert(m_state == State.Terminating || m_state == State.DoubleTerminated);
            }

            Assumes.NotNull(m_inboundPipe);

            // 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;
        }
Exemple #6
0
        /// <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);
            }
        }
Exemple #7
0
        /// <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();
            }
        }