Berserker
2008-09-23 13:01:44 UTC
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
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