From c1c800bad5b1e53427db8cdf9060ac0aafab227a Mon Sep 17 00:00:00 2001 From: Adrian DC Date: Sat, 20 Jul 2019 18:31:34 +0200 Subject: [PATCH 1/3] examples: add stability test example with 10000 iterations * Test sequence: - mkdir ./served.build/ - cd ./served.build/ - cmake -DCMAKE_BUILD_TYPE=Debug -DSERVED_BUILD_SHARED=ON -DSERVED_BUILD_STATIC=ON -DSERVED_BUILD_EXAMPLES=ON -DSERVED_BUILD_RPM=ON ../served/ - make -j8 - ../served/bin/eg_stability - gdb -q --batch -ex 'set print thread-events off' -ex 'run' -ex 'bt' ../served/bin/eg_stability --- src/examples/CMakeLists.txt | 1 + src/examples/stability/CMakeLists.txt | 36 ++++++++++++++ src/examples/stability/main.cpp | 70 +++++++++++++++++++++++++++ 3 files changed, 107 insertions(+) create mode 100644 src/examples/stability/CMakeLists.txt create mode 100644 src/examples/stability/main.cpp diff --git a/src/examples/CMakeLists.txt b/src/examples/CMakeLists.txt index 54049ee..581d179 100644 --- a/src/examples/CMakeLists.txt +++ b/src/examples/CMakeLists.txt @@ -28,3 +28,4 @@ ADD_SUBDIRECTORY (query_params) ADD_SUBDIRECTORY (list_endpoints) ADD_SUBDIRECTORY (request_logger_plugin) ADD_SUBDIRECTORY (rest_resource) +ADD_SUBDIRECTORY (stability) diff --git a/src/examples/stability/CMakeLists.txt b/src/examples/stability/CMakeLists.txt new file mode 100644 index 0000000..9d7badd --- /dev/null +++ b/src/examples/stability/CMakeLists.txt @@ -0,0 +1,36 @@ +# Copyright (C) 2014 MediaSift Ltd. +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +# +# Locate project sources +# +FILE (GLOB_RECURSE eg_stability_SRCS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp ${CMAKE_CURRENT_SOURCE_DIR}/*.hpp) + +# +# Configure common project settings +# +SET (eg_stability_LIBS ${PROJECT_NAME} ${Boost_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}) + +# +# Executable build rules +# +ADD_EXECUTABLE (eg_stability ${eg_stability_SRCS}) +TARGET_LINK_LIBRARIES (eg_stability ${eg_stability_LIBS}) +INSTALL (TARGETS eg_stability DESTINATION bin) diff --git a/src/examples/stability/main.cpp b/src/examples/stability/main.cpp new file mode 100644 index 0000000..bb22a84 --- /dev/null +++ b/src/examples/stability/main.cpp @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2014 MediaSift Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include + +/* stability example + * + * This example is a basic stability test of served run in non blocking way. + */ +void test(bool stop) +{ + served::multiplexer mux; + + mux.handle("/hello") + .get([](served::response & res, const served::request &) { + res << "Hello world"; + }); + + std::cout << "Try this example with:" << std::endl; + std::cout << " curl http://localhost:8123/hello" << std::endl; + + served::net::server server("127.0.0.1", "8123", mux, false); + server.run(10, false); // Run with a pool of 10 threads (not blocking) + + std::cout << "Time to stop the server" << std::endl; + if (stop) { + server.stop(); + } +} + +int main(int, char const**) +{ + for (size_t i = 0; i < 10000; ++i) { + std::cout << std::endl; + std::cout << "Performing test " << i << " (with stop()) :" << std::endl; + std::cout << std::endl; + test(true); + } + + for (size_t i = 0; i < 10000; ++i) { + std::cout << std::endl; + std::cout << "Performing test " << i << " (without stop()) :" << std::endl; + std::cout << std::endl; + test(false); + } + + std::cout << "Successfully performed the stability tests" << std::endl; + std::cout << std::endl; + return 0; +} From 504e1588c88900ff8fcb17ece0cf47ac9b64ddc9 Mon Sep 17 00:00:00 2001 From: Adrian DC Date: Sat, 20 Jul 2019 19:01:00 +0200 Subject: [PATCH 2/3] served: minor documentation fix about non-blocking run conditions --- src/served/net/server.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/served/net/server.hpp b/src/served/net/server.hpp index 9110fff..c83d04b 100644 --- a/src/served/net/server.hpp +++ b/src/served/net/server.hpp @@ -77,7 +77,7 @@ class server * and another param which defines the blocking nature. * * @param n_threads the number of threads to pool for request handling - * @param block if n_threads > 0, defines whether this operation is blocking or not + * @param block if n_threads > 1, defines whether this operation is blocking or not */ void run(int n_threads = 1, bool block = true); From 0205da988d51d92d36b503d5e0ac8d79424f5f70 Mon Sep 17 00:00:00 2001 From: Adrian DC Date: Sat, 20 Jul 2019 19:02:41 +0200 Subject: [PATCH 3/3] served: ensure multithreaded servers are properly released * A class destructor is added to properly release the members * The threads are joined upon destruction to ensure work is done * A 1 millisecond delay is added to avoid multithreading races * Threads are create with "bind" references rather than lambdas --- src/served/net/server.cpp | 36 +++++++++++++++++++++++++++++------- src/served/net/server.hpp | 7 +++++++ 2 files changed, 36 insertions(+), 7 deletions(-) diff --git a/src/served/net/server.cpp b/src/served/net/server.cpp index a1ebc62..77b235a 100644 --- a/src/served/net/server.cpp +++ b/src/served/net/server.cpp @@ -22,7 +22,6 @@ #include #include -#include #include @@ -71,6 +70,30 @@ server::server( const std::string & address do_accept(); } +server::~server() +{ + _acceptor.close(); + _connection_manager.stop_all(); + + if ( ! _io_service.stopped() ) + { + _io_service.stop(); + } + + if ( _threads.size() > 0 ) { + for ( auto & thread : _threads ) + { + if ( thread.joinable() ) + { + thread.join(); + } + } + + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + _threads.clear(); + } +} + void server::run(int n_threads /* = 1 */, bool block /* = true */) { @@ -82,14 +105,13 @@ server::run(int n_threads /* = 1 */, bool block /* = true */) */ if ( n_threads > 1 ) { - std::vector v_threads; - for ( int i = 0; i < n_threads; i++ ) + for ( int i = 0; i < 1; i++ ) { - v_threads.push_back(std::thread([this](){ - _io_service.run(); - })); + _threads.push_back(std::thread( + std::bind(static_cast( + &boost::asio::io_service::run), std::ref(_io_service)))); } - for ( auto & thread : v_threads ) + for ( auto & thread : _threads ) { if ( block ) { diff --git a/src/served/net/server.hpp b/src/served/net/server.hpp index c83d04b..4028a8f 100644 --- a/src/served/net/server.hpp +++ b/src/served/net/server.hpp @@ -25,6 +25,7 @@ #include #include +#include #include #include @@ -49,6 +50,7 @@ class server int _read_timeout; int _write_timeout; size_t _req_max_bytes; + std::vector _threads; public: server(const server&) = delete; @@ -70,6 +72,11 @@ class server , multiplexer & mux , bool register_signals = true ); + /* + * Destroys the server. + */ + ~server(); + /* * A call that prompts the server into listening for HTTP requests. *