asio and shared libraries problem (linux only)

io_service and shared libraries problem (linux only) Short question: is it safe to share asio "objects" (io_services, sockets and so on...) across shared libraries/modules? Long story: we are porting our project from Windows to Linux (actually we are working on Ubuntu with GCC 4.2.3) and we discovered a problem when an io_service is shared between modules: creating an io_service, for example, in the main executable and passing that to a shared library causes on Linux problems with handler's invocation. I stress that on Windows we have never reported the problem (with and without IOCP defining BOOST_ASIO_DISABLE_IOCP), instead on Linux it's always reproducible (event disabling the epoll implementation with BOOST_ASIO_DISABLE_EPOLL). The following example can reproduce the problem: "test_working_asio_example" let the shared library to create the io_service and in this case the "handle_timeout" and "handle_connection" are invoked as expected, instead "test_not_working_asio_example" freezes in the io_service::run invocation because the timeout is never invoked. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Shared library code: ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // connection.h //////////////////////////////////////////////////////////////////////////////////////////////////// #include <boost/asio.hpp> #include <boost/enable_shared_from_this.hpp> // NetExport on Windows is defined as _declspec(dllexport)/_declspec(dllimport) and on Linux is defined as __attribute__ ((visibility("default"))) class NetExport connection : public boost::enable_shared_from_this<connection> { public: connection(shared_ptr<boost::asio::io_service> service = shared_ptr<boost::asio::io_service>()); virtual ~connection(); boost::asio::io_service & service(); virtual void handle_connect(const boost::system::error_code &e); virtual void handle_timeout(); void connect(const boost::asio::ip::tcp::endpoint &endpoint, const boost::posix_time::time_duration &timeout); protected: shared_ptr<boost::asio::io_service> m_service; boost::asio::deadline_timer m_timeout; boost::asio::ip::tcp::socket m_socket; }; // connection.cpp //////////////////////////////////////////////////////////////////////////////////////////////////// #include "connection.h" #include <boost/bind.hpp> connection::connection(shared_ptr<boost::asio::io_service> service) : m_service(service ? service : shared_ptr<boost::asio::io_service>(new boost::asio::io_service())), m_timeout(*m_service), m_socket(*m_service) { std::cout << "connection::ctor" << std::endl; } connection::~connection() { std::cout << "connection::dctor" << std::endl; } boost::asio::io_service & connection::service() { return m_socket.io_service(); } void connection::handle_connect(const boost::system::error_code &e) { m_timeout.cancel(); if(e == boost::asio::error::operation_aborted) { std::cout << "connection::handle_connect (aborted)" << std::endl; return; } if(e) std::cout << "connection::handle_connect (error)" << std::endl; else std::cout << "connection::handle_connect (success)" << std::endl; } void connection::handle_timeout() { std::cout << "connection::handle_timeout" << std::endl; m_socket.close(); } void connection::connect(const boost::asio::ip::tcp::endpoint &endpoint, const boost::posix_time::time_duration &timeout) { m_socket.async_connect(endpoint, boost::bind(&connection::handle_connect, shared_from_this(), boost::asio::placeholders::error)); m_timeout.expires_from_now(timeout); m_timeout.async_wait(boost::bind(&connection::handle_timeout, shared_from_this())); } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Main executable code: ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void test_working_asio_example(const boost::asio::ip::tcp::endpoint &endpoint, const boost::posix_time::time_duration &timeout) { try { shared_ptr<connection> c(new connection()); c->connect(endpoint, timeout); c->service().run(); } catch(std::exception &e) { std::cerr << "Exception: " << e.what() << std::endl; } } void test_not_working_asio_example(const boost::asio::ip::tcp::endpoint &endpoint, const boost::posix_time::time_duration &timeout) { try { shared_ptr<connection> c(new connection(shared_ptr<boost::asio::io_service>(new boost::asio::io_service()))); c->connect(endpoint, timeout); c->service().run(); } catch(std::exception &e) { std::cerr << "Exception: " << e.what() << std::endl; } } int main(int argc, char *argv[]) { // 88.149.0.2:32123 is just a dummy endpoint that will "probably" timeout in 1 second ( if not try another fake one :) ) boost::asio::ip::tcp::endpoint endpoint(boost::asio::ip::address_v4::from_string("88.149.0.2"), 32123); boost::posix_time::time_duration timeout = boost::posix_time::seconds(1); test_working_asio_example(endpoint, timeout); test_not_working_asio_example(endpoint, timeout); return 0; } _________________________________________________________________ Stanco della solita finestra? Personalizza la tua Hotmail! http://www.messenger.it/personalizza.html#sfondi
participants (1)
-
Berserker