diff --git a/.github/workflows/cmake-superbuild/CMakeLists.txt b/.github/workflows/cmake-superbuild/CMakeLists.txt index 1c36ede..4117ad0 100644 --- a/.github/workflows/cmake-superbuild/CMakeLists.txt +++ b/.github/workflows/cmake-superbuild/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.0) +cmake_minimum_required(VERSION 3.10) project(azmq-super-build) #options @@ -23,12 +23,18 @@ endif () include(ExternalProject) -set(BOOST_177 "https://boostorg.jfrog.io/artifactory/main/release/1.77.0/source/boost_1_77_0.tar.bz2") -set(BOOST_176 "https://boostorg.jfrog.io/artifactory/main/release/1.76.0/source/boost_1_76_0.tar.bz2") -set(BOOST_174 "https://boostorg.jfrog.io/artifactory/main/release/1.74.0/source/boost_1_74_0.tar.bz2") -set(BOOST_172 "https://boostorg.jfrog.io/artifactory/main/release/1.72.0/source/boost_1_72_0.tar.bz2") -set(BOOST_170 "https://boostorg.jfrog.io/artifactory/main/release/1.70.0/source/boost_1_70_0.tar.bz2") -set(BOOST_168 "https://boostorg.jfrog.io/artifactory/main/release/1.68.0/source/boost_1_68_0.tar.bz2") + +set(BOOST_189 "https://archives.boost.io/release/1.89.0/source/boost_1_89_0.tar.bz2") +set(BOOST_187 "https://archives.boost.io/release/1.87.0/source/boost_1_87_0.tar.bz2") +set(BOOST_186 "https://archives.boost.io/release/1.86.0/source/boost_1_86_0.tar.bz2") +set(BOOST_184 "https://archives.boost.io/release/1.84.0/source/boost_1_84_0.tar.bz2") +set(BOOST_181 "https://archives.boost.io/release/1.81.0/source/boost_1_81_0.tar.bz2") +set(BOOST_177 "https://archives.boost.io/release/1.77.0/source/boost_1_77_0.tar.bz2") +set(BOOST_176 "https://archives.boost.io/release/1.76.0/source/boost_1_76_0.tar.bz2") +set(BOOST_174 "https://archives.boost.io/release/1.74.0/source/boost_1_74_0.tar.bz2") +set(BOOST_172 "https://archives.boost.io/release/1.72.0/source/boost_1_72_0.tar.bz2") +set(BOOST_170 "https://archives.boost.io/release/1.70.0/source/boost_1_70_0.tar.bz2") +set(BOOST_168 "https://archives.boost.io/release/1.68.0/source/boost_1_68_0.tar.bz2") set(DEVROOT ${CMAKE_BINARY_DIR}/devroot) @@ -76,13 +82,19 @@ if (NOT (BOOST_URL STREQUAL "system")) INSTALL_DIR ${DEVROOT} CONFIGURE_COMMAND ./bootstrap.sh --prefix= BUILD_COMMAND "" - INSTALL_COMMAND ./b2 install --prefix= -j${CPU_COUNT}) + INSTALL_COMMAND ./b2 install --prefix= -j${CPU_COUNT} --warnings-as-errors=off --without-python --without-math) list(APPEND LIBS boost) endif () +cmake_policy(GET CMP0167 _cmp0167_value) +if(_cmp0167_value) + set(_policy_arg "-DCMAKE_POLICY_DEFAULT_CMP0167=${_cmp0167_value}") + message(STATUS " Setting superbuild CMP0167 to ${_cmp0167_value} ") +endif() + ExternalProject_Add( azmq DEPENDS ${LIBS} - CMAKE_ARGS ${CMAKE_ARGS} -D AZMQ_BUILD_TESTS=YES + CMAKE_ARGS ${CMAKE_ARGS} -D AZMQ_BUILD_TESTS=YES ${_policy_arg} SOURCE_DIR ${CMAKE_SOURCE_DIR}/../../.. TEST_BEFORE_INSTALL YES) diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml index 6436fe0..e40b447 100644 --- a/.github/workflows/cmake.yml +++ b/.github/workflows/cmake.yml @@ -7,48 +7,94 @@ on: pull_request: branches: [master] +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + jobs: build: strategy: fail-fast: false matrix: - config: - - { - name: "ubuntu22", - os: ubuntu-22.04, - boost_url: system, - zmq_tag: system, - system_packages: "libboost-all-dev libzmq3-dev ", - cc: "gcc", - cxx: "g++", - } - - { - name: "ubuntu20 stock", - os: ubuntu-20.04, - boost_url: system, - zmq_tag: system, - system_packages: "libboost-all-dev libzmq3-dev ", - cc: "gcc", - cxx: "g++", - } - - { - name: "macos12 ", - os: macos-12, - boost_url: system, - zmq_tag: system, - system_packages: "zmq boost", - cc: "clang", - cxx: "clang++", - } - - { - name: "macos11 ", - os: macos-11, - boost_url: system, - zmq_tag: system, - system_packages: "zmq boost", - cc: "clang", - cxx: "clang++", - } + config: + - os: ubuntu-24.04 + family: ubuntu + cc: gcc + cxx: g++ + - os: ubuntu-22.04 + family: ubuntu + cc: gcc + cxx: g++ + - os: macos-26 + family: macos + cc: clang + cxx: clang++ + - os: macos-15 + family: macos + cc: clang + cxx: clang++ + - os: macos-14 + family: macos + cc: clang + cxx: clang++ + - os: macos-13 + family: macos + cc: clang + cxx: clang++ + boost: + - url: system + system_packages_ubuntu: libboost-all-dev + system_packages_macos: boost + extra_cmake_args: -DCMAKE_POLICY_DEFAULT_CMP0167=NEW + - url: BOOST_189 + system_packages_ubuntu: + system_packages_macos: + extra_cmake_args: -DCMAKE_POLICY_DEFAULT_CMP0167=NEW + - url: BOOST_187 + system_packages_ubuntu: + system_packages_macos: + extra_cmake_args: -DCMAKE_POLICY_DEFAULT_CMP0167=NEW + - url: BOOST_184 + system_packages_ubuntu: + system_packages_macos: + extra_cmake_args: -DCMAKE_POLICY_DEFAULT_CMP0167=NEW + - url: BOOST_181 + system_packages_ubuntu: + system_packages_macos: + extra_cmake_args: -DCMAKE_POLICY_DEFAULT_CMP0167=NEW + - url: BOOST_176 + system_packages_ubuntu: + system_packages_macos: + extra_cmake_args: -DCMAKE_POLICY_DEFAULT_CMP0167=NEW + - url: BOOST_174 + system_packages_ubuntu: + system_packages_macos: + extra_cmake_args: -DCMAKE_POLICY_DEFAULT_CMP0167=NEW + - url: BOOST_168 + system_packages_ubuntu: + system_packages_macos: + extra_cmake_args: -DCMAKE_POLICY_DEFAULT_CMP0167=OLD + zmq: + - tag: system + system_packages_ubuntu: libzmq3-dev + system_packages_macos: zmq + exclude: + - config: + family: macos + boost: + url: BOOST_176 + - config: + family: macos + boost: + url: BOOST_174 + - config: + family: macos + boost: + url: BOOST_168 + - config: + os: macos-14 + boost: + url: BOOST_181 runs-on: ${{ matrix.config.os }} @@ -56,26 +102,31 @@ jobs: CC: ${{ matrix.config.cc }} CXX: ${{ matrix.config.cxx }} CTEST_OUTPUT_ON_FAILURE: 1 - PACKAGES: ${{ matrix.config.system_packages }} + PACKAGES_UBUNTU: ${{ matrix.boost.system_packages_ubuntu }} ${{ matrix.zmq.system_packages_ubuntu }} + PACKAGES_MACOS: ${{ matrix.boost.system_packages_macos }} ${{ matrix.zmq.system_packages_macos }} + CONFIG_OS: ${{ matrix.config.os }} + MATRIX: ${{ toJson(matrix) }} steps: - uses: actions/checkout@v3 - name: buildtools on ubuntu - if: startsWith(matrix.config.name, 'ubuntu') + if: ${{ startsWith(matrix.config.os, 'ubuntu') }} shell: bash run: | - if [ -n "$PACKAGES" ]; then - sudo apt-get install -y $PACKAGES + PACKAGES_UBUNTU=$(echo $PACKAGES_UBUNTU | sed 's/^[ ]*//;s/[ ]*$//') + if [ -n "$PACKAGES_UBUNTU" ]; then + sudo apt-get update && sudo apt-get install -y $PACKAGES_UBUNTU fi - name: buildtools on macos - if: startsWith(matrix.config.name, 'macos') && matrix.config.*.system_packages + if: ${{ startsWith(matrix.config.os, 'macos') }} shell: bash run: | - if [ -n "$PACKAGES" ]; then - brew install $PACKAGES + PACKAGES_MACOS=$(echo $PACKAGES_MACOS | sed 's/^[ ]*//;s/[ ]*$//') + if [ -n "$PACKAGES_MACOS" ]; then + brew install $PACKAGES_MACOS fi - name: build shell: bash run: | - cmake -DBOOST_URL=${{matrix.config.boost_url}} -DZMQ_TAG=${{matrix.config.zmq_tag}} -S .github/workflows/cmake-superbuild -B build + cmake -DBOOST_URL=${{matrix.boost.url}} -DZMQ_TAG=${{matrix.zmq.tag}} ${{matrix.boost.extra_cmake_args}} -S .github/workflows/cmake-superbuild -B build cmake --build build diff --git a/.gitignore b/.gitignore index 7ef38a4..6c35d49 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,9 @@ *.a *.pyc build/* +build_*/* + +# Other files +.devcontainer +.vscode +.DS_Store diff --git a/AUTHORS b/AUTHORS index e071bd5..e7a65ce 100644 --- a/AUTHORS +++ b/AUTHORS @@ -6,3 +6,4 @@ Thomas W Rodgers Andrey Upadyshev Tim Blechmann Adam Boseley +Juan Pablo Pino diff --git a/AzmqCPack.cmake b/AzmqCPack.cmake index 4467dd5..ff75833 100644 --- a/AzmqCPack.cmake +++ b/AzmqCPack.cmake @@ -8,8 +8,8 @@ in general, and Asio in particular. The main abstraction exposed by the library is azmq::socket which provides an Asio style socket interface to the underlying zeromq socket -and interfaces with Asio's io_service(). The socket implementation -participates in the io_service's reactor for asynchronous IO and +and interfaces with Asio's io_context(). The socket implementation +participates in the io_context's reactor for asynchronous IO and may be freely mixed with other Asio socket types (raw TCP/UDP/Serial/etc.).") set(CPACK_PACKAGE_VERSION "1.1.0") diff --git a/CMakeLists.txt b/CMakeLists.txt index 4a9d611..a61e918 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ -cmake_minimum_required(VERSION 3.16.3...3.25) -# -- v3.16.3 is the default version in the current ubuntu lts release +cmake_minimum_required(VERSION 3.22.1...3.29.2) +# -- v3.22.1 is the default version in the current ubuntu lts release project(azmq VERSION 1.1.0 LANGUAGES CXX) @@ -21,13 +21,18 @@ set(CMAKE_CXX_EXTENSIONS OFF) # --- dependencies -- find_package( Boost 1.68 - COMPONENTS system - date_time + COMPONENTS date_time thread chrono random REQUIRED) +# Try to find Boost::system +find_package(Boost COMPONENTS system) +if (NOT Boost_SYSTEM_FOUND) + message(WARNING "Boost::system not found, some examples may not compile") +endif() + include(FindAzmqLibzmq.cmake) set(CMAKE_THREAD_PREFER_PTHREAD TRUE) @@ -37,7 +42,7 @@ find_package(Threads REQUIRED) add_library(${PROJECT_NAME} INTERFACE) add_library(Azmq::${PROJECT_NAME} ALIAS ${PROJECT_NAME}) -target_link_libraries(${PROJECT_NAME} INTERFACE Azmq::libzmq Boost::boost ${CMAKE_THREAD_LIBS_INIT}) +target_link_libraries(${PROJECT_NAME} INTERFACE Azmq::libzmq Boost::boost ${Boost_SYSTEM_LIBRARY} ${CMAKE_THREAD_LIBS_INIT}) target_include_directories(${PROJECT_NAME} INTERFACE "$" "$") diff --git a/README.md b/README.md index c01642b..58cce33 100644 --- a/README.md +++ b/README.md @@ -9,8 +9,8 @@ in general, and Asio in particular. The main abstraction exposed by the library is azmq::socket which provides an Asio style socket interface to the underlying zeromq socket -and interfaces with Asio's io_service(). The socket implementation -participates in the io_service's reactor for asynchronous IO and +and interfaces with Asio's io_context(). The socket implementation +participates in the io_context's reactor for asynchronous IO and may be freely mixed with other Asio socket types (raw TCP/UDP/Serial/etc.). ## Building and installation @@ -29,7 +29,7 @@ which supports C++11. Currently this has been tested with - * Microsoft Visual Studio 2013 on Windows Server 2008 R2 Library dependencies are - -* Boost 1.48 or later +* Boost 1.68 or later * ZeroMQ 4.0.x Tests and example code require - @@ -82,13 +82,13 @@ http://zeromq.org/intro:read-the-manual namespace asio = boost::asio; int main(int argc, char** argv) { - asio::io_service ios; - azmq::sub_socket subscriber(ios); + asio::io_context ioc; + azmq::sub_socket subscriber(ioc); subscriber.connect("tcp://192.168.55.112:5556"); subscriber.connect("tcp://192.168.55.201:7721"); subscriber.set_option(azmq::socket::subscribe("NASDAQ")); - azmq::pub_socket publisher(ios); + azmq::pub_socket publisher(ioc); publisher.bind("ipc://nasdaq-feed"); std::array buf; diff --git a/azmq/actor.hpp b/azmq/actor.hpp index 4b2dceb..7482561 100644 --- a/azmq/actor.hpp +++ b/azmq/actor.hpp @@ -12,7 +12,7 @@ #include "socket.hpp" #include "detail/actor_service.hpp" -#include +#include #include @@ -25,7 +25,7 @@ AZMQ_V1_INLINE_NAMESPACE_BEGIN using last_error = detail::actor_service::last_error; /** \brief create an actor bound to one end of a pipe (pair of inproc sockets) - * \param peer io_service to associate the peer (caller) end of the pipe + * \param peer io_context to associate the peer (caller) end of the pipe * \param f Function accepting socket& as the first parameter and a * number of additional args * \returns peer socket @@ -35,15 +35,15 @@ AZMQ_V1_INLINE_NAMESPACE_BEGIN * will be attached to the lifetime of the returned socket and will run * until it is destroyed. * - * \remark Each actor has an associated io_service and the supplied socket - * will be created on this io_service. The actor may access this by calling - * get_io_service() on the supplied socket. + * \remark Each actor has an associated io_context and the supplied socket + * will be created on this io_context. The actor may access this by calling + * get_io_context() on the supplied socket. * - * \remark The associated io_service is configured to stop the spawned actor + * \remark The associated io_context is configured to stop the spawned actor * on SIG_KILL and SIG_TERM. * * \remark Termination: - * well behaved actors should ultimately call run() on the io_service + * well behaved actors should ultimately call run() on the io_context * associated with the supplied socket. This allows the 'client' end of * the socket's lifetime to cleanly signal termination. If for some * reason, this is not possible, the caller should set the 'detached' @@ -54,12 +54,12 @@ AZMQ_V1_INLINE_NAMESPACE_BEGIN * message. * * Also note, the default signal handling for the background thread is - * designed to call stop() on the associated io_service, so not calling + * designed to call stop() on the associated io_context, so not calling * run() in your handler means you are responsible for catching these * signals in some other way. */ template - socket spawn(boost::asio::io_service & peer, bool defer_start, Function && f, Args&&... args) { + socket spawn(boost::asio::io_context & peer, bool defer_start, Function && f, Args&&... args) { auto& t = boost::asio::use_service(peer); return t.make_pipe(defer_start, std::bind(std::forward(f), std::placeholders::_1, @@ -67,7 +67,7 @@ AZMQ_V1_INLINE_NAMESPACE_BEGIN } template - socket spawn(boost::asio::io_service & peer, Function && f, Args&&... args) { + socket spawn(boost::asio::io_context & peer, Function && f, Args&&... args) { auto& t = boost::asio::use_service(peer); return t.make_pipe(false, std::bind(std::forward(f), std::placeholders::_1, @@ -78,4 +78,3 @@ AZMQ_V1_INLINE_NAMESPACE_END } // namespace actor } // namespace azmq #endif // AZMQ_ACTOR_HPP_ - diff --git a/azmq/context.hpp b/azmq/context.hpp index 85698ca..171c7e8 100644 --- a/azmq/context.hpp +++ b/azmq/context.hpp @@ -12,8 +12,7 @@ #include "detail/socket_service.hpp" #include "option.hpp" #include "error.hpp" - -#include +#include #include namespace azmq { @@ -28,10 +27,10 @@ AZMQ_V1_INLINE_NAMESPACE_BEGIN * \remark Must be called before any sockets are created */ template - boost::system::error_code set_option(boost::asio::io_service & io_service, + boost::system::error_code set_option(boost::asio::io_context & io_context, const Option & option, boost::system::error_code & ec) { - return boost::asio::use_service(io_service).set_option(option, ec); + return boost::asio::use_service(io_context).set_option(option, ec); } /** \brief set options on the zeromq context. @@ -40,9 +39,9 @@ AZMQ_V1_INLINE_NAMESPACE_BEGIN * \remark Must be called before any sockets are created */ template - void set_option(boost::asio::io_service & io_service, const Option & option) { + void set_option(boost::asio::io_context & io_context, const Option & option) { boost::system::error_code ec; - if (set_option(io_service, option, ec)) + if (set_option(io_context, option, ec)) throw boost::system::system_error(ec); } @@ -52,10 +51,10 @@ AZMQ_V1_INLINE_NAMESPACE_BEGIN * \param ec boost::system::error_code */ template - boost::system::error_code get_option(boost::asio::io_service & io_service, + boost::system::error_code get_option(boost::asio::io_context & io_context, Option & option, boost::system::error_code & ec) { - return boost::asio::use_service(io_service).get_option(option, ec); + return boost::asio::use_service(io_context).get_option(option, ec); } /** \brief get option from zeromq context @@ -64,9 +63,9 @@ AZMQ_V1_INLINE_NAMESPACE_BEGIN * \param ec boost::system::error_code */ template - void get_option(boost::asio::io_service & io_service, Option & option) { + void get_option(boost::asio::io_context & io_context, Option & option) { boost::system::error_code ec; - if (get_option(io_service, option)) + if (get_option(io_context, option)) throw boost::system::system_error(ec); } AZMQ_V1_INLINE_NAMESPACE_END diff --git a/azmq/detail/actor_service.hpp b/azmq/detail/actor_service.hpp index 79aa8e2..a153e55 100644 --- a/azmq/detail/actor_service.hpp +++ b/azmq/detail/actor_service.hpp @@ -24,9 +24,6 @@ #include #include -#if BOOST_VERSION < 107000 -# define AZMQ_DETAIL_USE_IO_SERVICE 1 -#endif #include #include @@ -42,15 +39,12 @@ namespace detail { public: inline static std::string get_uri(const char* pfx); -#ifdef AZMQ_DETAIL_USE_IO_SERVICE - actor_service(boost::asio::io_service & ios) -#else - actor_service(boost::asio::io_context & ios) -#endif - : azmq::detail::service_base(ios) + actor_service(boost::asio::io_context & ioc) + + : azmq::detail::service_base(ioc) { } - void shutdown_service() override { } + void shutdown() override { } using is_alive = opt::boolean(opt::limits::lib_actor_min)>; using detached = opt::boolean(opt::limits::lib_actor_min) + 1>; @@ -59,21 +53,13 @@ namespace detail { template socket make_pipe(bool defer_start, T&& data) { -#ifdef AZMQ_DETAIL_USE_IO_SERVICE - return make_pipe(get_io_service(), defer_start, std::forward(data)); -#else return make_pipe(get_io_context(), defer_start, std::forward(data)); -#endif } template -#ifdef AZMQ_DETAIL_USE_IO_SERVICE - static socket make_pipe(boost::asio::io_service & ios, bool defer_start, T&& data) { -#else - static socket make_pipe(boost::asio::io_context & ios, bool defer_start, T&& data) { -#endif + static socket make_pipe(boost::asio::io_context & ioc, bool defer_start, T&& data) { auto p = std::make_shared>(std::forward(data)); - auto res = p->peer_socket(ios); + auto res = p->peer_socket(ioc); associate_ext(res, handler(std::move(p), defer_start)); return std::move(res); } @@ -82,7 +68,7 @@ namespace detail { struct concept_ { using ptr = std::shared_ptr; - boost::asio::io_service io_service_; + boost::asio::io_context io_context_; boost::asio::signal_set signals_; pair_socket socket_; thread_t thread_; @@ -95,8 +81,8 @@ namespace detail { std::exception_ptr last_error_; concept_() - : signals_(io_service_, SIGINT, SIGTERM) - , socket_(io_service_) + : signals_(io_context_, SIGINT, SIGTERM) + , socket_(io_context_) , ready_(false) , stopped_(true) { @@ -105,11 +91,7 @@ namespace detail { virtual ~concept_() = default; -#ifdef AZMQ_DETAIL_USE_IO_SERVICE - pair_socket peer_socket(boost::asio::io_service & peer) { -#else pair_socket peer_socket(boost::asio::io_context & peer) { -#endif pair_socket res(peer); auto uri = socket_.endpoint(); BOOST_ASSERT_MSG(!uri.empty(), "uri empty"); @@ -121,7 +103,7 @@ namespace detail { void stop() { if (!joinable()) return; - io_service_.stop(); + io_context_.stop(); thread_.join(); } @@ -165,7 +147,7 @@ namespace detail { static void run(ptr p) { lock_type l { p->mutex_ }; p->signals_.async_wait([p](boost::system::error_code const&, int) { - p->io_service_.stop(); + p->io_context_.stop(); }); p->stopped_ = false; p->thread_ = thread_t([p] { @@ -200,7 +182,7 @@ namespace detail { , defer_start_(defer_start) { } - void on_install(boost::asio::io_service&, void*) { + void on_install(boost::asio::io_context&, void*) { if (defer_start_) return; defer_start_ = false; concept_::run(p_); @@ -286,4 +268,3 @@ namespace detail { } // namespace detail } // namespace azmq #endif // AZMQ_DETAIL_ACTOR_SERVICE_HPP_ - diff --git a/azmq/detail/basic_io_object.hpp b/azmq/detail/basic_io_object.hpp index 980d1b4..cf4f910 100644 --- a/azmq/detail/basic_io_object.hpp +++ b/azmq/detail/basic_io_object.hpp @@ -9,7 +9,7 @@ #ifndef AZMQ_DETAIL_BASIC_IO_OBJECT_HPP__ #define AZMQ_DETAIL_BASIC_IO_OBJECT_HPP__ -#include +#include #include namespace azmq { @@ -41,11 +41,10 @@ namespace detail { friend class core_access; public: - basic_io_object(boost::asio::io_service& ios) - : boost::asio::basic_io_object(ios) + basic_io_object(boost::asio::io_context& ioc) + : boost::asio::basic_io_object(ioc) { } }; } // namespace detail } // namespace azmq #endif // AZMQ_DETAIL_BASIC_IO_OBJECT_HPP__ - diff --git a/azmq/detail/reactor_op.hpp b/azmq/detail/reactor_op.hpp index 1e5f632..86f1eb4 100644 --- a/azmq/detail/reactor_op.hpp +++ b/azmq/detail/reactor_op.hpp @@ -12,8 +12,8 @@ #include "../message.hpp" #include "socket_ops.hpp" +#include #include -#include namespace azmq { namespace detail { @@ -41,4 +41,3 @@ class reactor_op { } // namespace detail } // namespace azmq #endif // AZMQ_DETAIL_REACTOR_OP_HPP_ - diff --git a/azmq/detail/receive_op.hpp b/azmq/detail/receive_op.hpp index 7bd1182..8c48543 100644 --- a/azmq/detail/receive_op.hpp +++ b/azmq/detail/receive_op.hpp @@ -15,9 +15,9 @@ #include "reactor_op.hpp" #include -#include #include #include +#include #if BOOST_VERSION >= 107900 #include #include @@ -197,5 +197,3 @@ class receive_op : public receive_op_base { } // namespace detail } // namespace azmq #endif // AZMQ_DETAIL_RECEIVE_OP_HPP_ - - diff --git a/azmq/detail/send_op.hpp b/azmq/detail/send_op.hpp index 67f868c..97f61c0 100644 --- a/azmq/detail/send_op.hpp +++ b/azmq/detail/send_op.hpp @@ -14,9 +14,9 @@ #include "reactor_op.hpp" #include -#include #include #include +#include #if BOOST_VERSION >= 107900 #include #include @@ -143,5 +143,3 @@ class send_op : public send_op_base { } // namespace detail } // namespace azmq #endif // AZMQ_DETAIL_SEND_OP_HPP_ - - diff --git a/azmq/detail/service_base.hpp b/azmq/detail/service_base.hpp index 0d65e7f..af24564 100644 --- a/azmq/detail/service_base.hpp +++ b/azmq/detail/service_base.hpp @@ -9,24 +9,24 @@ #ifndef AZMQ_DETAIL_SERVICE_BASE_HPP_ #define AZMQ_DETAIL_SERVICE_BASE_HPP_ -#include +#include namespace azmq { namespace detail { template class service_id - : public boost::asio::io_service::id + : public boost::asio::io_context::id { }; template class service_base - : public boost::asio::io_service::service { + : public boost::asio::io_context::service { public : static azmq::detail::service_id id; // Constructor. - service_base(boost::asio::io_service& io_service) - : boost::asio::io_service::service(io_service) + service_base(boost::asio::io_context& io_context) + : boost::asio::io_context::service(io_context) { } }; @@ -35,4 +35,3 @@ namespace detail { } // namespace detail } // namespace azmq #endif // AZMQ_DETAIL_SERVICE_BASE_HPP_ - diff --git a/azmq/detail/socket_ext.hpp b/azmq/detail/socket_ext.hpp index 78a08ed..429adb4 100644 --- a/azmq/detail/socket_ext.hpp +++ b/azmq/detail/socket_ext.hpp @@ -10,8 +10,8 @@ #define AZMQ_DETAIL_SOCKET_EXT_HPP__ #include "../error.hpp" +#include #include -#include #include #include @@ -35,9 +35,9 @@ namespace detail { return *this; } - void on_install(boost::asio::io_service& ios, void * socket) const { + void on_install(boost::asio::io_context& ioc, void * socket) const { BOOST_ASSERT_MSG(ptr_, "reusing moved instance of socket_ext"); - ptr_->on_install(ios, socket); + ptr_->on_install(ioc, socket); } void on_remove() { @@ -83,7 +83,7 @@ namespace detail { struct concept_ { virtual ~concept_() = default; - virtual void on_install(boost::asio::io_service &, void *) = 0; + virtual void on_install(boost::asio::io_context &, void *) = 0; virtual void on_remove() = 0; virtual boost::system::error_code set_option(opt_concept const&, boost::system::error_code &) = 0; virtual boost::system::error_code get_option(opt_concept &, boost::system::error_code &) = 0; @@ -96,7 +96,7 @@ namespace detail { model(T data): data_(std::move(data)) { } - void on_install(boost::asio::io_service & ios, void * socket) override { data_.on_install(ios, socket); } + void on_install(boost::asio::io_context & ioc, void * socket) override { data_.on_install(ioc, socket); } void on_remove() override { data_.on_remove(); } boost::system::error_code set_option(opt_concept const& opt, boost::system::error_code & ec) override { return data_.set_option(opt, ec); @@ -110,4 +110,3 @@ namespace detail { } // namespace detail } // namespace azmq #endif // AZMQ_DETAIL_SOCKET_EXT_HPP__ - diff --git a/azmq/detail/socket_ops.hpp b/azmq/detail/socket_ops.hpp index eea8e2c..ca11de0 100644 --- a/azmq/detail/socket_ops.hpp +++ b/azmq/detail/socket_ops.hpp @@ -15,7 +15,7 @@ #include #include -#include +#include #include #if ! defined BOOST_ASIO_WINDOWS #include @@ -88,7 +88,7 @@ namespace detail { return socket_type(res); } - static stream_descriptor get_stream_descriptor(boost::asio::io_service & io_service, + static stream_descriptor get_stream_descriptor(boost::asio::io_context & io_context, socket_type & socket, boost::system::error_code & ec) { BOOST_ASSERT_MSG(socket, "invalid socket"); @@ -100,13 +100,13 @@ namespace detail { ec = make_error_code(); else { #if ! defined BOOST_ASIO_WINDOWS - res.reset(new boost::asio::posix::stream_descriptor(io_service, handle)); + res.reset(new boost::asio::posix::stream_descriptor(io_context, handle)); #else // Use duplicated SOCKET, because ASIO socket takes ownership over it so destroys one in dtor. ::WSAPROTOCOL_INFO pi; ::WSADuplicateSocket(handle, ::GetCurrentProcessId(), &pi); handle = ::WSASocket(pi.iAddressFamily/*AF_INET*/, pi.iSocketType/*SOCK_STREAM*/, pi.iProtocol/*IPPROTO_TCP*/, &pi, 0, 0); - res.reset(new boost::asio::ip::tcp::socket(io_service, boost::asio::ip::tcp::v4(), handle)); + res.reset(new boost::asio::ip::tcp::socket(io_context, boost::asio::ip::tcp::v4(), handle)); #endif } return res; @@ -269,12 +269,12 @@ namespace detail { socket_type & socket, flags_type flags, boost::system::error_code & ec) -> - typename boost::enable_if, size_t>::type + typename boost::enable_if, size_t>::type { size_t res = 0; - auto last = std::distance(std::begin(buffers), std::end(buffers)) - 1; + auto last = std::distance(boost::asio::buffer_sequence_begin(buffers), boost::asio::buffer_sequence_end(buffers)) - 1; decltype(last) index = 0u; - for (auto it = std::begin(buffers); it != std::end(buffers); ++it, ++index) { + for (auto it = boost::asio::buffer_sequence_begin(buffers); it != boost::asio::buffer_sequence_end(buffers); ++it, ++index) { auto f = index == last ? flags : flags | ZMQ_SNDMORE; res += send(message(*it), socket, f, ec); @@ -301,11 +301,11 @@ namespace detail { socket_type & socket, flags_type flags, boost::system::error_code & ec) -> - typename boost::enable_if, size_t>::type + typename boost::enable_if, size_t>::type { size_t res = 0; message msg; - auto it = std::begin(buffers); + auto it = boost::asio::buffer_sequence_begin(buffers); do { auto sz = receive(msg, socket, flags, ec); if (ec) @@ -318,7 +318,7 @@ namespace detail { res += sz; flags |= ZMQ_RCVMORE; - } while ((it != std::end(buffers)) && msg.more()); + } while ((it != boost::asio::buffer_sequence_end(buffers)) && msg.more()); if (msg.more()) ec = make_error_code(boost::system::errc::no_buffer_space); @@ -373,4 +373,3 @@ namespace detail { } // namespace detail } // namespace azmq #endif // AZMQ_DETAIL_SOCKET_OPS_HPP__ - diff --git a/azmq/detail/socket_service.hpp b/azmq/detail/socket_service.hpp index 8250ee0..17c2ed8 100644 --- a/azmq/detail/socket_service.hpp +++ b/azmq/detail/socket_service.hpp @@ -25,18 +25,14 @@ #include "receive_op.hpp" #include +#include +#include #include #include #include #include #include -#if BOOST_VERSION < 107000 -# define AZMQ_DETAIL_USE_IO_SERVICE 1 -#else -# include -#endif - #include #include #include @@ -89,11 +85,7 @@ namespace detail { bool serverish_ = false; std::array op_queues_; -#ifdef AZMQ_DETAIL_USE_IO_SERVICE - void do_open(boost::asio::io_service & ios, -#else - void do_open(boost::asio::io_context & ios, -#endif + void do_open(boost::asio::io_context & ioc, context_type & ctx, int type, bool optimize_single_threaded, @@ -102,7 +94,7 @@ namespace detail { socket_ = socket_ops::create_socket(ctx, type, ec); if (ec) return; - sd_ = socket_ops::get_stream_descriptor(ios, socket_, ec); + sd_ = socket_ops::get_stream_descriptor(ioc, socket_, ec); if (ec) return; optimize_single_threaded_ = optimize_single_threaded; @@ -193,16 +185,12 @@ namespace detail { using core_access = azmq::detail::core_access; -#ifdef AZMQ_DETAIL_USE_IO_SERVICE - explicit socket_service(boost::asio::io_service & ios) -#else - explicit socket_service(boost::asio::io_service & ios) -#endif - : azmq::detail::service_base(ios) + explicit socket_service(boost::asio::io_context & ioc) + : azmq::detail::service_base(ioc) , ctx_(context_ops::get_context()) { } - void shutdown_service() override { + void shutdown() override { ctx_.reset(); } @@ -229,11 +217,7 @@ namespace detail { bool optimize_single_threaded, boost::system::error_code & ec) { BOOST_ASSERT_MSG(impl, "impl"); -#ifdef AZMQ_DETAIL_USE_IO_SERVICE - impl->do_open(get_io_service(), ctx_, type, optimize_single_threaded, ec); -#else impl->do_open(get_io_context(), ctx_, type, optimize_single_threaded, ec); -#endif if (ec) impl.reset(); return ec; @@ -258,11 +242,7 @@ namespace detail { std::tie(it, res) = impl->exts_.emplace(std::type_index(typeid(Extension)), socket_ext(std::forward(ext))); if (res) -#ifdef AZMQ_DETAIL_USE_IO_SERVICE - it->second.on_install(get_io_service(), impl->socket_.get()); -#else it->second.on_install(get_io_context(), impl->socket_.get()); -#endif return res; } @@ -556,11 +536,7 @@ namespace detail { { impl->missed_events_found_ = true; weak_descriptor_ptr weak_impl(impl); -#ifdef AZMQ_DETAIL_USE_IO_SERVICE - impl->sd_->get_io_service().post([weak_impl, ec]() { handle_missed_events(weak_impl, ec); }); -#else - boost::asio::post(impl->sd_->get_executor(), [weak_impl, ec]() { handle_missed_events(weak_impl, ec); }); -#endif + boost::asio::post(impl->sd_->get_executor(), [weak_impl, ec]() { handle_missed_events(weak_impl, ec); }); } } @@ -634,11 +610,7 @@ namespace detail { auto evs = socket_ops::get_events(impl->socket_, ec) & impl->events_mask(); if (evs || ec) { -#ifdef AZMQ_DETAIL_USE_IO_SERVICE - impl->sd_->get_io_service().post([handler, ec] { handler(ec, 0); }); -#else - boost::asio::post(impl->sd_->get_executor(), [handler, ec] { handler(ec, 0); }); -#endif + boost::asio::post(impl->sd_->get_executor(), [handler, ec] { handler(ec, 0); }); } else { impl->sd_->async_read_some(boost::asio::null_buffers(), std::move(handler)); @@ -688,12 +660,7 @@ namespace detail { if (op->do_perform(impl->socket_)) { impl->in_speculative_completion_ = true; l.unlock(); -#ifdef AZMQ_DETAIL_USE_IO_SERVICE - get_io_service() -#else - get_io_context() -#endif - .post(deferred_completion(impl, std::move(op))); + boost::asio::post(get_io_context(), deferred_completion(impl, std::move(op))); return; } } @@ -725,4 +692,3 @@ namespace detail { } // namespace detail } // namespace azmq #endif // AZMQ_DETAIL_SOCKET_SERVICE_HPP__ - diff --git a/azmq/error.hpp b/azmq/error.hpp index 0f0a5a5..7aeb9f4 100644 --- a/azmq/error.hpp +++ b/azmq/error.hpp @@ -15,18 +15,6 @@ #include #include - -#if BOOST_VERSION < 105400 - #ifndef BOOST_NOEXCEPT - #ifdef BOOST_NO_CXX11_NOEXCEPT - #define BOOST_NOEXCEPT - #else - #define BOOST_NOEXCEPT noexcept - #endif - #endif - #define BOOST_SYSTEM_NOEXCEPT BOOST_NOEXCEPT -#endif - namespace azmq { AZMQ_V1_INLINE_NAMESPACE_BEGIN /** \brief custom error_category to map zeromq errors */ diff --git a/azmq/message.hpp b/azmq/message.hpp index 48d3efa..d13da26 100644 --- a/azmq/message.hpp +++ b/azmq/message.hpp @@ -14,9 +14,7 @@ #include #include -#if BOOST_VERSION >= 105300 - #include -#endif +#include #include #include #include @@ -76,7 +74,7 @@ AZMQ_V1_INLINE_NAMESPACE_BEGIN message(nocopy_t, boost::asio::const_buffer const& buffer) : message(nocopy, boost::asio::mutable_buffer( - (void *)boost::asio::buffer_cast(buffer), + const_cast(buffer.data()), boost::asio::buffer_size(buffer)), nullptr, nullptr) @@ -85,7 +83,7 @@ AZMQ_V1_INLINE_NAMESPACE_BEGIN message(nocopy_t, boost::asio::mutable_buffer const& buffer, void* hint, zmq_free_fn* deleter) { auto rc = zmq_msg_init_data(&msg_, - boost::asio::buffer_cast(buffer), + buffer.data(), boost::asio::buffer_size(buffer), deleter, hint); if (rc) @@ -107,7 +105,7 @@ AZMQ_V1_INLINE_NAMESPACE_BEGIN std::unique_ptr d(new D(std::forward(deleter))); auto rc = zmq_msg_init_data(&msg_, - boost::asio::buffer_cast(buffer), + buffer.data(), boost::asio::buffer_size(buffer), call_deleter, d.get()); if (rc) @@ -125,18 +123,16 @@ AZMQ_V1_INLINE_NAMESPACE_BEGIN }; auto rc = zmq_msg_init_data(&msg_, - boost::asio::buffer_cast(buffer), + buffer.data(), boost::asio::buffer_size(buffer), call_deleter, reinterpret_cast(deleter)); if (rc) throw boost::system::system_error(make_error_code()); } -#if BOOST_VERSION >= 105300 explicit message(boost::string_ref str) : message(boost::asio::buffer(str.data(), str.size())) { } -#endif message(message && rhs) BOOST_NOEXCEPT : msg_(rhs.msg_) @@ -193,7 +189,7 @@ AZMQ_V1_INLINE_NAMESPACE_BEGIN template T const& buffer_cast() const { - return *boost::asio::buffer_cast(buffer()); + return *static_cast(buffer().data()); } size_t buffer_copy(boost::asio::mutable_buffer const& target) const { diff --git a/azmq/socket.hpp b/azmq/socket.hpp index 76c3733..7d2d342 100644 --- a/azmq/socket.hpp +++ b/azmq/socket.hpp @@ -17,15 +17,12 @@ #include "detail/send_op.hpp" #include "detail/receive_op.hpp" +#include #include -#include +#include #include #include -#if BOOST_VERSION >= 106600 -#include -#endif - #include #include @@ -94,31 +91,31 @@ class socket : using conflate = opt::boolean; /** \brief socket constructor - * \param ios reference to an asio::io_service + * \param ioc reference to an asio::io_context * \param s_type int socket type * For socket types see the zeromq documentation * \param optimize_single_threaded bool * Defaults to false - socket is not optimized for a single - * threaded io_service + * threaded io_context * \remarks * ZeroMQ's socket types are not thread safe. Because there is no - * guarantee that the supplied io_service is running in a single + * guarantee that the supplied io_context is running in a single * thread, Aziomq by default wraps all calls to ZeroMQ APIs with * a mutex. If you can guarantee that a single thread has called - * io_service.run() you may bypass the mutex by passing true for + * io_context.run() you may bypass the mutex by passing true for * optimize_single_threaded. */ - explicit socket(boost::asio::io_service& ios, + explicit socket(boost::asio::io_context& ioc, int type, bool optimize_single_threaded = false) - : azmq::detail::basic_io_object(ios) { + : azmq::detail::basic_io_object(ioc) { boost::system::error_code ec; if (get_service().do_open(get_implementation(), type, optimize_single_threaded, ec)) throw boost::system::system_error(ec); } socket(socket&& other) - : azmq::detail::basic_io_object(other.get_io_service()) { + : azmq::detail::basic_io_object(other.get_io_context()) { get_service().move_construct(get_implementation(), other.get_service(), other.get_implementation()); @@ -651,16 +648,16 @@ class socket : } /** \brief monitor events on a socket - * \param ios io_service on which to bind the returned monitor socket + * \param ioc io_context on which to bind the returned monitor socket * \param events int mask of events to publish to returned socket * \param ec error_code to set on error * \returns socket **/ - socket monitor(boost::asio::io_service & ios, + socket monitor(boost::asio::io_context & ioc, int events, boost::system::error_code & ec) { auto uri = get_service().monitor(get_implementation(), events, ec); - socket res(ios, ZMQ_PAIR); + socket res(ioc, ZMQ_PAIR); if (ec) return res; @@ -670,14 +667,14 @@ class socket : } /** \brief monitor events on a socket - * \param ios io_service on which to bind the returned monitor socket + * \param ioc io_context on which to bind the returned monitor socket * \param events int mask of events to publish to returned socket * \returns socket **/ - socket monitor(boost::asio::io_service & ios, + socket monitor(boost::asio::io_context & ioc, int events) { boost::system::error_code ec; - auto res = monitor(ios, events, ec); + auto res = monitor(ioc, events, ec); if (ec) throw boost::system::system_error(ec); return res; @@ -777,9 +774,9 @@ namespace detail { typedef socket Base; public: - specialized_socket(boost::asio::io_service & ios, + specialized_socket(boost::asio::io_context & ioc, bool optimize_single_threaded = false) - : Base(ios, Type, optimize_single_threaded) + : Base(ioc, Type, optimize_single_threaded) { // Note that we expect these to get sliced to socket, so DO NOT add any data members static_assert(sizeof(*this) == sizeof(socket), "Specialized socket must not have any specific data members"); diff --git a/azmqConfig.cmake b/azmqConfig.cmake index 33e7b02..4fcfe31 100644 --- a/azmqConfig.cmake +++ b/azmqConfig.cmake @@ -1,6 +1,11 @@ include(CMakeFindDependencyMacro) -find_package(Boost 1.68 COMPONENTS system date_time thread chrono random REQUIRED) +find_package(Boost 1.68 COMPONENTS date_time thread chrono random REQUIRED) +find_package(Boost 1.68 COMPONENTS system) +if (NOT Boost_SYSTEM_FOUND) + message(WARNING "Boost::system not found") +endif() + include(${CMAKE_CURRENT_LIST_DIR}/FindAzmqLibzmq.cmake) set(CMAKE_THREAD_PREFER_PTHREAD TRUE) find_package(Threads REQUIRED) -include("${CMAKE_CURRENT_LIST_DIR}/azmqTargets.cmake") \ No newline at end of file +include("${CMAKE_CURRENT_LIST_DIR}/azmqTargets.cmake") diff --git a/doc/examples/actor/main.cpp b/doc/examples/actor/main.cpp index 19880d7..93774e8 100644 --- a/doc/examples/actor/main.cpp +++ b/doc/examples/actor/main.cpp @@ -1,7 +1,7 @@ #include #include -#include +#include #include #include #include @@ -17,9 +17,9 @@ namespace pt = boost::posix_time; class server_t { public: - server_t(asio::io_service & ios) + server_t(asio::io_context & ioc) : pimpl_(std::make_shared()) - , frontend_(azmq::actor::spawn(ios, run, pimpl_)) + , frontend_(azmq::actor::spawn(ioc, run, pimpl_)) { } void ping() { @@ -76,7 +76,7 @@ class server_t { // This is the function run by the background thread static void run(azmq::socket & backend, ptr pimpl) { do_receive(backend, pimpl); - backend.get_io_service().run(); + backend.get_io_context().run(); } azmq::socket frontend_; @@ -97,29 +97,29 @@ void schedule_ping(asio::deadline_timer & timer, server_t & server) { }; int main(int argc, char** argv) { - asio::io_service ios; + asio::io_context ioc; std::cout << "Running..."; std::cout.flush(); // halt on SIGINT or SIGTERM - asio::signal_set signals(ios, SIGTERM, SIGINT); + asio::signal_set signals(ioc, SIGTERM, SIGINT); signals.async_wait([&](boost::system::error_code const&, int) { - ios.stop(); + ioc.stop(); }); - server_t server(ios); + server_t server(ioc); - asio::deadline_timer timer(ios); + asio::deadline_timer timer(ioc); schedule_ping(timer, server); // run for 5 secods - asio::deadline_timer deadline(ios, pt::seconds(5)); + asio::deadline_timer deadline(ioc, pt::seconds(5)); deadline.async_wait([&](boost::system::error_code const&) { - ios.stop(); + ioc.stop(); }); - ios.run(); + ioc.run(); std::cout << "Done. Results - " << server << std::endl; diff --git a/test/actor/main.cpp b/test/actor/main.cpp index 24f054f..674eec0 100644 --- a/test/actor/main.cpp +++ b/test/actor/main.cpp @@ -9,11 +9,15 @@ #include #include + +#include #include +#include #include #include #include +#include #define CATCH_CONFIG_MAIN #include @@ -29,10 +33,12 @@ std::string subj(const char* name) { TEST_CASE( "Async Send/Receive", "[actor]" ) { boost::system::error_code ecc; - size_t btc = 0; + std::promise btc_promise; + auto btc = btc_promise.get_future(); boost::system::error_code ecb; - size_t btb = 0; + std::promise btb_promise; + auto btb = btb_promise.get_future(); { std::array a; std::array b; @@ -42,27 +48,31 @@ TEST_CASE( "Async Send/Receive", "[actor]" ) { boost::asio::buffer(b) }}; - boost::asio::io_service ios; - auto s = azmq::actor::spawn(ios, [&](azmq::socket & ss) { + boost::asio::io_context io; + auto s = azmq::actor::spawn(io, [&](azmq::socket & ss) { ss.async_receive(rcv_bufs, [&](boost::system::error_code const& ec, size_t bytes_transferred) { ecb = ec; - btb = bytes_transferred; - ios.stop(); + btb_promise.set_value(bytes_transferred); + io.stop(); }); - ss.get_io_service().run(); + ss.get_io_context().run(); }); s.async_send(snd_bufs, [&] (boost::system::error_code const& ec, size_t bytes_transferred) { ecc = ec; - btc = bytes_transferred; + btc_promise.set_value(bytes_transferred); }); - boost::asio::io_service::work w(ios); - ios.run(); + auto work = boost::asio::make_work_guard(io); + io.run(); } + std::cout << "IO context run complete" << std::endl; + + REQUIRE(btb.wait_for(std::chrono::seconds(1)) == std::future_status::ready); + REQUIRE(btc.wait_for(std::chrono::seconds(1)) == std::future_status::ready); REQUIRE(ecc == boost::system::error_code()); - REQUIRE(btc == 4); + REQUIRE(btc.get() == 4); REQUIRE(ecb == boost::system::error_code()); - REQUIRE(btb == 4); + REQUIRE(btb.get() == 4); } diff --git a/test/cpp20/socket/CMakeLists.txt b/test/cpp20/socket/CMakeLists.txt index d416d23..ab7981d 100644 --- a/test/cpp20/socket/CMakeLists.txt +++ b/test/cpp20/socket/CMakeLists.txt @@ -32,7 +32,7 @@ target_link_libraries(${PROJECT_NAME} Azmq::azmq Boost::boost Boost::thread - Boost::system + ${Boost_SYSTEM_LIBRARY} ${ZeroMQ_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}) diff --git a/test/cpp20/socket/main.cpp b/test/cpp20/socket/main.cpp index a580f5f..23e03ce 100644 --- a/test/cpp20/socket/main.cpp +++ b/test/cpp20/socket/main.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include @@ -74,4 +75,3 @@ TEST_CASE("coroutine send/receive message", "[socket_cpp20]") { REQUIRE(btc.has_value()); REQUIRE(btc.value() == 4); } - diff --git a/test/message/CMakeLists.txt b/test/message/CMakeLists.txt index e254368..637579c 100644 --- a/test/message/CMakeLists.txt +++ b/test/message/CMakeLists.txt @@ -2,6 +2,6 @@ project(test_message) add_executable(${PROJECT_NAME} main.cpp) -target_link_libraries(${PROJECT_NAME} Azmq::azmq) +target_link_libraries(${PROJECT_NAME} Azmq::azmq Boost::boost ${Boost_SYSTEM_LIBRARY}) add_catch_test(${PROJECT_NAME}) diff --git a/test/message/main.cpp b/test/message/main.cpp index e3d79fc..b220ceb 100644 --- a/test/message/main.cpp +++ b/test/message/main.cpp @@ -166,7 +166,7 @@ TEST_CASE( "write_through_mutable_buffer", "[message]" ) { azmq::message mm(m); boost::asio::mutable_buffer bb = mm.buffer(); - auto pstr = boost::asio::buffer_cast(bb); + auto pstr = static_cast(bb.data()); pstr[0] = 't'; auto s = mm.string(); diff --git a/test/signal/main.cpp b/test/signal/main.cpp index 16e11d5..678607a 100644 --- a/test/signal/main.cpp +++ b/test/signal/main.cpp @@ -8,15 +8,15 @@ */ #include -#include +#include #define CATCH_CONFIG_MAIN #include TEST_CASE( "Send/Receive a signal", "[signal]" ) { - boost::asio::io_service ios; - azmq::pair_socket sb(ios); - azmq::pair_socket sc(ios); + boost::asio::io_context io; + azmq::pair_socket sb(io); + azmq::pair_socket sc(io); sb.bind("inproc://test"); sc.connect("inproc://test"); diff --git a/test/socket/main.cpp b/test/socket/main.cpp index c39088f..f83efc9 100644 --- a/test/socket/main.cpp +++ b/test/socket/main.cpp @@ -14,7 +14,8 @@ #include #include #include -#include +#include + #if BOOST_VERSION >= 107000 #include @@ -51,9 +52,9 @@ std::string subj(const char* name) { } TEST_CASE( "Set/Get options", "[socket]" ) { - boost::asio::io_service ios; + boost::asio::io_context ioc; - azmq::socket s(ios, ZMQ_ROUTER); + azmq::socket s(ioc, ZMQ_ROUTER); // set/get_option are generic, works for one and all... azmq::socket::rcv_hwm in_hwm(42); @@ -72,12 +73,12 @@ TEST_CASE( "Set/Get options", "[socket]" ) { } TEST_CASE( "Send/Receive single buffer", "[socket]") { - boost::asio::io_service ios; + boost::asio::io_context ioc; - azmq::socket sb(ios, ZMQ_PAIR); + azmq::socket sb(ioc, ZMQ_PAIR); sb.bind(subj(BOOST_CURRENT_FUNCTION)); - azmq::socket sc(ios, ZMQ_PAIR); + azmq::socket sc(ioc, ZMQ_PAIR); sc.connect(subj(BOOST_CURRENT_FUNCTION)); auto msg = "TEST"; @@ -92,12 +93,12 @@ TEST_CASE( "Send/Receive single buffer", "[socket]") { } TEST_CASE( "Send/Receive single message", "[socket]") { - boost::asio::io_service ios; + boost::asio::io_context ioc; - azmq::socket sb(ios, ZMQ_PAIR); + azmq::socket sb(ioc, ZMQ_PAIR); sb.bind(subj(BOOST_CURRENT_FUNCTION)); - azmq::socket sc(ios, ZMQ_PAIR); + azmq::socket sc(ioc, ZMQ_PAIR); sc.connect(subj(BOOST_CURRENT_FUNCTION)); auto msg = "TEST"; @@ -113,12 +114,12 @@ TEST_CASE( "Send/Receive single message", "[socket]") { } TEST_CASE( "Send/Receive synchronous", "[socket]" ) { - boost::asio::io_service ios; + boost::asio::io_context ioc; - azmq::socket sb(ios, ZMQ_ROUTER); + azmq::socket sb(ioc, ZMQ_ROUTER); sb.bind(subj(BOOST_CURRENT_FUNCTION)); - azmq::socket sc(ios, ZMQ_DEALER); + azmq::socket sc(ioc, ZMQ_DEALER); sc.connect(subj(BOOST_CURRENT_FUNCTION)); sc.send(snd_bufs); @@ -152,19 +153,19 @@ TEST_CASE( "Send/Receive synchronous", "[socket]" ) { } TEST_CASE( "Send/Receive async", "[socket_ops]" ) { - boost::asio::io_service ios_b; - boost::asio::io_service ios_c; + boost::asio::io_context ioc_b; + boost::asio::io_context ioc_c; - azmq::socket sb(ios_b, ZMQ_ROUTER); + azmq::socket sb(ioc_b, ZMQ_ROUTER); sb.bind(subj(BOOST_CURRENT_FUNCTION)); - azmq::socket sc(ios_c, ZMQ_DEALER); + azmq::socket sc(ioc_c, ZMQ_DEALER); sc.connect(subj(BOOST_CURRENT_FUNCTION)); boost::system::error_code ecc; size_t btc = 0; sc.async_send(snd_bufs, [&] (boost::system::error_code const& ec, size_t bytes_transferred) { - SCOPE_EXIT { ios_c.stop(); }; + SCOPE_EXIT { ioc_c.stop(); }; ecc = ec; btc = bytes_transferred; }); @@ -182,13 +183,13 @@ TEST_CASE( "Send/Receive async", "[socket_ops]" ) { boost::system::error_code ecb; size_t btb = 0; sb.async_receive(rcv_bufs, [&](boost::system::error_code const& ec, size_t bytes_transferred) { - SCOPE_EXIT { ios_b.stop(); }; + SCOPE_EXIT { ioc_b.stop(); }; ecb = ec; btb = bytes_transferred; }); - ios_c.run(); - ios_b.run(); + ioc_c.run(); + ioc_b.run(); REQUIRE(ecc == boost::system::error_code()); REQUIRE(btc == 4); @@ -202,7 +203,7 @@ TEST_CASE( "Async send/receive copies buffer refs", "[socket_ops]" ) { class Base { protected: - boost::asio::io_service ioservice; + boost::asio::io_context ioservice; azmq::pair_socket sock; boost::system::error_code error; size_t bytes = 0; @@ -311,21 +312,21 @@ TEST_CASE( "Async send/receive copies buffer refs", "[socket_ops]" ) { } TEST_CASE( "Send/Receive async is_speculative", "[socket_ops]" ) { - boost::asio::io_service ios_b; - boost::asio::io_service ios_c; + boost::asio::io_context ioc_b; + boost::asio::io_context ioc_c; - azmq::socket sb(ios_b, ZMQ_ROUTER); + azmq::socket sb(ioc_b, ZMQ_ROUTER); sb.set_option(azmq::socket::allow_speculative(true)); sb.bind(subj(BOOST_CURRENT_FUNCTION)); - azmq::socket sc(ios_c, ZMQ_DEALER); + azmq::socket sc(ioc_c, ZMQ_DEALER); sc.set_option(azmq::socket::allow_speculative(true)); sc.connect(subj(BOOST_CURRENT_FUNCTION)); boost::system::error_code ecc; size_t btc = 0; sc.async_send(snd_bufs, [&] (boost::system::error_code const& ec, size_t bytes_transferred) { - SCOPE_EXIT { ios_c.stop(); }; + SCOPE_EXIT { ioc_c.stop(); }; ecc = ec; btc = bytes_transferred; }); @@ -343,13 +344,13 @@ TEST_CASE( "Send/Receive async is_speculative", "[socket_ops]" ) { boost::system::error_code ecb; size_t btb = 0; sb.async_receive(rcv_bufs, [&](boost::system::error_code const& ec, size_t bytes_transferred) { - SCOPE_EXIT { ios_b.stop(); }; + SCOPE_EXIT { ioc_b.stop(); }; ecb = ec; btb = bytes_transferred; }); - ios_c.run(); - ios_b.run(); + ioc_c.run(); + ioc_b.run(); REQUIRE(ecc == boost::system::error_code()); REQUIRE(btc == 4); @@ -358,23 +359,23 @@ TEST_CASE( "Send/Receive async is_speculative", "[socket_ops]" ) { } TEST_CASE( "Send/Receive async threads", "[socket]" ) { - boost::asio::io_service ios_b; - azmq::socket sb(ios_b, ZMQ_ROUTER); + boost::asio::io_context ioc_b; + azmq::socket sb(ioc_b, ZMQ_ROUTER); sb.bind(subj(BOOST_CURRENT_FUNCTION)); - boost::asio::io_service ios_c; - azmq::socket sc(ios_c, ZMQ_DEALER); + boost::asio::io_context ioc_c; + azmq::socket sc(ioc_c, ZMQ_DEALER); sc.connect(subj(BOOST_CURRENT_FUNCTION)); boost::system::error_code ecc; size_t btc = 0; std::thread tc([&] { sc.async_send(snd_bufs, [&] (boost::system::error_code const& ec, size_t bytes_transferred) { - SCOPE_EXIT { ios_c.stop(); }; + SCOPE_EXIT { ioc_c.stop(); }; ecc = ec; btc = bytes_transferred; }); - ios_c.run(); + ioc_c.run(); }); boost::system::error_code ecb; @@ -391,11 +392,11 @@ TEST_CASE( "Send/Receive async threads", "[socket]" ) { }}; sb.async_receive(rcv_bufs, [&](boost::system::error_code const& ec, size_t bytes_transferred) { - SCOPE_EXIT { ios_b.stop(); }; + SCOPE_EXIT { ioc_b.stop(); }; ecb = ec; btb = bytes_transferred; }); - ios_b.run(); + ioc_b.run(); }); tc.join(); @@ -407,19 +408,19 @@ TEST_CASE( "Send/Receive async threads", "[socket]" ) { } TEST_CASE( "Send/Receive message async", "[socket]" ) { - boost::asio::io_service ios_b; - boost::asio::io_service ios_c; + boost::asio::io_context ioc_b; + boost::asio::io_context ioc_c; - azmq::socket sb(ios_b, ZMQ_ROUTER); + azmq::socket sb(ioc_b, ZMQ_ROUTER); sb.bind(subj(BOOST_CURRENT_FUNCTION)); - azmq::socket sc(ios_c, ZMQ_DEALER); + azmq::socket sc(ioc_c, ZMQ_DEALER); sc.connect(subj(BOOST_CURRENT_FUNCTION)); boost::system::error_code ecc; size_t btc = 0; sc.async_send(snd_bufs, [&] (boost::system::error_code const& ec, size_t bytes_transferred) { - SCOPE_EXIT { ios_c.stop(); }; + SCOPE_EXIT { ioc_c.stop(); }; ecc = ec; btc = bytes_transferred; }); @@ -431,7 +432,7 @@ TEST_CASE( "Send/Receive message async", "[socket]" ) { boost::system::error_code ecb; size_t btb = 0; sb.async_receive([&](boost::system::error_code const& ec, azmq::message & msg, size_t bytes_transferred) { - SCOPE_EXIT { ios_b.stop(); }; + SCOPE_EXIT { ioc_b.stop(); }; ecb = ec; if (ecb) return; @@ -453,8 +454,8 @@ TEST_CASE( "Send/Receive message async", "[socket]" ) { } }); - ios_c.run(); - ios_b.run(); + ioc_c.run(); + ioc_b.run(); REQUIRE(ecc == boost::system::error_code()); REQUIRE(btc == 4); @@ -463,19 +464,19 @@ TEST_CASE( "Send/Receive message async", "[socket]" ) { } TEST_CASE( "Send/Receive message more async", "[socket]" ) { - boost::asio::io_service ios_b; - boost::asio::io_service ios_c; + boost::asio::io_context ioc_b; + boost::asio::io_context ioc_c; - azmq::socket sb(ios_b, ZMQ_ROUTER); + azmq::socket sb(ioc_b, ZMQ_ROUTER); sb.bind(subj(BOOST_CURRENT_FUNCTION)); - azmq::socket sc(ios_c, ZMQ_DEALER); + azmq::socket sc(ioc_c, ZMQ_DEALER); sc.connect(subj(BOOST_CURRENT_FUNCTION)); boost::system::error_code ecc; size_t btc = 0; sc.async_send(snd_bufs, [&] (boost::system::error_code const& ec, size_t bytes_transferred) { - SCOPE_EXIT { ios_c.stop(); }; + SCOPE_EXIT { ioc_c.stop(); }; ecc = ec; btc = bytes_transferred; }); @@ -492,7 +493,7 @@ TEST_CASE( "Send/Receive message more async", "[socket]" ) { boost::system::error_code ecb; size_t btb = 0; sb.async_receive([&](boost::system::error_code const& ec, azmq::message & msg, size_t bytes_transferred) { - SCOPE_EXIT { ios_b.stop(); }; + SCOPE_EXIT { ioc_b.stop(); }; ecb = ec; if (ecb) return; @@ -511,8 +512,8 @@ TEST_CASE( "Send/Receive message more async", "[socket]" ) { (*it++).buffer_copy(buf); }); - ios_c.run(); - ios_b.run(); + ioc_c.run(); + ioc_b.run(); REQUIRE(ecc == boost::system::error_code()); REQUIRE(btc == 4); @@ -542,8 +543,8 @@ struct monitor_handler { std::string role_; std::vector events_; - monitor_handler(boost::asio::io_service & ios, azmq::socket& s, std::string role) - : socket_(s.monitor(ios, ZMQ_EVENT_ALL)) + monitor_handler(boost::asio::io_context & ioc, azmq::socket& s, std::string role) + : socket_(s.monitor(ioc, ZMQ_EVENT_ALL)) , role_(std::move(role)) { } @@ -591,22 +592,22 @@ void bounce(azmq::socket & server, azmq::socket & client) { } TEST_CASE( "Socket Monitor", "[socket]" ) { - boost::asio::io_service ios; - boost::asio::io_service ios_m; + boost::asio::io_context ioc; + boost::asio::io_context ioc_m; using socket_ptr = std::unique_ptr; - socket_ptr client(new azmq::socket(ios, ZMQ_DEALER)); + socket_ptr client(new azmq::socket(ioc, ZMQ_DEALER)); - socket_ptr server(new azmq::socket(ios, ZMQ_DEALER)); + socket_ptr server(new azmq::socket(ioc, ZMQ_DEALER)); - monitor_handler client_monitor(ios_m, *client, "client"); - monitor_handler server_monitor(ios_m, *server, "server"); + monitor_handler client_monitor(ioc_m, *client, "client"); + monitor_handler server_monitor(ioc_m, *server, "server"); client_monitor.start(); server_monitor.start(); std::thread t([&] { - ios_m.run(); + ioc_m.run(); }); server->bind("tcp://127.0.0.1:9998"); @@ -622,7 +623,7 @@ TEST_CASE( "Socket Monitor", "[socket]" ) { std::this_thread::sleep_for(std::chrono::seconds(1)); - ios_m.stop(); + ioc_m.stop(); t.join(); { @@ -651,8 +652,8 @@ TEST_CASE( "Socket Monitor", "[socket]" ) { TEST_CASE( "Attach Method", "[socket]" ) { using namespace boost::algorithm; - boost::asio::io_service ios; - azmq::dealer_socket s(ios); + boost::asio::io_context ioc; + azmq::dealer_socket s(ioc); std::vector elems; @@ -661,12 +662,12 @@ TEST_CASE( "Attach Method", "[socket]" ) { } TEST_CASE( "Pub/Sub", "[socket]" ) { - boost::asio::io_service ios; - azmq::sub_socket subscriber(ios); + boost::asio::io_context ioc; + azmq::sub_socket subscriber(ioc); subscriber.connect("tcp://127.0.0.1:5556"); subscriber.set_option(azmq::socket::subscribe("FOO")); - azmq::pub_socket publisher(ios); + azmq::pub_socket publisher(ioc); publisher.bind("tcp://127.0.0.1:5556"); std::this_thread::sleep_for(std::chrono::seconds(1)); @@ -696,32 +697,32 @@ struct state { sb.async_receive(rcv_bufs, [&] (boost::system::error_code const& ec, size_t) { if (ec) { s.ec = ec; - sb.get_io_service().stop(); + sb.get_io_context().stop(); return; } if (++s.ct >= s.max) - sb.get_io_service().stop(); + sb.get_io_context().stop(); run(s, sb); }); } }; TEST_CASE( "Loopback", "[socket]" ) { - boost::asio::io_service ios_b; - boost::asio::io_service ios_c; + boost::asio::io_context ioc_b; + boost::asio::io_context ioc_c; - azmq::socket sb(ios_b, ZMQ_ROUTER); + azmq::socket sb(ioc_b, ZMQ_ROUTER); sb.bind("tcp://127.0.0.1:5560"); - azmq::socket sc(ios_c, ZMQ_DEALER); + azmq::socket sc(ioc_c, ZMQ_DEALER); sc.connect("tcp://127.0.0.1:5560"); size_t ct = 100000; state s(ct); std::thread t([&] { state::run(s, sb); - ios_b.run(); + ioc_b.run(); }); for (auto i = 0u; i < ct; ++i) { @@ -735,7 +736,7 @@ TEST_CASE( "Loopback", "[socket]" ) { } TEST_CASE( "socket_service does not call pending completion handlers when destroyed", "[socket]" ) { - boost::asio::io_service ioservice; + boost::asio::io_context ioservice; azmq::socket socket(ioservice, ZMQ_ROUTER); socket.bind(subj(BOOST_CURRENT_FUNCTION)); socket.async_receive([](boost::system::error_code const& ec, azmq::message & msg, size_t bytes_transferred) { @@ -746,13 +747,13 @@ TEST_CASE( "socket_service does not call pending completion handlers when destro #if BOOST_VERSION >= 107000 TEST_CASE("Async Operation Send/Receive with callback", "[socket_ops]") { - boost::asio::io_service ios_b; - boost::asio::io_service ios_c; + boost::asio::io_context ioc_b; + boost::asio::io_context ioc_c; - azmq::socket sb(ios_b, ZMQ_ROUTER); + azmq::socket sb(ioc_b, ZMQ_ROUTER); sb.bind(subj(BOOST_CURRENT_FUNCTION)); - azmq::socket sc(ios_c, ZMQ_DEALER); + azmq::socket sc(ioc_c, ZMQ_DEALER); sc.connect(subj(BOOST_CURRENT_FUNCTION)); boost::system::error_code ecc; @@ -760,7 +761,7 @@ TEST_CASE("Async Operation Send/Receive with callback", "[socket_ops]") { azmq::async_send(sc, snd_bufs, [&](boost::system::error_code const &ec, size_t bytes_transferred) { SCOPE_EXIT - { ios_c.stop(); }; + { ioc_c.stop(); }; ecc = ec; btc = bytes_transferred; }); @@ -779,13 +780,13 @@ TEST_CASE("Async Operation Send/Receive with callback", "[socket_ops]") { size_t btb = 0; azmq::async_receive(sb, rcv_bufs, [&](boost::system::error_code const &ec, size_t bytes_transferred) { SCOPE_EXIT - { ios_b.stop(); }; + { ioc_b.stop(); }; ecb = ec; btb = bytes_transferred; }); - ios_c.run(); - ios_b.run(); + ioc_c.run(); + ioc_b.run(); REQUIRE(ecc == boost::system::error_code()); REQUIRE(btc == 4); @@ -794,13 +795,13 @@ TEST_CASE("Async Operation Send/Receive with callback", "[socket_ops]") { } TEST_CASE("Async Operation Send/Receive with future ", "[socket_ops]") { - boost::asio::io_service ios_b; - boost::asio::io_service ios_c; + boost::asio::io_context ioc_b; + boost::asio::io_context ioc_c; - azmq::socket sb(ios_b, ZMQ_ROUTER); + azmq::socket sb(ioc_b, ZMQ_ROUTER); sb.bind(subj(BOOST_CURRENT_FUNCTION)); - azmq::socket sc(ios_c, ZMQ_DEALER); + azmq::socket sc(ioc_c, ZMQ_DEALER); sc.connect(subj(BOOST_CURRENT_FUNCTION)); std::future btc = azmq::async_send(sc, snd_bufs, boost::asio::use_future); @@ -817,32 +818,43 @@ TEST_CASE("Async Operation Send/Receive with future ", "[socket_ops]") { std::future btb = azmq::async_receive(sb, rcv_bufs, boost::asio::use_future); - ios_c.run(); - ios_b.run(); + ioc_c.run(); + ioc_b.run(); REQUIRE(btc.get() == 4); REQUIRE(btb.get() == 9); } +// If boost >= 1.80 use completion token boost::asio::use_future TEST_CASE("Async Operation Send/Receive with stackful coroutine", "[socket_ops]") { - boost::asio::io_service ios; + boost::asio::io_context ioc; - azmq::socket sb(ios, ZMQ_ROUTER); + azmq::socket sb(ioc, ZMQ_ROUTER); sb.bind(subj(BOOST_CURRENT_FUNCTION)); - azmq::socket sc(ios, ZMQ_DEALER); + azmq::socket sc(ioc, ZMQ_DEALER); sc.connect(subj(BOOST_CURRENT_FUNCTION)); boost::optional btc{}; boost::optional btb{}; //send coroutine task - boost::asio::spawn(ios, [&](boost::asio::yield_context yield) { + # if BOOST_VERSION >= 108000 + auto future_send = + # endif + boost::asio::spawn(ioc, [&](boost::asio::yield_context yield) { btc = azmq::async_send(sc, snd_bufs, yield); - }); + } + #if BOOST_VERSION >= 108000 + , boost::asio::use_future + #endif + ); //receive coroutine task - boost::asio::spawn(ios, [&](boost::asio::yield_context yield) { + # if BOOST_VERSION >= 108000 + auto future_recv = + # endif + boost::asio::spawn(ioc, [&](boost::asio::yield_context yield) { std::array ident; std::array a; std::array b; @@ -854,33 +866,56 @@ TEST_CASE("Async Operation Send/Receive with stackful coroutine", "[socket_ops]" }}; btb = azmq::async_receive(sb, rcv_bufs, yield); - }); + } + #if BOOST_VERSION >= 108000 + , boost::asio::use_future + #endif + ); + + ioc.run(); + + // Make sure coroutines have executed + # if BOOST_VERSION >= 108000 + REQUIRE(future_send.wait_for(std::chrono::seconds(1)) == std::future_status::ready); + REQUIRE(future_recv.wait_for(std::chrono::seconds(1)) == std::future_status::ready); + # endif + + REQUIRE(btc.has_value()); + REQUIRE(btc.value() == 4); - ios.run(); REQUIRE(btb.has_value()); REQUIRE(btb.value() == 9); - REQUIRE(btc.has_value()); - REQUIRE(btc.value() == 4); } +// If boost >= 1.80 use completion token boost::asio::use_future TEST_CASE("Async Operation Send/Receive single message, stackful coroutine, one message at a time", "[socket_ops]") { - boost::asio::io_service ios; + boost::asio::io_context ioc; - azmq::socket sb(ios, ZMQ_ROUTER); + azmq::socket sb(ioc, ZMQ_ROUTER); sb.bind(subj(BOOST_CURRENT_FUNCTION)); - azmq::socket sc(ios, ZMQ_DEALER); + azmq::socket sc(ioc, ZMQ_DEALER); sc.connect(subj(BOOST_CURRENT_FUNCTION)); //send coroutine task - boost::asio::spawn(ios, [&](boost::asio::yield_context yield) { + #if BOOST_VERSION >= 108000 + auto future_send = + #endif + boost::asio::spawn(ioc, [&](boost::asio::yield_context yield) { auto const btc = azmq::async_send(sc, snd_bufs, yield); REQUIRE(btc == 4); - }); + } + #if BOOST_VERSION >= 108000 + , boost::asio::use_future + #endif + ); //receive coroutine task - boost::asio::spawn(ios, [&](boost::asio::yield_context yield) { + #if BOOST_VERSION >= 108000 + auto future_recv = + #endif + boost::asio::spawn(ioc, [&](boost::asio::yield_context yield) { auto frame1 = azmq::message{}; auto const btb1 = azmq::async_receive(sb, frame1, yield); REQUIRE(btb1 == 5); @@ -897,25 +932,33 @@ TEST_CASE("Async Operation Send/Receive single message, stackful coroutine, one REQUIRE(btb3 == 2); REQUIRE(!frame3.more()); REQUIRE(message_ref(snd_bufs.at(1)) == message_ref(frame3)); - - }); - - ios.run(); + } + #if BOOST_VERSION >= 108000 + , boost::asio::use_future + #endif + ); + + ioc.run(); + // Make sure coroutines have executed + #if BOOST_VERSION >= 108000 + REQUIRE(future_send.wait_for(std::chrono::seconds(1)) == std::future_status::ready); + REQUIRE(future_recv.wait_for(std::chrono::seconds(1)) == std::future_status::ready); + #endif } TEST_CASE("Async Operation Send/Receive single message, check thread safety", "[socket_ops]") { - boost::asio::io_service ios; + boost::asio::io_context ioc; #if BOOST_VERSION >= 107400 - boost::asio::strand strand{ios.get_executor()}; + boost::asio::strand strand{ioc.get_executor()}; #else - boost::asio::strand strand{ios.get_executor()}; + boost::asio::strand strand{ioc.get_executor()}; #endif - azmq::socket sb(ios, ZMQ_ROUTER); + azmq::socket sb(ioc, ZMQ_ROUTER); sb.bind(subj(BOOST_CURRENT_FUNCTION)); - azmq::socket sc(ios, ZMQ_DEALER); + azmq::socket sc(ioc, ZMQ_DEALER); sc.connect(subj(BOOST_CURRENT_FUNCTION)); //send coroutine task @@ -950,8 +993,7 @@ TEST_CASE("Async Operation Send/Receive single message, check thread safety", "[ REQUIRE(message_ref(snd_bufs.at(1)) == boost::string_ref(b.data(), 2)); }); - ios.run(); + ioc.run(); } #endif // BOOST_VERSION >= 107000 -