void zmq::pipe_t::process_pipe_term_ack () { // Notify the user that all the references to the pipe should be dropped. zmq_assert (sink); sink->pipe_terminated (this); // In term_ack_sent and term_req_sent2 states there's nothing to do. // Simply deallocate the pipe. In term_req_sent1 state we have to ack // the peer before deallocating this side of the pipe. // All the other states are invalid. if (state == term_req_sent1) { outpipe = NULL; send_pipe_term_ack (peer); } else zmq_assert (state == term_ack_sent || state == term_req_sent2); // 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. msg_t msg; while (inpipe->read (&msg)) { int rc = msg.close (); errno_assert (rc == 0); } delete inpipe; // Deallocate the pipe object delete this; }
void zmq::pipe_t::terminate (bool delay_) { // Overload the value specified at pipe creation. delay = delay_; // If terminate was already called, we can ignore the duplicate invocation. if (state == term_req_sent1 || state == term_req_sent2) { return; } // If the pipe is in the final phase of async termination, it's going to // closed anyway. No need to do anything special here. else if (state == term_ack_sent) { return; } // The simple sync termination case. Ask the peer to terminate and wait // for the ack. else if (state == active) { send_pipe_term (peer); state = term_req_sent1; } // There are still pending messages available, but the user calls // 'terminate'. We can act as if all the pending messages were read. else if (state == waiting_for_delimiter && !delay) { // Drop any unfinished outbound messages. rollback (); outpipe = NULL; send_pipe_term_ack (peer); state = term_ack_sent; } // If there are pending messages still available, do nothing. else if (state == waiting_for_delimiter) { } // 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. else if (state == delimiter_received) { send_pipe_term (peer); state = term_req_sent1; } // There are no other states. else { zmq_assert (false); } // Stop outbound flow of messages. out_active = false; if (outpipe) { // 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. msg_t msg; msg.init_delimiter (); outpipe->write (msg, false); flush (); } }
void zmq::writer_t::process_pipe_term () { if (endpoint) endpoint->detach_outpipe (this); reader_t *p = peer; peer = NULL; send_pipe_term_ack (p); }
void xs::pipe_t::process_pipe_term () { // 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 (state == active) { if (!delay) { state = terminating; outpipe = NULL; send_pipe_term_ack (peer); return; } else { 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 (state == delimited) { state = terminating; outpipe = NULL; send_pipe_term_ack (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 (state == terminated) { state = double_terminated; outpipe = NULL; send_pipe_term_ack (peer); return; } // pipe_term is invalid in other states. xs_assert (false); }
void zmq::pipe_t::process_delimiter () { zmq_assert (_state == active || _state == waiting_for_delimiter); if (_state == active) _state = delimiter_received; else { _out_pipe = NULL; send_pipe_term_ack (_peer); _state = term_ack_sent; } }
void zmq::pipe_t::process_pipe_term () { zmq_assert (state == active || state == delimiter_received || state == term_req_sent1); // 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 term_ack_sent state. // Otherwise we'll hang up in waiting_for_delimiter state till all // pending messages are read. if (state == active) { if (delay) state = waiting_for_delimiter; else { state = term_ack_sent; outpipe = NULL; send_pipe_term_ack (peer); } } // Delimiter happened to arrive before the term command. Now we have the // term command as well, so we can move straight to term_ack_sent state. else if (state == delimiter_received) { state = term_ack_sent; outpipe = NULL; send_pipe_term_ack (peer); } // 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. else if (state == term_req_sent1) { state = term_req_sent2; outpipe = NULL; send_pipe_term_ack (peer); } }
void zmq::pipe_t::process_delimiter () { zmq_assert (state == active || state == waiting_for_delimiter); if (state == active) state = delimiter_received; else { outpipe = NULL; send_pipe_term_ack (peer); state = term_ack_sent; } }
void zmq::writer_t::process_pipe_term () { send_pipe_term_ack (reader); // The above command allows reader to deallocate itself and the pipe. // For safety's sake we'll drop the pointers here. reader = NULL; pipe = NULL; // Notify owner about the termination. zmq_assert (sink); sink->terminated (this); // Deallocate the resources. delete this; }
void xs::pipe_t::delimit () { if (state == active) { state = delimited; return; } if (state == pending) { outpipe = NULL; send_pipe_term_ack (peer); state = terminating; return; } // Delimiter in any other state is invalid. xs_assert (false); }