diff --git a/changelog.md b/changelog.md index 834ebeface..c7ef8e8f41 100644 --- a/changelog.md +++ b/changelog.md @@ -1,4 +1,6 @@ HEAD +- Feature: Adds `start_perpetual` and `stop_perpetual` methods to asio transport + These may be used to replace manually managed `asio::io_service::work` objects - Feature: Allow setting pong and handshake timeouts at runtime. - Feature: Allows changing the listen backlog queue length. - Feature: Split tcp init into pre and post init. diff --git a/test/transport/integration.cpp b/test/transport/integration.cpp index 5e163d5bf1..d117617966 100644 --- a/test/transport/integration.cpp +++ b/test/transport/integration.cpp @@ -117,9 +117,10 @@ void run_client(client & c, std::string uri, bool log = false) { c.clear_access_channels(websocketpp::log::alevel::all); c.clear_error_channels(websocketpp::log::elevel::all); } - c.init_asio(); - websocketpp::lib::error_code ec; + c.init_asio(ec); + BOOST_CHECK(!ec); + client::connection_ptr con = c.get_connection(uri,ec); BOOST_CHECK( !ec ); c.connect(con); @@ -127,6 +128,14 @@ void run_client(client & c, std::string uri, bool log = false) { c.run(); } +void run_client_and_mark(client * c, bool * flag, websocketpp::lib::mutex * mutex) { + c->run(); + BOOST_CHECK( true ); + websocketpp::lib::lock_guard lock(*mutex); + *flag = true; + BOOST_CHECK( true ); +} + void run_time_limited_client(client & c, std::string uri, long timeout, bool log) { @@ -430,3 +439,56 @@ BOOST_AUTO_TEST_CASE( server_self_initiated_close_handshake_timeout ) { sthread.join(); } + +BOOST_AUTO_TEST_CASE( client_runs_out_of_work ) { + client c; + + websocketpp::lib::thread tthread(websocketpp::lib::bind(&run_test_timer,3)); + tthread.detach(); + + websocketpp::lib::error_code ec; + c.init_asio(ec); + BOOST_CHECK(!ec); + + c.run(); + + // This test checks that an io_service with no work ends immediately. + BOOST_CHECK(true); +} + + + + +BOOST_AUTO_TEST_CASE( client_is_perpetual ) { + client c; + bool flag = false; + websocketpp::lib::mutex mutex; + + websocketpp::lib::error_code ec; + c.init_asio(ec); + BOOST_CHECK(!ec); + + c.start_perpetual(); + + websocketpp::lib::thread cthread(websocketpp::lib::bind(&run_client_and_mark,&c,&flag,&mutex)); + + sleep(1); + + { + // Checks that the thread hasn't exited yet + websocketpp::lib::lock_guard lock(mutex); + BOOST_CHECK( !flag ); + } + + c.stop_perpetual(); + + sleep(1); + + { + // Checks that the thread has exited + websocketpp::lib::lock_guard lock(mutex); + BOOST_CHECK( flag ); + } + + cthread.join(); +} diff --git a/websocketpp/transport/asio/endpoint.hpp b/websocketpp/transport/asio/endpoint.hpp index cd243889a2..2728c66b3e 100644 --- a/websocketpp/transport/asio/endpoint.hpp +++ b/websocketpp/transport/asio/endpoint.hpp @@ -84,6 +84,8 @@ public: typedef lib::shared_ptr resolver_ptr; /// Type of timer handle typedef lib::shared_ptr timer_ptr; + /// Type of a shared pointer to an io_service work object + typedef lib::shared_ptr work_ptr; // generate and manage our own io_service explicit endpoint() @@ -554,6 +556,34 @@ public: return m_io_service->stopped(); } + /// Marks the endpoint as perpetual, stopping it from exiting when empty + /** + * Marks the endpoint as perpetual. Perpetual endpoints will not + * automatically exit when they run out of connections to process. To stop + * a perpetual endpoint call `end_perpetual`. + * + * An endpoint may be marked perpetual at any time by any thread. It must be + * called either before the endpoint has run out of work or before it was + * started + * + * @since 0.4.0-alpha1 + */ + void start_perpetual() { + m_work.reset(new boost::asio::io_service::work(*m_io_service)); + } + + /// Clears the endpoint's perpetual flag, allowing it to exit when empty + /** + * Clears the endpoint's perpetual flag. This will cause the endpoint's run + * method to exit normally when it runs out of connections. If there are + * currently active connections it will not end until they are complete. + * + * @since 0.4.0-alpha1 + */ + void stop_perpetual() { + m_work.reset(); + } + /// Call back a function after a period of time. /** * Sets a timer that calls back a function after the specified period of @@ -988,6 +1018,7 @@ private: bool m_external_io_service; acceptor_ptr m_acceptor; resolver_ptr m_resolver; + work_ptr m_work; // Network constants int m_listen_backlog;