epee: fix hang on exit
When the boost ioservice is stopped, pending work notifications will not happen. This includes deadline timers, which would otherwise time out the now cancelled I/O operations. When this happens just after starting a new connect operation, this can leave that operations in a state where it won't receive either the completion notification nor a timeout, causing a hang. This is fixed by keeping a list of connections corresponding to the connect operations, and cancelling them before stopping the boost ioservice. Note that the list of these connections can grow unbounded, as they're never cleaned up. Cleaning them up would involve working out which connections do not have any pending work, and it's not quite clear yet how to go about this.
This commit is contained in:
parent
17ff6f2114
commit
1e2f2d7da0
@ -111,6 +111,8 @@ namespace net_utils
|
|||||||
|
|
||||||
bool speed_limit_is_enabled() const; ///< tells us should we be sleeping here (e.g. do not sleep on RPC connections)
|
bool speed_limit_is_enabled() const; ///< tells us should we be sleeping here (e.g. do not sleep on RPC connections)
|
||||||
|
|
||||||
|
bool cancel();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
//----------------- i_service_endpoint ---------------------
|
//----------------- i_service_endpoint ---------------------
|
||||||
virtual bool do_send(const void* ptr, size_t cb); ///< (see do_send from i_service_endpoint)
|
virtual bool do_send(const void* ptr, size_t cb); ///< (see do_send from i_service_endpoint)
|
||||||
@ -303,6 +305,9 @@ namespace net_utils
|
|||||||
/// The next connection to be accepted
|
/// The next connection to be accepted
|
||||||
connection_ptr new_connection_;
|
connection_ptr new_connection_;
|
||||||
|
|
||||||
|
std::mutex connections_mutex;
|
||||||
|
std::deque<connection_ptr> connections_;
|
||||||
|
|
||||||
}; // class <>boosted_tcp_server
|
}; // class <>boosted_tcp_server
|
||||||
|
|
||||||
|
|
||||||
|
@ -565,7 +565,12 @@ PRAGMA_WARNING_DISABLE_VS(4355)
|
|||||||
return true;
|
return true;
|
||||||
CATCH_ENTRY_L0("connection<t_protocol_handler>::close", false);
|
CATCH_ENTRY_L0("connection<t_protocol_handler>::close", false);
|
||||||
}
|
}
|
||||||
|
//---------------------------------------------------------------------------------
|
||||||
|
template<class t_protocol_handler>
|
||||||
|
bool connection<t_protocol_handler>::cancel()
|
||||||
|
{
|
||||||
|
return close();
|
||||||
|
}
|
||||||
//---------------------------------------------------------------------------------
|
//---------------------------------------------------------------------------------
|
||||||
template<class t_protocol_handler>
|
template<class t_protocol_handler>
|
||||||
void connection<t_protocol_handler>::handle_write(const boost::system::error_code& e, size_t cb)
|
void connection<t_protocol_handler>::handle_write(const boost::system::error_code& e, size_t cb)
|
||||||
@ -871,6 +876,12 @@ POP_WARNINGS
|
|||||||
}
|
}
|
||||||
m_stop_signal_sent = true;
|
m_stop_signal_sent = true;
|
||||||
TRY_ENTRY();
|
TRY_ENTRY();
|
||||||
|
connections_mutex.lock();
|
||||||
|
for (auto &c: connections_)
|
||||||
|
{
|
||||||
|
c->cancel();
|
||||||
|
}
|
||||||
|
connections_mutex.unlock();
|
||||||
io_service_.stop();
|
io_service_.stop();
|
||||||
CATCH_ENTRY_L0("boosted_tcp_server<t_protocol_handler>::send_stop_signal()", void());
|
CATCH_ENTRY_L0("boosted_tcp_server<t_protocol_handler>::send_stop_signal()", void());
|
||||||
}
|
}
|
||||||
@ -914,6 +925,10 @@ POP_WARNINGS
|
|||||||
TRY_ENTRY();
|
TRY_ENTRY();
|
||||||
|
|
||||||
connection_ptr new_connection_l(new connection<t_protocol_handler>(io_service_, m_config, m_sock_count, m_sock_number, m_pfilter, m_connection_type) );
|
connection_ptr new_connection_l(new connection<t_protocol_handler>(io_service_, m_config, m_sock_count, m_sock_number, m_pfilter, m_connection_type) );
|
||||||
|
connections_mutex.lock();
|
||||||
|
connections_.push_back(new_connection_l);
|
||||||
|
LOG_PRINT_L2("connections_ size now " << connections_.size());
|
||||||
|
connections_mutex.unlock();
|
||||||
boost::asio::ip::tcp::socket& sock_ = new_connection_l->socket();
|
boost::asio::ip::tcp::socket& sock_ = new_connection_l->socket();
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
@ -1006,6 +1021,10 @@ POP_WARNINGS
|
|||||||
{
|
{
|
||||||
TRY_ENTRY();
|
TRY_ENTRY();
|
||||||
connection_ptr new_connection_l(new connection<t_protocol_handler>(io_service_, m_config, m_sock_count, m_sock_number, m_pfilter, m_connection_type) );
|
connection_ptr new_connection_l(new connection<t_protocol_handler>(io_service_, m_config, m_sock_count, m_sock_number, m_pfilter, m_connection_type) );
|
||||||
|
connections_mutex.lock();
|
||||||
|
connections_.push_back(new_connection_l);
|
||||||
|
LOG_PRINT_L2("connections_ size now " << connections_.size());
|
||||||
|
connections_mutex.unlock();
|
||||||
boost::asio::ip::tcp::socket& sock_ = new_connection_l->socket();
|
boost::asio::ip::tcp::socket& sock_ = new_connection_l->socket();
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
Loading…
Reference in New Issue
Block a user