diff --git a/src/corosio/src/acceptor.cpp b/src/corosio/src/acceptor.cpp index 119aedb..b5d2c5f 100644 --- a/src/corosio/src/acceptor.cpp +++ b/src/corosio/src/acceptor.cpp @@ -9,10 +9,12 @@ #include -#ifdef _WIN32 -#include "src/detail/win/sockets.hpp" -#else -#include "detail/posix_sockets.hpp" +#include "src/detail/config_backend.hpp" + +#if defined(BOOST_COROSIO_BACKEND_IOCP) +#include "src/detail/iocp/sockets.hpp" +#elif defined(BOOST_COROSIO_BACKEND_EPOLL) +#include "src/detail/epoll/sockets.hpp" #endif #include @@ -23,12 +25,12 @@ namespace boost { namespace corosio { namespace { -#ifdef _WIN32 +#if defined(BOOST_COROSIO_BACKEND_IOCP) using acceptor_service = detail::win_sockets; using acceptor_impl_type = detail::win_acceptor_impl; -#else -using acceptor_service = detail::posix_sockets; -using acceptor_impl_type = detail::posix_acceptor_impl; +#elif defined(BOOST_COROSIO_BACKEND_EPOLL) +using acceptor_service = detail::epoll_sockets; +using acceptor_impl_type = detail::epoll_acceptor_impl; #endif } // namespace diff --git a/src/corosio/src/detail/config_backend.hpp b/src/corosio/src/detail/config_backend.hpp new file mode 100644 index 0000000..23dcfed --- /dev/null +++ b/src/corosio/src/detail/config_backend.hpp @@ -0,0 +1,50 @@ +// +// Copyright (c) 2026 Steve Gerbino +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/cppalliance/corosio +// + +#ifndef BOOST_COROSIO_DETAIL_CONFIG_BACKEND_HPP +#define BOOST_COROSIO_DETAIL_CONFIG_BACKEND_HPP + +// +// Backend selection for I/O multiplexing and signal handling. +// +// I/O Backends: +// BOOST_COROSIO_BACKEND_IOCP - Windows I/O Completion Ports +// BOOST_COROSIO_BACKEND_EPOLL - Linux epoll +// BOOST_COROSIO_BACKEND_IO_URING - Linux io_uring (future) +// BOOST_COROSIO_BACKEND_KQUEUE - BSD/macOS kqueue (future) +// BOOST_COROSIO_BACKEND_POLL - POSIX poll fallback (future) +// +// Signal Backends: +// BOOST_COROSIO_SIGNAL_WIN - Windows (SetConsoleCtrlHandler + signal) +// BOOST_COROSIO_SIGNAL_POSIX - POSIX (sigaction) +// + +#if defined(_WIN32) + #define BOOST_COROSIO_BACKEND_IOCP 1 + #define BOOST_COROSIO_SIGNAL_WIN 1 +#elif defined(__linux__) + #if defined(BOOST_COROSIO_USE_IO_URING) + #define BOOST_COROSIO_BACKEND_IO_URING 1 + #else + #define BOOST_COROSIO_BACKEND_EPOLL 1 + #endif + #define BOOST_COROSIO_SIGNAL_POSIX 1 +#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__) + #define BOOST_COROSIO_BACKEND_KQUEUE 1 + #define BOOST_COROSIO_SIGNAL_POSIX 1 +#elif defined(__APPLE__) + #define BOOST_COROSIO_BACKEND_KQUEUE 1 + #define BOOST_COROSIO_SIGNAL_POSIX 1 +#else + // Fallback to poll for other POSIX systems + #define BOOST_COROSIO_BACKEND_POLL 1 + #define BOOST_COROSIO_SIGNAL_POSIX 1 +#endif + +#endif // BOOST_COROSIO_DETAIL_CONFIG_BACKEND_HPP diff --git a/src/corosio/src/detail/posix_op.hpp b/src/corosio/src/detail/epoll/op.hpp similarity index 91% rename from src/corosio/src/detail/posix_op.hpp rename to src/corosio/src/detail/epoll/op.hpp index 81fdff1..6a49461 100644 --- a/src/corosio/src/detail/posix_op.hpp +++ b/src/corosio/src/detail/epoll/op.hpp @@ -7,8 +7,12 @@ // Official repository: https://github.com/cppalliance/corosio // -#ifndef BOOST_COROSIO_DETAIL_POSIX_OP_HPP -#define BOOST_COROSIO_DETAIL_POSIX_OP_HPP +#ifndef BOOST_COROSIO_DETAIL_EPOLL_OP_HPP +#define BOOST_COROSIO_DETAIL_EPOLL_OP_HPP + +#include "src/detail/config_backend.hpp" + +#if defined(BOOST_COROSIO_BACKEND_EPOLL) #include #include @@ -37,17 +41,17 @@ namespace boost { namespace corosio { namespace detail { -/** Base class for POSIX async operations. +/** Base class for epoll async operations. This class is analogous to overlapped_op on Windows. It stores the coroutine handle, executor, and result pointers needed to complete an async operation. */ -struct posix_op : scheduler_op +struct epoll_op : scheduler_op { struct canceller { - posix_op* op; + epoll_op* op; void operator()() const noexcept { op->request_cancel(); } }; @@ -64,7 +68,7 @@ struct posix_op : scheduler_op std::atomic cancelled{false}; std::optional> stop_cb; - posix_op() + epoll_op() { data_ = this; } @@ -135,16 +139,16 @@ struct posix_op : scheduler_op virtual void perform_io() noexcept {} }; -inline posix_op* -get_posix_op(scheduler_op* h) noexcept +inline epoll_op* +get_epoll_op(scheduler_op* h) noexcept { - return static_cast(h->data()); + return static_cast(h->data()); } //------------------------------------------------------------------------------ /** Connect operation state. */ -struct posix_connect_op : posix_op +struct epoll_connect_op : epoll_op { void perform_io() noexcept override { @@ -160,7 +164,7 @@ struct posix_connect_op : posix_op //------------------------------------------------------------------------------ /** Read operation state with buffer descriptors. */ -struct posix_read_op : posix_op +struct epoll_read_op : epoll_op { static constexpr std::size_t max_buffers = 16; iovec iovecs[max_buffers]; @@ -170,7 +174,7 @@ struct posix_read_op : posix_op void reset() noexcept { - posix_op::reset(); + epoll_op::reset(); iovec_count = 0; } @@ -187,7 +191,7 @@ struct posix_read_op : posix_op //------------------------------------------------------------------------------ /** Write operation state with buffer descriptors. */ -struct posix_write_op : posix_op +struct epoll_write_op : epoll_op { static constexpr std::size_t max_buffers = 16; iovec iovecs[max_buffers]; @@ -195,7 +199,7 @@ struct posix_write_op : posix_op void reset() noexcept { - posix_op::reset(); + epoll_op::reset(); iovec_count = 0; } @@ -212,7 +216,7 @@ struct posix_write_op : posix_op //------------------------------------------------------------------------------ /** Accept operation state. */ -struct posix_accept_op : posix_op +struct epoll_accept_op : epoll_op { int accepted_fd = -1; io_object::io_object_impl* peer_impl = nullptr; @@ -224,7 +228,7 @@ struct posix_accept_op : posix_op void reset() noexcept { - posix_op::reset(); + epoll_op::reset(); accepted_fd = -1; peer_impl = nullptr; impl_out = nullptr; @@ -297,4 +301,6 @@ struct posix_accept_op : posix_op } // namespace corosio } // namespace boost -#endif +#endif // BOOST_COROSIO_BACKEND_EPOLL + +#endif // BOOST_COROSIO_DETAIL_EPOLL_OP_HPP diff --git a/src/corosio/src/detail/posix_resolver_service.hpp b/src/corosio/src/detail/epoll/resolver_service.hpp similarity index 62% rename from src/corosio/src/detail/posix_resolver_service.hpp rename to src/corosio/src/detail/epoll/resolver_service.hpp index ac8f83b..0f09712 100644 --- a/src/corosio/src/detail/posix_resolver_service.hpp +++ b/src/corosio/src/detail/epoll/resolver_service.hpp @@ -7,8 +7,12 @@ // Official repository: https://github.com/cppalliance/corosio // -#ifndef BOOST_COROSIO_DETAIL_POSIX_RESOLVER_SERVICE_HPP -#define BOOST_COROSIO_DETAIL_POSIX_RESOLVER_SERVICE_HPP +#ifndef BOOST_COROSIO_DETAIL_EPOLL_RESOLVER_SERVICE_HPP +#define BOOST_COROSIO_DETAIL_EPOLL_RESOLVER_SERVICE_HPP + +#include "src/detail/config_backend.hpp" + +#if defined(BOOST_COROSIO_BACKEND_EPOLL) #include #include @@ -25,27 +29,27 @@ namespace boost { namespace corosio { namespace detail { -class posix_resolver_service; -class posix_resolver_impl; +class epoll_resolver_service; +class epoll_resolver_impl; //------------------------------------------------------------------------------ -/** Resolver implementation stub for POSIX platforms. +/** Resolver implementation stub for Linux. This is a placeholder implementation that allows compilation on - POSIX platforms. Operations throw std::logic_error indicating - the functionality is not yet implemented. + Linux. Operations throw std::logic_error indicating the + functionality is not yet implemented. - @note Full POSIX resolver support is planned for a future release. + @note Full resolver support is planned for a future release. */ -class posix_resolver_impl +class epoll_resolver_impl : public resolver::resolver_impl - , public capy::intrusive_list::node + , public capy::intrusive_list::node { - friend class posix_resolver_service; + friend class epoll_resolver_service; public: - explicit posix_resolver_impl(posix_resolver_service& svc) noexcept + explicit epoll_resolver_impl(epoll_resolver_service& svc) noexcept : svc_(svc) { } @@ -62,45 +66,45 @@ class posix_resolver_impl system::error_code*, resolver_results*) override { - throw std::logic_error("posix resolver resolve not implemented"); + throw std::logic_error("epoll resolver resolve not implemented"); } void cancel() noexcept { /* stub */ } private: - posix_resolver_service& svc_; + epoll_resolver_service& svc_; }; //------------------------------------------------------------------------------ -/** POSIX resolver service stub. +/** Linux resolver service stub. This service provides placeholder implementations for DNS - resolution on POSIX platforms. Operations throw std::logic_error. + resolution on Linux. Operations throw std::logic_error. - @note Full POSIX resolver support is planned for a future release. + @note Full resolver support is planned for a future release. */ -class posix_resolver_service +class epoll_resolver_service : public capy::execution_context::service { public: - using key_type = posix_resolver_service; + using key_type = epoll_resolver_service; /** Construct the resolver service. @param ctx Reference to the owning execution_context. */ - explicit posix_resolver_service(capy::execution_context& /*ctx*/) + explicit epoll_resolver_service(capy::execution_context& /*ctx*/) { } /** Destroy the resolver service. */ - ~posix_resolver_service() + ~epoll_resolver_service() { } - posix_resolver_service(posix_resolver_service const&) = delete; - posix_resolver_service& operator=(posix_resolver_service const&) = delete; + epoll_resolver_service(epoll_resolver_service const&) = delete; + epoll_resolver_service& operator=(epoll_resolver_service const&) = delete; /** Shut down the service. */ void shutdown() override @@ -115,16 +119,16 @@ class posix_resolver_service } /** Create a new resolver implementation. */ - posix_resolver_impl& create_impl() + epoll_resolver_impl& create_impl() { std::lock_guard lock(mutex_); - auto* impl = new posix_resolver_impl(*this); + auto* impl = new epoll_resolver_impl(*this); resolver_list_.push_back(impl); return *impl; } /** Destroy a resolver implementation. */ - void destroy_impl(posix_resolver_impl& impl) + void destroy_impl(epoll_resolver_impl& impl) { std::lock_guard lock(mutex_); resolver_list_.remove(&impl); @@ -133,13 +137,13 @@ class posix_resolver_service private: std::mutex mutex_; - capy::intrusive_list resolver_list_; + capy::intrusive_list resolver_list_; }; //------------------------------------------------------------------------------ inline void -posix_resolver_impl:: +epoll_resolver_impl:: release() { svc_.destroy_impl(*this); @@ -149,4 +153,6 @@ release() } // namespace corosio } // namespace boost -#endif +#endif // BOOST_COROSIO_BACKEND_EPOLL + +#endif // BOOST_COROSIO_DETAIL_EPOLL_RESOLVER_SERVICE_HPP diff --git a/src/corosio/src/detail/posix_scheduler.cpp b/src/corosio/src/detail/epoll/scheduler.cpp similarity index 91% rename from src/corosio/src/detail/posix_scheduler.cpp rename to src/corosio/src/detail/epoll/scheduler.cpp index fbbfc22..538a024 100644 --- a/src/corosio/src/detail/posix_scheduler.cpp +++ b/src/corosio/src/detail/epoll/scheduler.cpp @@ -1,5 +1,5 @@ // -// Copyright (c) 2025 Vinnie Falco (vinnie dot falco at gmail dot com) +// Copyright (c) 2026 Steve Gerbino // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -7,10 +7,12 @@ // Official repository: https://github.com/cppalliance/corosio // -#ifndef _WIN32 +#include "src/detail/config_backend.hpp" -#include "src/detail/posix_scheduler.hpp" -#include "src/detail/posix_op.hpp" +#if defined(BOOST_COROSIO_BACKEND_EPOLL) + +#include "src/detail/epoll/scheduler.hpp" +#include "src/detail/epoll/op.hpp" #include #include @@ -34,7 +36,7 @@ namespace { struct scheduler_context { - posix_scheduler const* key; + epoll_scheduler const* key; scheduler_context* next; }; @@ -45,7 +47,7 @@ struct thread_context_guard scheduler_context frame_; explicit thread_context_guard( - posix_scheduler const* ctx) noexcept + epoll_scheduler const* ctx) noexcept : frame_{ctx, context_stack.get()} { context_stack.set(&frame_); @@ -59,8 +61,8 @@ struct thread_context_guard } // namespace -posix_scheduler:: -posix_scheduler( +epoll_scheduler:: +epoll_scheduler( capy::execution_context& ctx, int) : epoll_fd_(-1) @@ -103,11 +105,11 @@ posix_scheduler( timer_svc_->set_on_earliest_changed( timer_service::callback( this, - [](void* p) { static_cast(p)->wakeup(); })); + [](void* p) { static_cast(p)->wakeup(); })); } -posix_scheduler:: -~posix_scheduler() +epoll_scheduler:: +~epoll_scheduler() { if (event_fd_ >= 0) ::close(event_fd_); @@ -116,7 +118,7 @@ posix_scheduler:: } void -posix_scheduler:: +epoll_scheduler:: shutdown() { std::unique_lock lock(mutex_); @@ -136,7 +138,7 @@ shutdown() } void -posix_scheduler:: +epoll_scheduler:: post(capy::any_coro h) const { struct post_handler final @@ -176,7 +178,7 @@ post(capy::any_coro h) const } void -posix_scheduler:: +epoll_scheduler:: post(scheduler_op* h) const { outstanding_work_.fetch_add(1, std::memory_order_relaxed); @@ -189,14 +191,14 @@ post(scheduler_op* h) const } void -posix_scheduler:: +epoll_scheduler:: on_work_started() noexcept { outstanding_work_.fetch_add(1, std::memory_order_relaxed); } void -posix_scheduler:: +epoll_scheduler:: on_work_finished() noexcept { if (outstanding_work_.fetch_sub(1, std::memory_order_acq_rel) == 1) @@ -204,7 +206,7 @@ on_work_finished() noexcept } bool -posix_scheduler:: +epoll_scheduler:: running_in_this_thread() const noexcept { for (auto* c = context_stack.get(); c != nullptr; c = c->next) @@ -214,7 +216,7 @@ running_in_this_thread() const noexcept } void -posix_scheduler:: +epoll_scheduler:: stop() { bool expected = false; @@ -226,21 +228,21 @@ stop() } bool -posix_scheduler:: +epoll_scheduler:: stopped() const noexcept { return stopped_.load(std::memory_order_acquire); } void -posix_scheduler:: +epoll_scheduler:: restart() { stopped_.store(false, std::memory_order_release); } std::size_t -posix_scheduler:: +epoll_scheduler:: run() { if (stopped_.load(std::memory_order_acquire)) @@ -262,7 +264,7 @@ run() } std::size_t -posix_scheduler:: +epoll_scheduler:: run_one() { if (stopped_.load(std::memory_order_acquire)) @@ -279,7 +281,7 @@ run_one() } std::size_t -posix_scheduler:: +epoll_scheduler:: wait_one(long usec) { if (stopped_.load(std::memory_order_acquire)) @@ -296,7 +298,7 @@ wait_one(long usec) } std::size_t -posix_scheduler:: +epoll_scheduler:: poll() { if (stopped_.load(std::memory_order_acquire)) @@ -318,7 +320,7 @@ poll() } std::size_t -posix_scheduler:: +epoll_scheduler:: poll_one() { if (stopped_.load(std::memory_order_acquire)) @@ -335,8 +337,8 @@ poll_one() } void -posix_scheduler:: -register_fd(int fd, posix_op* op, std::uint32_t events) const +epoll_scheduler:: +register_fd(int fd, epoll_op* op, std::uint32_t events) const { epoll_event ev{}; ev.events = events; @@ -350,8 +352,8 @@ register_fd(int fd, posix_op* op, std::uint32_t events) const } void -posix_scheduler:: -modify_fd(int fd, posix_op* op, std::uint32_t events) const +epoll_scheduler:: +modify_fd(int fd, epoll_op* op, std::uint32_t events) const { epoll_event ev{}; ev.events = events; @@ -365,7 +367,7 @@ modify_fd(int fd, posix_op* op, std::uint32_t events) const } void -posix_scheduler:: +epoll_scheduler:: unregister_fd(int fd) const { // EPOLL_CTL_DEL ignores the event parameter (can be NULL on Linux 2.6.9+) @@ -373,21 +375,21 @@ unregister_fd(int fd) const } void -posix_scheduler:: +epoll_scheduler:: work_started() const noexcept { outstanding_work_.fetch_add(1, std::memory_order_relaxed); } void -posix_scheduler:: +epoll_scheduler:: work_finished() const noexcept { outstanding_work_.fetch_sub(1, std::memory_order_acq_rel); } void -posix_scheduler:: +epoll_scheduler:: wakeup() const { // Write cannot fail: eventfd counter won't overflow with single increments @@ -398,12 +400,12 @@ wakeup() const // RAII guard - work_finished called even if handler throws struct work_guard { - posix_scheduler const* self; + epoll_scheduler const* self; ~work_guard() { self->work_finished(); } }; long -posix_scheduler:: +epoll_scheduler:: calculate_timeout(long requested_timeout_us) const { if (requested_timeout_us == 0) @@ -429,7 +431,7 @@ calculate_timeout(long requested_timeout_us) const } std::size_t -posix_scheduler:: +epoll_scheduler:: do_one(long timeout_us) { for (;;) @@ -493,7 +495,7 @@ do_one(long timeout_us) continue; } - auto* op = static_cast(events[i].data.ptr); + auto* op = static_cast(events[i].data.ptr); // One-shot: unregister before I/O unregister_fd(op->fd); diff --git a/src/corosio/src/detail/posix_scheduler.hpp b/src/corosio/src/detail/epoll/scheduler.hpp similarity index 84% rename from src/corosio/src/detail/posix_scheduler.hpp rename to src/corosio/src/detail/epoll/scheduler.hpp index b33c3b5..7af83db 100644 --- a/src/corosio/src/detail/posix_scheduler.hpp +++ b/src/corosio/src/detail/epoll/scheduler.hpp @@ -1,5 +1,5 @@ // -// Copyright (c) 2025 Vinnie Falco (vinnie dot falco at gmail dot com) +// Copyright (c) 2026 Steve Gerbino // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -7,8 +7,12 @@ // Official repository: https://github.com/cppalliance/corosio // -#ifndef BOOST_COROSIO_DETAIL_POSIX_SCHEDULER_HPP -#define BOOST_COROSIO_DETAIL_POSIX_SCHEDULER_HPP +#ifndef BOOST_COROSIO_DETAIL_EPOLL_SCHEDULER_HPP +#define BOOST_COROSIO_DETAIL_EPOLL_SCHEDULER_HPP + +#include "src/detail/config_backend.hpp" + +#if defined(BOOST_COROSIO_BACKEND_EPOLL) #include #include @@ -27,9 +31,9 @@ namespace boost { namespace corosio { namespace detail { -struct posix_op; +struct epoll_op; -/** POSIX scheduler using epoll for I/O multiplexing. +/** Linux scheduler using epoll for I/O multiplexing. This scheduler implements the scheduler interface using Linux epoll for efficient I/O event notification. It manages a queue of handlers @@ -42,7 +46,7 @@ struct posix_op; @par Thread Safety All public member functions are thread-safe. */ -class posix_scheduler +class epoll_scheduler : public scheduler , public capy::execution_context::service { @@ -56,14 +60,14 @@ class posix_scheduler @param ctx Reference to the owning execution_context. @param concurrency_hint Hint for expected thread count (unused). */ - posix_scheduler( + epoll_scheduler( capy::execution_context& ctx, int concurrency_hint = -1); - ~posix_scheduler(); + ~epoll_scheduler(); - posix_scheduler(posix_scheduler const&) = delete; - posix_scheduler& operator=(posix_scheduler const&) = delete; + epoll_scheduler(epoll_scheduler const&) = delete; + epoll_scheduler& operator=(epoll_scheduler const&) = delete; void shutdown() override; void post(capy::any_coro h) const override; @@ -95,7 +99,7 @@ class posix_scheduler @param op The operation associated with this fd. @param events The epoll events to monitor (EPOLLIN, EPOLLOUT, etc.). */ - void register_fd(int fd, posix_op* op, std::uint32_t events) const; + void register_fd(int fd, epoll_op* op, std::uint32_t events) const; /** Modify epoll registration for a file descriptor. @@ -103,7 +107,7 @@ class posix_scheduler @param op The operation associated with this fd. @param events The new epoll events to monitor. */ - void modify_fd(int fd, posix_op* op, std::uint32_t events) const; + void modify_fd(int fd, epoll_op* op, std::uint32_t events) const; /** Unregister a file descriptor from epoll. @@ -136,4 +140,6 @@ class posix_scheduler } // namespace corosio } // namespace boost -#endif +#endif // BOOST_COROSIO_BACKEND_EPOLL + +#endif // BOOST_COROSIO_DETAIL_EPOLL_SCHEDULER_HPP diff --git a/src/corosio/src/detail/posix_sockets.hpp b/src/corosio/src/detail/epoll/sockets.hpp similarity index 78% rename from src/corosio/src/detail/posix_sockets.hpp rename to src/corosio/src/detail/epoll/sockets.hpp index b96e997..14384ef 100644 --- a/src/corosio/src/detail/posix_sockets.hpp +++ b/src/corosio/src/detail/epoll/sockets.hpp @@ -7,8 +7,12 @@ // Official repository: https://github.com/cppalliance/corosio // -#ifndef BOOST_COROSIO_DETAIL_POSIX_SOCKETS_HPP -#define BOOST_COROSIO_DETAIL_POSIX_SOCKETS_HPP +#ifndef BOOST_COROSIO_DETAIL_EPOLL_SOCKETS_HPP +#define BOOST_COROSIO_DETAIL_EPOLL_SOCKETS_HPP + +#include "src/detail/config_backend.hpp" + +#if defined(BOOST_COROSIO_BACKEND_EPOLL) #include #include @@ -18,8 +22,8 @@ #include #include -#include "src/detail/posix_op.hpp" -#include "src/detail/posix_scheduler.hpp" +#include "src/detail/epoll/op.hpp" +#include "src/detail/epoll/scheduler.hpp" #include "src/detail/endpoint_convert.hpp" #include @@ -36,9 +40,9 @@ namespace boost { namespace corosio { namespace detail { -class posix_sockets; -class posix_socket_impl; -class posix_acceptor_impl; +class epoll_sockets; +class epoll_socket_impl; +class epoll_acceptor_impl; //------------------------------------------------------------------------------ @@ -47,14 +51,14 @@ class posix_acceptor_impl; This class contains the state for a single socket, including the native socket handle and pending operations. */ -class posix_socket_impl +class epoll_socket_impl : public socket::socket_impl - , public capy::intrusive_list::node + , public capy::intrusive_list::node { - friend class posix_sockets; + friend class epoll_sockets; public: - explicit posix_socket_impl(posix_sockets& svc) noexcept; + explicit epoll_socket_impl(epoll_sockets& svc) noexcept; void release() override; @@ -87,12 +91,12 @@ class posix_socket_impl void close_socket() noexcept; void set_socket(int fd) noexcept { fd_ = fd; } - posix_connect_op conn_; - posix_read_op rd_; - posix_write_op wr_; + epoll_connect_op conn_; + epoll_read_op rd_; + epoll_write_op wr_; private: - posix_sockets& svc_; + epoll_sockets& svc_; int fd_ = -1; }; @@ -102,14 +106,14 @@ class posix_socket_impl This class contains the state for a listening socket. */ -class posix_acceptor_impl +class epoll_acceptor_impl : public acceptor::acceptor_impl - , public capy::intrusive_list::node + , public capy::intrusive_list::node { - friend class posix_sockets; + friend class epoll_sockets; public: - explicit posix_acceptor_impl(posix_sockets& svc) noexcept; + explicit epoll_acceptor_impl(epoll_sockets& svc) noexcept; void release() override; @@ -125,59 +129,59 @@ class posix_acceptor_impl void cancel() noexcept; void close_socket() noexcept; - posix_accept_op acc_; + epoll_accept_op acc_; private: - posix_sockets& svc_; + epoll_sockets& svc_; int fd_ = -1; }; //------------------------------------------------------------------------------ -/** POSIX epoll socket management service. +/** epoll socket management service. This service owns all socket implementations and coordinates their lifecycle with the epoll-based scheduler. */ -class posix_sockets +class epoll_sockets : public capy::execution_context::service { public: - using key_type = posix_sockets; + using key_type = epoll_sockets; /** Construct the socket service. @param ctx Reference to the owning execution_context. */ - explicit posix_sockets(capy::execution_context& ctx); + explicit epoll_sockets(capy::execution_context& ctx); /** Destroy the socket service. */ - ~posix_sockets(); + ~epoll_sockets(); - posix_sockets(posix_sockets const&) = delete; - posix_sockets& operator=(posix_sockets const&) = delete; + epoll_sockets(epoll_sockets const&) = delete; + epoll_sockets& operator=(epoll_sockets const&) = delete; /** Shut down the service. */ void shutdown() override; /** Create a new socket implementation. */ - posix_socket_impl& create_impl(); + epoll_socket_impl& create_impl(); /** Destroy a socket implementation. */ - void destroy_impl(posix_socket_impl& impl); + void destroy_impl(epoll_socket_impl& impl); /** Create and configure a socket. @param impl The socket implementation to initialize. @return Error code, or success. */ - system::error_code open_socket(posix_socket_impl& impl); + system::error_code open_socket(epoll_socket_impl& impl); /** Create a new acceptor implementation. */ - posix_acceptor_impl& create_acceptor_impl(); + epoll_acceptor_impl& create_acceptor_impl(); /** Destroy an acceptor implementation. */ - void destroy_acceptor_impl(posix_acceptor_impl& impl); + void destroy_acceptor_impl(epoll_acceptor_impl& impl); /** Create, bind, and listen on an acceptor socket. @@ -187,15 +191,15 @@ class posix_sockets @return Error code, or success. */ system::error_code open_acceptor( - posix_acceptor_impl& impl, + epoll_acceptor_impl& impl, endpoint ep, int backlog); /** Return the scheduler. */ - posix_scheduler& scheduler() const noexcept { return sched_; } + epoll_scheduler& scheduler() const noexcept { return sched_; } /** Post an operation for completion. */ - void post(posix_op* op); + void post(epoll_op* op); /** Notify scheduler of pending I/O work. */ void work_started() noexcept; @@ -204,25 +208,25 @@ class posix_sockets void work_finished() noexcept; private: - posix_scheduler& sched_; + epoll_scheduler& sched_; std::mutex mutex_; - capy::intrusive_list socket_list_; - capy::intrusive_list acceptor_list_; + capy::intrusive_list socket_list_; + capy::intrusive_list acceptor_list_; }; //------------------------------------------------------------------------------ -// posix_socket_impl implementation +// epoll_socket_impl implementation //------------------------------------------------------------------------------ inline -posix_socket_impl:: -posix_socket_impl(posix_sockets& svc) noexcept +epoll_socket_impl:: +epoll_socket_impl(epoll_sockets& svc) noexcept : svc_(svc) { } inline void -posix_socket_impl:: +epoll_socket_impl:: release() { close_socket(); @@ -230,7 +234,7 @@ release() } inline void -posix_socket_impl:: +epoll_socket_impl:: connect( std::coroutine_handle<> h, capy::any_executor_ref d, @@ -268,7 +272,7 @@ connect( } inline void -posix_socket_impl:: +epoll_socket_impl:: read_some( std::coroutine_handle<> h, capy::any_executor_ref d, @@ -286,8 +290,8 @@ read_some( op.fd = fd_; op.start(token); - capy::mutable_buffer bufs[posix_read_op::max_buffers]; - op.iovec_count = static_cast(param.copy_to(bufs, posix_read_op::max_buffers)); + capy::mutable_buffer bufs[epoll_read_op::max_buffers]; + op.iovec_count = static_cast(param.copy_to(bufs, epoll_read_op::max_buffers)); for (int i = 0; i < op.iovec_count; ++i) { op.iovecs[i].iov_base = bufs[i].data(); @@ -322,7 +326,7 @@ read_some( } inline void -posix_socket_impl:: +epoll_socket_impl:: write_some( std::coroutine_handle<> h, capy::any_executor_ref d, @@ -340,8 +344,8 @@ write_some( op.fd = fd_; op.start(token); - capy::mutable_buffer bufs[posix_write_op::max_buffers]; - op.iovec_count = static_cast(param.copy_to(bufs, posix_write_op::max_buffers)); + capy::mutable_buffer bufs[epoll_write_op::max_buffers]; + op.iovec_count = static_cast(param.copy_to(bufs, epoll_write_op::max_buffers)); for (int i = 0; i < op.iovec_count; ++i) { op.iovecs[i].iov_base = bufs[i].data(); @@ -370,7 +374,7 @@ write_some( } inline void -posix_socket_impl:: +epoll_socket_impl:: cancel() noexcept { conn_.request_cancel(); @@ -379,7 +383,7 @@ cancel() noexcept } inline void -posix_socket_impl:: +epoll_socket_impl:: close_socket() noexcept { if (fd_ >= 0) @@ -391,18 +395,18 @@ close_socket() noexcept } //------------------------------------------------------------------------------ -// posix_acceptor_impl implementation +// epoll_acceptor_impl implementation //------------------------------------------------------------------------------ inline -posix_acceptor_impl:: -posix_acceptor_impl(posix_sockets& svc) noexcept +epoll_acceptor_impl:: +epoll_acceptor_impl(epoll_sockets& svc) noexcept : svc_(svc) { } inline void -posix_acceptor_impl:: +epoll_acceptor_impl:: release() { close_socket(); @@ -410,7 +414,7 @@ release() } inline void -posix_acceptor_impl:: +epoll_acceptor_impl:: accept( std::coroutine_handle<> h, capy::any_executor_ref d, @@ -430,7 +434,7 @@ accept( // Callback for creating peer socket when accept completes via epoll op.service_ptr = &svc_; op.create_peer = [](void* svc_ptr, int new_fd) -> io_object::io_object_impl* { - auto& svc = *static_cast(svc_ptr); + auto& svc = *static_cast(svc_ptr); auto& peer_impl = svc.create_impl(); peer_impl.set_socket(new_fd); return &peer_impl; @@ -464,14 +468,14 @@ accept( } inline void -posix_acceptor_impl:: +epoll_acceptor_impl:: cancel() noexcept { acc_.request_cancel(); } inline void -posix_acceptor_impl:: +epoll_acceptor_impl:: close_socket() noexcept { if (fd_ >= 0) @@ -483,24 +487,24 @@ close_socket() noexcept } //------------------------------------------------------------------------------ -// posix_sockets implementation +// epoll_sockets implementation //------------------------------------------------------------------------------ inline -posix_sockets:: -posix_sockets(capy::execution_context& ctx) - : sched_(ctx.use_service()) +epoll_sockets:: +epoll_sockets(capy::execution_context& ctx) + : sched_(ctx.use_service()) { } inline -posix_sockets:: -~posix_sockets() +epoll_sockets:: +~epoll_sockets() { } inline void -posix_sockets:: +epoll_sockets:: shutdown() { std::lock_guard lock(mutex_); @@ -518,11 +522,11 @@ shutdown() } } -inline posix_socket_impl& -posix_sockets:: +inline epoll_socket_impl& +epoll_sockets:: create_impl() { - auto* impl = new posix_socket_impl(*this); + auto* impl = new epoll_socket_impl(*this); { std::lock_guard lock(mutex_); @@ -533,8 +537,8 @@ create_impl() } inline void -posix_sockets:: -destroy_impl(posix_socket_impl& impl) +epoll_sockets:: +destroy_impl(epoll_socket_impl& impl) { { std::lock_guard lock(mutex_); @@ -545,8 +549,8 @@ destroy_impl(posix_socket_impl& impl) } inline system::error_code -posix_sockets:: -open_socket(posix_socket_impl& impl) +epoll_sockets:: +open_socket(epoll_socket_impl& impl) { impl.close_socket(); @@ -558,11 +562,11 @@ open_socket(posix_socket_impl& impl) return {}; } -inline posix_acceptor_impl& -posix_sockets:: +inline epoll_acceptor_impl& +epoll_sockets:: create_acceptor_impl() { - auto* impl = new posix_acceptor_impl(*this); + auto* impl = new epoll_acceptor_impl(*this); { std::lock_guard lock(mutex_); @@ -573,8 +577,8 @@ create_acceptor_impl() } inline void -posix_sockets:: -destroy_acceptor_impl(posix_acceptor_impl& impl) +epoll_sockets:: +destroy_acceptor_impl(epoll_acceptor_impl& impl) { { std::lock_guard lock(mutex_); @@ -585,9 +589,9 @@ destroy_acceptor_impl(posix_acceptor_impl& impl) } inline system::error_code -posix_sockets:: +epoll_sockets:: open_acceptor( - posix_acceptor_impl& impl, + epoll_acceptor_impl& impl, endpoint ep, int backlog) { @@ -620,21 +624,21 @@ open_acceptor( } inline void -posix_sockets:: -post(posix_op* op) +epoll_sockets:: +post(epoll_op* op) { sched_.post(op); } inline void -posix_sockets:: +epoll_sockets:: work_started() noexcept { sched_.work_started(); } inline void -posix_sockets:: +epoll_sockets:: work_finished() noexcept { sched_.work_finished(); @@ -644,4 +648,6 @@ work_finished() noexcept } // namespace corosio } // namespace boost -#endif +#endif // BOOST_COROSIO_BACKEND_EPOLL + +#endif // BOOST_COROSIO_DETAIL_EPOLL_SOCKETS_HPP diff --git a/src/corosio/src/detail/win/completion_key.hpp b/src/corosio/src/detail/iocp/completion_key.hpp similarity index 84% rename from src/corosio/src/detail/win/completion_key.hpp rename to src/corosio/src/detail/iocp/completion_key.hpp index 070420b..22cfab5 100644 --- a/src/corosio/src/detail/win/completion_key.hpp +++ b/src/corosio/src/detail/iocp/completion_key.hpp @@ -7,10 +7,14 @@ // Official repository: https://github.com/cppalliance/corosio // -#ifndef BOOST_COROSIO_DETAIL_WIN_COMPLETION_KEY_HPP -#define BOOST_COROSIO_DETAIL_WIN_COMPLETION_KEY_HPP +#ifndef BOOST_COROSIO_DETAIL_IOCP_COMPLETION_KEY_HPP +#define BOOST_COROSIO_DETAIL_IOCP_COMPLETION_KEY_HPP -#include "src/detail/windows.hpp" +#include "src/detail/config_backend.hpp" + +#if defined(BOOST_COROSIO_BACKEND_IOCP) + +#include "src/detail/iocp/windows.hpp" namespace boost { namespace corosio { @@ -79,4 +83,6 @@ struct completion_key } // namespace corosio } // namespace boost -#endif +#endif // BOOST_COROSIO_BACKEND_IOCP + +#endif // BOOST_COROSIO_DETAIL_IOCP_COMPLETION_KEY_HPP diff --git a/src/corosio/src/detail/win/mutex.hpp b/src/corosio/src/detail/iocp/mutex.hpp similarity index 79% rename from src/corosio/src/detail/win/mutex.hpp rename to src/corosio/src/detail/iocp/mutex.hpp index 2b599c5..09efbb2 100644 --- a/src/corosio/src/detail/win/mutex.hpp +++ b/src/corosio/src/detail/iocp/mutex.hpp @@ -7,12 +7,16 @@ // Official repository: https://github.com/cppalliance/corosio // -#ifndef BOOST_COROSIO_DETAIL_WIN_MUTEX_HPP -#define BOOST_COROSIO_DETAIL_WIN_MUTEX_HPP +#ifndef BOOST_COROSIO_DETAIL_IOCP_MUTEX_HPP +#define BOOST_COROSIO_DETAIL_IOCP_MUTEX_HPP + +#include "src/detail/config_backend.hpp" + +#if defined(BOOST_COROSIO_BACKEND_IOCP) #include -#include "src/detail/windows.hpp" +#include "src/detail/iocp/windows.hpp" namespace boost { namespace corosio { @@ -69,4 +73,6 @@ class win_mutex } // namespace corosio } // namespace boost -#endif +#endif // BOOST_COROSIO_BACKEND_IOCP + +#endif // BOOST_COROSIO_DETAIL_IOCP_MUTEX_HPP diff --git a/src/corosio/src/detail/win/overlapped_op.hpp b/src/corosio/src/detail/iocp/overlapped_op.hpp similarity index 88% rename from src/corosio/src/detail/win/overlapped_op.hpp rename to src/corosio/src/detail/iocp/overlapped_op.hpp index 6fac0d3..8830848 100644 --- a/src/corosio/src/detail/win/overlapped_op.hpp +++ b/src/corosio/src/detail/iocp/overlapped_op.hpp @@ -7,8 +7,12 @@ // Official repository: https://github.com/cppalliance/corosio // -#ifndef BOOST_COROSIO_DETAIL_WIN_OVERLAPPED_OP_HPP -#define BOOST_COROSIO_DETAIL_WIN_OVERLAPPED_OP_HPP +#ifndef BOOST_COROSIO_DETAIL_IOCP_OVERLAPPED_OP_HPP +#define BOOST_COROSIO_DETAIL_IOCP_OVERLAPPED_OP_HPP + +#include "src/detail/config_backend.hpp" + +#if defined(BOOST_COROSIO_BACKEND_IOCP) #include #include @@ -24,7 +28,7 @@ #include #include -#include "src/detail/windows.hpp" +#include "src/detail/iocp/windows.hpp" namespace boost { namespace corosio { @@ -144,4 +148,6 @@ get_overlapped_op(scheduler_op* h) noexcept } // namespace corosio } // namespace boost -#endif +#endif // BOOST_COROSIO_BACKEND_IOCP + +#endif // BOOST_COROSIO_DETAIL_IOCP_OVERLAPPED_OP_HPP diff --git a/src/corosio/src/detail/win/resolver_service.cpp b/src/corosio/src/detail/iocp/resolver_service.cpp similarity index 93% rename from src/corosio/src/detail/win/resolver_service.cpp rename to src/corosio/src/detail/iocp/resolver_service.cpp index d7099b8..60a04d6 100644 --- a/src/corosio/src/detail/win/resolver_service.cpp +++ b/src/corosio/src/detail/iocp/resolver_service.cpp @@ -7,10 +7,12 @@ // Official repository: https://github.com/cppalliance/corosio // -#ifdef _WIN32 +#include "src/detail/config_backend.hpp" -#include "src/detail/win/resolver_service.hpp" -#include "src/detail/win/scheduler.hpp" +#if defined(BOOST_COROSIO_BACKEND_IOCP) + +#include "src/detail/iocp/resolver_service.hpp" +#include "src/detail/iocp/scheduler.hpp" #include "src/detail/endpoint_convert.hpp" #include diff --git a/src/corosio/src/detail/win/resolver_service.hpp b/src/corosio/src/detail/iocp/resolver_service.hpp similarity index 87% rename from src/corosio/src/detail/win/resolver_service.hpp rename to src/corosio/src/detail/iocp/resolver_service.hpp index 812c32f..e953dcd 100644 --- a/src/corosio/src/detail/win/resolver_service.hpp +++ b/src/corosio/src/detail/iocp/resolver_service.hpp @@ -7,12 +7,14 @@ // Official repository: https://github.com/cppalliance/corosio // -#ifndef BOOST_COROSIO_DETAIL_WIN_RESOLVER_SERVICE_HPP -#define BOOST_COROSIO_DETAIL_WIN_RESOLVER_SERVICE_HPP +#ifndef BOOST_COROSIO_DETAIL_IOCP_RESOLVER_SERVICE_HPP +#define BOOST_COROSIO_DETAIL_IOCP_RESOLVER_SERVICE_HPP -#include +#include "src/detail/config_backend.hpp" + +#if defined(BOOST_COROSIO_BACKEND_IOCP) -#ifdef _WIN32 +#include // GetAddrInfoExW requires Windows 8 or later #if !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0602) @@ -26,10 +28,10 @@ #include #include -#include "src/detail/windows.hpp" -#include "src/detail/win/overlapped_op.hpp" -#include "src/detail/win/mutex.hpp" -#include "src/detail/win/wsa_init.hpp" +#include "src/detail/iocp/windows.hpp" +#include "src/detail/iocp/overlapped_op.hpp" +#include "src/detail/iocp/mutex.hpp" +#include "src/detail/iocp/wsa_init.hpp" #include @@ -171,6 +173,6 @@ class win_resolver_service } // namespace corosio } // namespace boost -#endif // _WIN32 +#endif // BOOST_COROSIO_BACKEND_IOCP -#endif +#endif // BOOST_COROSIO_DETAIL_IOCP_RESOLVER_SERVICE_HPP diff --git a/src/corosio/src/detail/win/scheduler.cpp b/src/corosio/src/detail/iocp/scheduler.cpp similarity index 98% rename from src/corosio/src/detail/win/scheduler.cpp rename to src/corosio/src/detail/iocp/scheduler.cpp index d6e84c8..e6aea2f 100644 --- a/src/corosio/src/detail/win/scheduler.cpp +++ b/src/corosio/src/detail/iocp/scheduler.cpp @@ -7,11 +7,13 @@ // Official repository: https://github.com/cppalliance/corosio // -#ifdef _WIN32 +#include "src/detail/config_backend.hpp" -#include "src/detail/win/scheduler.hpp" -#include "src/detail/win/overlapped_op.hpp" -#include "src/detail/win/timers.hpp" +#if defined(BOOST_COROSIO_BACKEND_IOCP) + +#include "src/detail/iocp/scheduler.hpp" +#include "src/detail/iocp/overlapped_op.hpp" +#include "src/detail/iocp/timers.hpp" #include "src/detail/timer_service.hpp" #include diff --git a/src/corosio/src/detail/win/scheduler.hpp b/src/corosio/src/detail/iocp/scheduler.hpp similarity index 87% rename from src/corosio/src/detail/win/scheduler.hpp rename to src/corosio/src/detail/iocp/scheduler.hpp index 37686ee..f6c25c0 100644 --- a/src/corosio/src/detail/win/scheduler.hpp +++ b/src/corosio/src/detail/iocp/scheduler.hpp @@ -7,8 +7,12 @@ // Official repository: https://github.com/cppalliance/corosio // -#ifndef BOOST_COROSIO_DETAIL_WIN_SCHEDULER_HPP -#define BOOST_COROSIO_DETAIL_WIN_SCHEDULER_HPP +#ifndef BOOST_COROSIO_DETAIL_IOCP_SCHEDULER_HPP +#define BOOST_COROSIO_DETAIL_IOCP_SCHEDULER_HPP + +#include "src/detail/config_backend.hpp" + +#if defined(BOOST_COROSIO_BACKEND_IOCP) #include #include @@ -16,14 +20,14 @@ #include #include "src/detail/scheduler_op.hpp" -#include "src/detail/win/completion_key.hpp" -#include "src/detail/win/mutex.hpp" +#include "src/detail/iocp/completion_key.hpp" +#include "src/detail/iocp/mutex.hpp" #include #include #include -#include "src/detail/windows.hpp" +#include "src/detail/iocp/windows.hpp" namespace boost { namespace corosio { @@ -125,4 +129,6 @@ class win_scheduler } // namespace corosio } // namespace boost -#endif +#endif // BOOST_COROSIO_BACKEND_IOCP + +#endif // BOOST_COROSIO_DETAIL_IOCP_SCHEDULER_HPP diff --git a/src/corosio/src/detail/win/sockets.cpp b/src/corosio/src/detail/iocp/sockets.cpp similarity index 99% rename from src/corosio/src/detail/win/sockets.cpp rename to src/corosio/src/detail/iocp/sockets.cpp index 91eb30f..24b6dbf 100644 --- a/src/corosio/src/detail/win/sockets.cpp +++ b/src/corosio/src/detail/iocp/sockets.cpp @@ -7,10 +7,12 @@ // Official repository: https://github.com/cppalliance/corosio // -#ifdef _WIN32 +#include "src/detail/config_backend.hpp" -#include "src/detail/win/sockets.hpp" -#include "src/detail/win/scheduler.hpp" +#if defined(BOOST_COROSIO_BACKEND_IOCP) + +#include "src/detail/iocp/sockets.hpp" +#include "src/detail/iocp/scheduler.hpp" #include "src/detail/endpoint_convert.hpp" namespace boost { diff --git a/src/corosio/src/detail/win/sockets.hpp b/src/corosio/src/detail/iocp/sockets.hpp similarity index 91% rename from src/corosio/src/detail/win/sockets.hpp rename to src/corosio/src/detail/iocp/sockets.hpp index 7cbaa40..223211d 100644 --- a/src/corosio/src/detail/win/sockets.hpp +++ b/src/corosio/src/detail/iocp/sockets.hpp @@ -7,8 +7,12 @@ // Official repository: https://github.com/cppalliance/corosio // -#ifndef BOOST_COROSIO_DETAIL_WIN_SOCKETS_HPP -#define BOOST_COROSIO_DETAIL_WIN_SOCKETS_HPP +#ifndef BOOST_COROSIO_DETAIL_IOCP_SOCKETS_HPP +#define BOOST_COROSIO_DETAIL_IOCP_SOCKETS_HPP + +#include "src/detail/config_backend.hpp" + +#if defined(BOOST_COROSIO_BACKEND_IOCP) #include #include @@ -18,11 +22,11 @@ #include #include -#include "src/detail/windows.hpp" -#include "src/detail/win/completion_key.hpp" -#include "src/detail/win/overlapped_op.hpp" -#include "src/detail/win/mutex.hpp" -#include "src/detail/win/wsa_init.hpp" +#include "src/detail/iocp/windows.hpp" +#include "src/detail/iocp/completion_key.hpp" +#include "src/detail/iocp/overlapped_op.hpp" +#include "src/detail/iocp/mutex.hpp" +#include "src/detail/iocp/wsa_init.hpp" #include #include @@ -311,4 +315,6 @@ class win_sockets } // namespace corosio } // namespace boost -#endif +#endif // BOOST_COROSIO_BACKEND_IOCP + +#endif // BOOST_COROSIO_DETAIL_IOCP_SOCKETS_HPP diff --git a/src/corosio/src/detail/win/timers.cpp b/src/corosio/src/detail/iocp/timers.cpp similarity index 75% rename from src/corosio/src/detail/win/timers.cpp rename to src/corosio/src/detail/iocp/timers.cpp index 70deec1..aecb94d 100644 --- a/src/corosio/src/detail/win/timers.cpp +++ b/src/corosio/src/detail/iocp/timers.cpp @@ -7,11 +7,13 @@ // Official repository: https://github.com/cppalliance/corosio // -#ifdef _WIN32 +#include "src/detail/config_backend.hpp" -#include "src/detail/win/timers.hpp" -#include "src/detail/win/timers_nt.hpp" -#include "src/detail/win/timers_thread.hpp" +#if defined(BOOST_COROSIO_BACKEND_IOCP) + +#include "src/detail/iocp/timers.hpp" +#include "src/detail/iocp/timers_nt.hpp" +#include "src/detail/iocp/timers_thread.hpp" namespace boost { namespace corosio { diff --git a/src/corosio/src/detail/win/timers.hpp b/src/corosio/src/detail/iocp/timers.hpp similarity index 81% rename from src/corosio/src/detail/win/timers.hpp rename to src/corosio/src/detail/iocp/timers.hpp index e42dd23..c26b872 100644 --- a/src/corosio/src/detail/win/timers.hpp +++ b/src/corosio/src/detail/iocp/timers.hpp @@ -7,10 +7,14 @@ // Official repository: https://github.com/cppalliance/corosio // -#ifndef BOOST_COROSIO_DETAIL_WIN_TIMERS_HPP -#define BOOST_COROSIO_DETAIL_WIN_TIMERS_HPP +#ifndef BOOST_COROSIO_DETAIL_IOCP_TIMERS_HPP +#define BOOST_COROSIO_DETAIL_IOCP_TIMERS_HPP -#include "src/detail/win/completion_key.hpp" +#include "src/detail/config_backend.hpp" + +#if defined(BOOST_COROSIO_BACKEND_IOCP) + +#include "src/detail/iocp/completion_key.hpp" #include #include @@ -61,4 +65,6 @@ std::unique_ptr make_win_timers( } // namespace corosio } // namespace boost -#endif +#endif // BOOST_COROSIO_BACKEND_IOCP + +#endif // BOOST_COROSIO_DETAIL_IOCP_TIMERS_HPP diff --git a/src/corosio/src/detail/win/timers_none.hpp b/src/corosio/src/detail/iocp/timers_none.hpp similarity index 67% rename from src/corosio/src/detail/win/timers_none.hpp rename to src/corosio/src/detail/iocp/timers_none.hpp index fd68647..37430a7 100644 --- a/src/corosio/src/detail/win/timers_none.hpp +++ b/src/corosio/src/detail/iocp/timers_none.hpp @@ -7,10 +7,14 @@ // Official repository: https://github.com/cppalliance/corosio // -#ifndef BOOST_COROSIO_DETAIL_WIN_TIMERS_NONE_HPP -#define BOOST_COROSIO_DETAIL_WIN_TIMERS_NONE_HPP +#ifndef BOOST_COROSIO_DETAIL_IOCP_TIMERS_NONE_HPP +#define BOOST_COROSIO_DETAIL_IOCP_TIMERS_NONE_HPP -#include "src/detail/win/timers.hpp" +#include "src/detail/config_backend.hpp" + +#if defined(BOOST_COROSIO_BACKEND_IOCP) + +#include "src/detail/iocp/timers.hpp" namespace boost { namespace corosio { @@ -32,4 +36,6 @@ class win_timers_none final : public win_timers } // namespace corosio } // namespace boost -#endif +#endif // BOOST_COROSIO_BACKEND_IOCP + +#endif // BOOST_COROSIO_DETAIL_IOCP_TIMERS_NONE_HPP diff --git a/src/corosio/src/detail/win/timers_nt.cpp b/src/corosio/src/detail/iocp/timers_nt.cpp similarity index 96% rename from src/corosio/src/detail/win/timers_nt.cpp rename to src/corosio/src/detail/iocp/timers_nt.cpp index c03e2b4..95fd366 100644 --- a/src/corosio/src/detail/win/timers_nt.cpp +++ b/src/corosio/src/detail/iocp/timers_nt.cpp @@ -7,10 +7,12 @@ // Official repository: https://github.com/cppalliance/corosio // -#ifdef _WIN32 +#include "src/detail/config_backend.hpp" -#include "src/detail/win/timers_nt.hpp" -#include "src/detail/windows.hpp" +#if defined(BOOST_COROSIO_BACKEND_IOCP) + +#include "src/detail/iocp/timers_nt.hpp" +#include "src/detail/iocp/windows.hpp" namespace boost { namespace corosio { diff --git a/src/corosio/src/detail/win/timers_nt.hpp b/src/corosio/src/detail/iocp/timers_nt.hpp similarity index 81% rename from src/corosio/src/detail/win/timers_nt.hpp rename to src/corosio/src/detail/iocp/timers_nt.hpp index 3b21002..2c9e6d5 100644 --- a/src/corosio/src/detail/win/timers_nt.hpp +++ b/src/corosio/src/detail/iocp/timers_nt.hpp @@ -7,10 +7,14 @@ // Official repository: https://github.com/cppalliance/corosio // -#ifndef BOOST_COROSIO_DETAIL_WIN_TIMERS_NT_HPP -#define BOOST_COROSIO_DETAIL_WIN_TIMERS_NT_HPP +#ifndef BOOST_COROSIO_DETAIL_IOCP_TIMERS_NT_HPP +#define BOOST_COROSIO_DETAIL_IOCP_TIMERS_NT_HPP -#include "src/detail/win/timers.hpp" +#include "src/detail/config_backend.hpp" + +#if defined(BOOST_COROSIO_BACKEND_IOCP) + +#include "src/detail/iocp/timers.hpp" namespace boost { namespace corosio { @@ -54,4 +58,6 @@ class win_timers_nt final : public win_timers } // namespace corosio } // namespace boost -#endif +#endif // BOOST_COROSIO_BACKEND_IOCP + +#endif // BOOST_COROSIO_DETAIL_IOCP_TIMERS_NT_HPP diff --git a/src/corosio/src/detail/win/timers_thread.cpp b/src/corosio/src/detail/iocp/timers_thread.cpp similarity index 94% rename from src/corosio/src/detail/win/timers_thread.cpp rename to src/corosio/src/detail/iocp/timers_thread.cpp index b2aa770..880ab66 100644 --- a/src/corosio/src/detail/win/timers_thread.cpp +++ b/src/corosio/src/detail/iocp/timers_thread.cpp @@ -7,10 +7,12 @@ // Official repository: https://github.com/cppalliance/corosio // -#ifdef _WIN32 +#include "src/detail/config_backend.hpp" -#include "src/detail/win/timers_thread.hpp" -#include "src/detail/windows.hpp" +#if defined(BOOST_COROSIO_BACKEND_IOCP) + +#include "src/detail/iocp/timers_thread.hpp" +#include "src/detail/iocp/windows.hpp" namespace boost { namespace corosio { diff --git a/src/corosio/src/detail/win/timers_thread.hpp b/src/corosio/src/detail/iocp/timers_thread.hpp similarity index 75% rename from src/corosio/src/detail/win/timers_thread.hpp rename to src/corosio/src/detail/iocp/timers_thread.hpp index 0aa731f..bbab974 100644 --- a/src/corosio/src/detail/win/timers_thread.hpp +++ b/src/corosio/src/detail/iocp/timers_thread.hpp @@ -7,10 +7,14 @@ // Official repository: https://github.com/cppalliance/corosio // -#ifndef BOOST_COROSIO_DETAIL_WIN_TIMERS_THREAD_HPP -#define BOOST_COROSIO_DETAIL_WIN_TIMERS_THREAD_HPP +#ifndef BOOST_COROSIO_DETAIL_IOCP_TIMERS_THREAD_HPP +#define BOOST_COROSIO_DETAIL_IOCP_TIMERS_THREAD_HPP -#include "src/detail/win/timers.hpp" +#include "src/detail/config_backend.hpp" + +#if defined(BOOST_COROSIO_BACKEND_IOCP) + +#include "src/detail/iocp/timers.hpp" #include namespace boost { @@ -43,4 +47,6 @@ class win_timers_thread final : public win_timers } // namespace corosio } // namespace boost -#endif +#endif // BOOST_COROSIO_BACKEND_IOCP + +#endif // BOOST_COROSIO_DETAIL_IOCP_TIMERS_THREAD_HPP diff --git a/src/corosio/src/detail/windows.hpp b/src/corosio/src/detail/iocp/windows.hpp similarity index 69% rename from src/corosio/src/detail/windows.hpp rename to src/corosio/src/detail/iocp/windows.hpp index 6fbc28d..52287a2 100644 --- a/src/corosio/src/detail/windows.hpp +++ b/src/corosio/src/detail/iocp/windows.hpp @@ -7,8 +7,12 @@ // Official repository: https://github.com/cppalliance/corosio // -#ifndef BOOST_COROSIO_DETAIL_WINDOWS_HPP -#define BOOST_COROSIO_DETAIL_WINDOWS_HPP +#ifndef BOOST_COROSIO_DETAIL_IOCP_WINDOWS_HPP +#define BOOST_COROSIO_DETAIL_IOCP_WINDOWS_HPP + +#include "src/detail/config_backend.hpp" + +#if defined(BOOST_COROSIO_BACKEND_IOCP) #if defined(_WIN32_WINNT) && (_WIN32_WINNT < 0x0600) #error "corosio requires Windows Vista or later (_WIN32_WINNT >= 0x0600)" @@ -25,4 +29,6 @@ #include #include -#endif +#endif // BOOST_COROSIO_BACKEND_IOCP + +#endif // BOOST_COROSIO_DETAIL_IOCP_WINDOWS_HPP diff --git a/src/corosio/src/detail/win/wsa_init.cpp b/src/corosio/src/detail/iocp/wsa_init.cpp similarity index 85% rename from src/corosio/src/detail/win/wsa_init.cpp rename to src/corosio/src/detail/iocp/wsa_init.cpp index 6fe29f3..8c4f87f 100644 --- a/src/corosio/src/detail/win/wsa_init.cpp +++ b/src/corosio/src/detail/iocp/wsa_init.cpp @@ -7,9 +7,11 @@ // Official repository: https://github.com/cppalliance/corosio // -#ifdef _WIN32 +#include "src/detail/config_backend.hpp" -#include "src/detail/win/wsa_init.hpp" +#if defined(BOOST_COROSIO_BACKEND_IOCP) + +#include "src/detail/iocp/wsa_init.hpp" #include diff --git a/src/corosio/src/detail/win/wsa_init.hpp b/src/corosio/src/detail/iocp/wsa_init.hpp similarity index 72% rename from src/corosio/src/detail/win/wsa_init.hpp rename to src/corosio/src/detail/iocp/wsa_init.hpp index be7521c..821fae4 100644 --- a/src/corosio/src/detail/win/wsa_init.hpp +++ b/src/corosio/src/detail/iocp/wsa_init.hpp @@ -7,12 +7,16 @@ // Official repository: https://github.com/cppalliance/corosio // -#ifndef BOOST_COROSIO_DETAIL_WIN_WSA_INIT_HPP -#define BOOST_COROSIO_DETAIL_WIN_WSA_INIT_HPP +#ifndef BOOST_COROSIO_DETAIL_IOCP_WSA_INIT_HPP +#define BOOST_COROSIO_DETAIL_IOCP_WSA_INIT_HPP + +#include "src/detail/config_backend.hpp" + +#if defined(BOOST_COROSIO_BACKEND_IOCP) #include -#include "src/detail/windows.hpp" +#include "src/detail/iocp/windows.hpp" namespace boost { namespace corosio { @@ -43,4 +47,6 @@ class win_wsa_init } // namespace corosio } // namespace boost -#endif +#endif // BOOST_COROSIO_BACKEND_IOCP + +#endif // BOOST_COROSIO_DETAIL_IOCP_WSA_INIT_HPP diff --git a/src/corosio/src/detail/posix_signals.cpp b/src/corosio/src/detail/posix/signals.cpp similarity index 93% rename from src/corosio/src/detail/posix_signals.cpp rename to src/corosio/src/detail/posix/signals.cpp index 7e1fc30..59bcb6a 100644 --- a/src/corosio/src/detail/posix_signals.cpp +++ b/src/corosio/src/detail/posix/signals.cpp @@ -1,5 +1,5 @@ // -// Copyright (c) 2025 Vinnie Falco (vinnie dot falco at gmail dot com) +// Copyright (c) 2026 Steve Gerbino // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -7,10 +7,12 @@ // Official repository: https://github.com/cppalliance/corosio // -#ifndef _WIN32 +#include "src/detail/config_backend.hpp" -#include "src/detail/posix_signals.hpp" -#include "src/detail/posix_scheduler.hpp" +#if defined(BOOST_COROSIO_SIGNAL_POSIX) + +#include "src/detail/posix/signals.hpp" +#include "src/detail/epoll/scheduler.hpp" #include #include @@ -175,7 +177,7 @@ cancel() posix_signals:: posix_signals(capy::execution_context& ctx) - : sched_(ctx.use_service()) + : sched_(ctx.use_service()) { for (int i = 0; i < max_signal_number; ++i) { diff --git a/src/corosio/src/detail/posix_signals.hpp b/src/corosio/src/detail/posix/signals.hpp similarity index 93% rename from src/corosio/src/detail/posix_signals.hpp rename to src/corosio/src/detail/posix/signals.hpp index 944479a..93b599f 100644 --- a/src/corosio/src/detail/posix_signals.hpp +++ b/src/corosio/src/detail/posix/signals.hpp @@ -1,5 +1,5 @@ // -// Copyright (c) 2025 Vinnie Falco (vinnie dot falco at gmail dot com) +// Copyright (c) 2026 Steve Gerbino // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -10,6 +10,10 @@ #ifndef BOOST_COROSIO_DETAIL_POSIX_SIGNALS_HPP #define BOOST_COROSIO_DETAIL_POSIX_SIGNALS_HPP +#include "src/detail/config_backend.hpp" + +#if defined(BOOST_COROSIO_SIGNAL_POSIX) + #include #include #include @@ -17,7 +21,6 @@ #include #include -#include "src/detail/posix_op.hpp" #include "src/detail/scheduler_op.hpp" #include @@ -31,7 +34,7 @@ namespace boost { namespace corosio { namespace detail { -class posix_scheduler; +class epoll_scheduler; class posix_signals; class posix_signal_impl; @@ -69,7 +72,7 @@ struct signal_registration //------------------------------------------------------------------------------ -/** Signal set implementation for POSIX using signalfd. +/** Signal set implementation for POSIX. This class contains the state for a single signal_set, including registered signals and pending wait operation. @@ -107,20 +110,18 @@ class posix_signal_impl //------------------------------------------------------------------------------ -/** POSIX signal management service using signalfd. +/** POSIX signal management service. This service owns all signal set implementations and coordinates - their lifecycle. It provides: + their lifecycle using C signal handlers. It provides: - Signal implementation allocation and deallocation - - Signal registration via signalfd + - Signal registration via C signal() - Global signal state management - Graceful shutdown - destroys all implementations when io_context stops @par Thread Safety All public member functions are thread-safe. - - @note Only available on POSIX platforms with signalfd support. */ class posix_signals : public capy::execution_context::service { @@ -209,7 +210,7 @@ class posix_signals : public capy::execution_context::service static void add_service(posix_signals* service); static void remove_service(posix_signals* service); - posix_scheduler& sched_; + epoll_scheduler& sched_; std::mutex mutex_; capy::intrusive_list impl_list_; @@ -228,4 +229,6 @@ class posix_signals : public capy::execution_context::service } // namespace corosio } // namespace boost -#endif +#endif // BOOST_COROSIO_SIGNAL_POSIX + +#endif // BOOST_COROSIO_DETAIL_POSIX_SIGNALS_HPP diff --git a/src/corosio/src/detail/timer_service.cpp b/src/corosio/src/detail/timer_service.cpp index 0a97976..fd7af98 100644 --- a/src/corosio/src/detail/timer_service.cpp +++ b/src/corosio/src/detail/timer_service.cpp @@ -1,474 +1,474 @@ -// -// Copyright (c) 2025 Vinnie Falco (vinnie dot falco at gmail dot com) -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// -// Official repository: https://github.com/cppalliance/corosio -// - -#include "timer_service.hpp" - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -namespace boost { -namespace corosio { -namespace detail { - -class timer_service_impl; - -struct timer_impl - : timer::timer_impl - , capy::intrusive_list::node -{ - using clock_type = std::chrono::steady_clock; - using time_point = clock_type::time_point; - using duration = clock_type::duration; - - timer_service_impl* svc_ = nullptr; - time_point expiry_; - std::size_t heap_index_ = (std::numeric_limits::max)(); - - // Wait operation state - std::coroutine_handle<> h_; - capy::any_executor_ref d_; - system::error_code* ec_out_ = nullptr; - std::stop_token token_; - bool waiting_ = false; - - explicit timer_impl(timer_service_impl& svc) noexcept - : svc_(&svc) - { - } - - void release() override; - - void wait( - std::coroutine_handle<>, - capy::any_executor_ref, - std::stop_token, - system::error_code*) override; -}; - -//------------------------------------------------------------------------------ - -class timer_service_impl : public timer_service -{ -public: - using clock_type = std::chrono::steady_clock; - using time_point = clock_type::time_point; - using key_type = timer_service; - -private: - struct heap_entry - { - time_point time_; - timer_impl* timer_; - }; - - scheduler* sched_ = nullptr; - mutable std::mutex mutex_; - std::vector heap_; - capy::intrusive_list timers_; - capy::intrusive_list free_list_; - callback on_earliest_changed_; - -public: - timer_service_impl(capy::execution_context&, scheduler& sched) - : timer_service() - , sched_(&sched) - { - } - - scheduler& get_scheduler() noexcept { return *sched_; } - - ~timer_service_impl() - { - } - - timer_service_impl(timer_service_impl const&) = delete; - timer_service_impl& operator=(timer_service_impl const&) = delete; - - void set_on_earliest_changed(callback cb) override - { - on_earliest_changed_ = cb; - } - - void shutdown() override - { - while (auto* impl = timers_.pop_front()) - delete impl; - while (auto* impl = free_list_.pop_front()) - delete impl; - } - - timer::timer_impl* create_impl() override - { - std::lock_guard lock(mutex_); - timer_impl* impl; - if (auto* p = free_list_.pop_front()) - { - impl = p; - impl->heap_index_ = (std::numeric_limits::max)(); - } - else - { - impl = new timer_impl(*this); - } - timers_.push_back(impl); - return impl; - } - - void destroy_impl(timer_impl& impl) - { - std::lock_guard lock(mutex_); - remove_timer_impl(impl); - timers_.remove(&impl); - free_list_.push_back(&impl); - } - - void update_timer(timer_impl& impl, time_point new_time) - { - bool notify = false; - bool was_waiting = false; - std::coroutine_handle<> h; - capy::any_executor_ref d; - system::error_code* ec_out = nullptr; - - { - std::lock_guard lock(mutex_); - - // If currently waiting, cancel the pending wait - if (impl.waiting_) - { - was_waiting = true; - impl.waiting_ = false; - h = impl.h_; - d = impl.d_; - ec_out = impl.ec_out_; - } - - if (impl.heap_index_ < heap_.size()) - { - // Already in heap, update position - time_point old_time = heap_[impl.heap_index_].time_; - heap_[impl.heap_index_].time_ = new_time; - - if (new_time < old_time) - up_heap(impl.heap_index_); - else - down_heap(impl.heap_index_); - } - else - { - // Not in heap, add it - impl.heap_index_ = heap_.size(); - heap_.push_back({new_time, &impl}); - up_heap(heap_.size() - 1); - } - - // Notify if this timer is now the earliest - notify = (impl.heap_index_ == 0); - } - - // Resume cancelled waiter outside lock - if (was_waiting) - { - if (ec_out) - *ec_out = make_error_code(capy::error::canceled); - auto resume_h = d.dispatch(h); - // Resume the handle if executor returned it for symmetric transfer - if (resume_h.address() == h.address()) - resume_h.resume(); - // Call on_work_finished AFTER the coroutine resumes - sched_->on_work_finished(); - } - - if (notify) - on_earliest_changed_(); - } - - void remove_timer(timer_impl& impl) - { - std::lock_guard lock(mutex_); - remove_timer_impl(impl); - } - - void cancel_timer(timer_impl& impl) - { - std::coroutine_handle<> h; - capy::any_executor_ref d; - system::error_code* ec_out = nullptr; - bool was_waiting = false; - - { - std::lock_guard lock(mutex_); - remove_timer_impl(impl); - if (impl.waiting_) - { - was_waiting = true; - impl.waiting_ = false; - h = impl.h_; - d = std::move(impl.d_); - ec_out = impl.ec_out_; - } - } - - // Dispatch outside lock - if (was_waiting) - { - if (ec_out) - *ec_out = make_error_code(capy::error::canceled); - auto resume_h = d.dispatch(h); - // Resume the handle if executor returned it for symmetric transfer - if (resume_h.address() == h.address()) - resume_h.resume(); - // Call on_work_finished AFTER the coroutine resumes - sched_->on_work_finished(); - } - } - - bool empty() const noexcept override - { - std::lock_guard lock(mutex_); - return heap_.empty(); - } - - time_point nearest_expiry() const noexcept override - { - std::lock_guard lock(mutex_); - return heap_.empty() ? time_point::max() : heap_[0].time_; - } - - std::size_t process_expired() override - { - // Collect expired timers while holding lock - struct expired_entry - { - std::coroutine_handle<> h; - capy::any_executor_ref d; - system::error_code* ec_out; - }; - std::vector expired; - - { - std::lock_guard lock(mutex_); - auto now = clock_type::now(); - - while (!heap_.empty() && heap_[0].time_ <= now) - { - timer_impl* t = heap_[0].timer_; - remove_timer_impl(*t); - - if (t->waiting_) - { - t->waiting_ = false; - expired.push_back({t->h_, std::move(t->d_), t->ec_out_}); - } - // If not waiting, timer is removed but not dispatched - - // wait() will handle this by checking expiry - } - } - - // Dispatch outside lock - for (auto& e : expired) - { - if (e.ec_out) - *e.ec_out = {}; - auto resume_h = e.d.dispatch(e.h); - // Resume the handle if executor returned it for symmetric transfer - // (executor returns our handle if we should resume, noop if it posted) - if (resume_h.address() == e.h.address()) - resume_h.resume(); - // Call on_work_finished AFTER the coroutine resumes, so it has a - // chance to add new work before we potentially trigger stop() - sched_->on_work_finished(); - } - - return expired.size(); - } - -private: - void remove_timer_impl(timer_impl& impl) - { - std::size_t index = impl.heap_index_; - if (index >= heap_.size()) - return; // Not in heap - - if (index == heap_.size() - 1) - { - // Last element, just pop - impl.heap_index_ = (std::numeric_limits::max)(); - heap_.pop_back(); - } - else - { - // Swap with last and reheapify - swap_heap(index, heap_.size() - 1); - impl.heap_index_ = (std::numeric_limits::max)(); - heap_.pop_back(); - - if (index > 0 && heap_[index].time_ < heap_[(index - 1) / 2].time_) - up_heap(index); - else - down_heap(index); - } - } - - void up_heap(std::size_t index) - { - while (index > 0) - { - std::size_t parent = (index - 1) / 2; - if (!(heap_[index].time_ < heap_[parent].time_)) - break; - swap_heap(index, parent); - index = parent; - } - } - - void down_heap(std::size_t index) - { - std::size_t child = index * 2 + 1; - while (child < heap_.size()) - { - std::size_t min_child = (child + 1 == heap_.size() || - heap_[child].time_ < heap_[child + 1].time_) - ? child : child + 1; - - if (heap_[index].time_ < heap_[min_child].time_) - break; - - swap_heap(index, min_child); - index = min_child; - child = index * 2 + 1; - } - } - - void swap_heap(std::size_t i1, std::size_t i2) - { - heap_entry tmp = heap_[i1]; - heap_[i1] = heap_[i2]; - heap_[i2] = tmp; - heap_[i1].timer_->heap_index_ = i1; - heap_[i2].timer_->heap_index_ = i2; - } -}; - -//------------------------------------------------------------------------------ - -void -timer_impl:: -release() -{ - svc_->destroy_impl(*this); -} - -void -timer_impl:: -wait( - std::coroutine_handle<> h, - capy::any_executor_ref d, - std::stop_token token, - system::error_code* ec) -{ - // Check if timer already expired (not in heap anymore) - bool already_expired = (heap_index_ == (std::numeric_limits::max)()); - - if (already_expired) - { - // Timer already expired - dispatch immediately - if (ec) - *ec = {}; - // Note: no work tracking needed - we dispatch synchronously - auto resume_h = d.dispatch(h); - // Resume the handle if executor returned it for symmetric transfer - if (resume_h.address() == h.address()) - resume_h.resume(); - return; - } - - h_ = h; - d_ = std::move(d); - token_ = std::move(token); - ec_out_ = ec; - waiting_ = true; - svc_->get_scheduler().on_work_started(); -} - -//------------------------------------------------------------------------------ -// -// Extern free functions called from timer.cpp -// -//------------------------------------------------------------------------------ - -timer::timer_impl* -timer_service_create(capy::execution_context& ctx) -{ - auto* svc = ctx.find_service(); - if (!svc) - { - // Timer service not yet created - this happens if io_context - // hasn't been constructed yet, or if the scheduler didn't - // initialize the timer service - throw std::runtime_error("timer_service not found"); - } - return svc->create_impl(); -} - -void -timer_service_destroy(timer::timer_impl& base) noexcept -{ - static_cast(base).release(); -} - -timer::time_point -timer_service_expiry(timer::timer_impl& base) noexcept -{ - return static_cast(base).expiry_; -} - -void -timer_service_expires_at(timer::timer_impl& base, timer::time_point t) -{ - auto& impl = static_cast(base); - impl.expiry_ = t; - impl.svc_->update_timer(impl, t); -} - -void -timer_service_expires_after(timer::timer_impl& base, timer::duration d) -{ - auto& impl = static_cast(base); - impl.expiry_ = timer::clock_type::now() + d; - impl.svc_->update_timer(impl, impl.expiry_); -} - -void -timer_service_cancel(timer::timer_impl& base) noexcept -{ - auto& impl = static_cast(base); - impl.svc_->cancel_timer(impl); -} - -timer_service& -get_timer_service(capy::execution_context& ctx, scheduler& sched) -{ - return ctx.make_service(sched); -} - -} // namespace detail -} // namespace corosio -} // namespace boost +// +// Copyright (c) 2026 Steve Gerbino +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/cppalliance/corosio +// + +#include "src/detail/timer_service.hpp" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace corosio { +namespace detail { + +class timer_service_impl; + +struct timer_impl + : timer::timer_impl + , capy::intrusive_list::node +{ + using clock_type = std::chrono::steady_clock; + using time_point = clock_type::time_point; + using duration = clock_type::duration; + + timer_service_impl* svc_ = nullptr; + time_point expiry_; + std::size_t heap_index_ = (std::numeric_limits::max)(); + + // Wait operation state + std::coroutine_handle<> h_; + capy::any_executor_ref d_; + system::error_code* ec_out_ = nullptr; + std::stop_token token_; + bool waiting_ = false; + + explicit timer_impl(timer_service_impl& svc) noexcept + : svc_(&svc) + { + } + + void release() override; + + void wait( + std::coroutine_handle<>, + capy::any_executor_ref, + std::stop_token, + system::error_code*) override; +}; + +//------------------------------------------------------------------------------ + +class timer_service_impl : public timer_service +{ +public: + using clock_type = std::chrono::steady_clock; + using time_point = clock_type::time_point; + using key_type = timer_service; + +private: + struct heap_entry + { + time_point time_; + timer_impl* timer_; + }; + + scheduler* sched_ = nullptr; + mutable std::mutex mutex_; + std::vector heap_; + capy::intrusive_list timers_; + capy::intrusive_list free_list_; + callback on_earliest_changed_; + +public: + timer_service_impl(capy::execution_context&, scheduler& sched) + : timer_service() + , sched_(&sched) + { + } + + scheduler& get_scheduler() noexcept { return *sched_; } + + ~timer_service_impl() + { + } + + timer_service_impl(timer_service_impl const&) = delete; + timer_service_impl& operator=(timer_service_impl const&) = delete; + + void set_on_earliest_changed(callback cb) override + { + on_earliest_changed_ = cb; + } + + void shutdown() override + { + while (auto* impl = timers_.pop_front()) + delete impl; + while (auto* impl = free_list_.pop_front()) + delete impl; + } + + timer::timer_impl* create_impl() override + { + std::lock_guard lock(mutex_); + timer_impl* impl; + if (auto* p = free_list_.pop_front()) + { + impl = p; + impl->heap_index_ = (std::numeric_limits::max)(); + } + else + { + impl = new timer_impl(*this); + } + timers_.push_back(impl); + return impl; + } + + void destroy_impl(timer_impl& impl) + { + std::lock_guard lock(mutex_); + remove_timer_impl(impl); + timers_.remove(&impl); + free_list_.push_back(&impl); + } + + void update_timer(timer_impl& impl, time_point new_time) + { + bool notify = false; + bool was_waiting = false; + std::coroutine_handle<> h; + capy::any_executor_ref d; + system::error_code* ec_out = nullptr; + + { + std::lock_guard lock(mutex_); + + // If currently waiting, cancel the pending wait + if (impl.waiting_) + { + was_waiting = true; + impl.waiting_ = false; + h = impl.h_; + d = impl.d_; + ec_out = impl.ec_out_; + } + + if (impl.heap_index_ < heap_.size()) + { + // Already in heap, update position + time_point old_time = heap_[impl.heap_index_].time_; + heap_[impl.heap_index_].time_ = new_time; + + if (new_time < old_time) + up_heap(impl.heap_index_); + else + down_heap(impl.heap_index_); + } + else + { + // Not in heap, add it + impl.heap_index_ = heap_.size(); + heap_.push_back({new_time, &impl}); + up_heap(heap_.size() - 1); + } + + // Notify if this timer is now the earliest + notify = (impl.heap_index_ == 0); + } + + // Resume cancelled waiter outside lock + if (was_waiting) + { + if (ec_out) + *ec_out = make_error_code(capy::error::canceled); + auto resume_h = d.dispatch(h); + // Resume the handle if executor returned it for symmetric transfer + if (resume_h.address() == h.address()) + resume_h.resume(); + // Call on_work_finished AFTER the coroutine resumes + sched_->on_work_finished(); + } + + if (notify) + on_earliest_changed_(); + } + + void remove_timer(timer_impl& impl) + { + std::lock_guard lock(mutex_); + remove_timer_impl(impl); + } + + void cancel_timer(timer_impl& impl) + { + std::coroutine_handle<> h; + capy::any_executor_ref d; + system::error_code* ec_out = nullptr; + bool was_waiting = false; + + { + std::lock_guard lock(mutex_); + remove_timer_impl(impl); + if (impl.waiting_) + { + was_waiting = true; + impl.waiting_ = false; + h = impl.h_; + d = std::move(impl.d_); + ec_out = impl.ec_out_; + } + } + + // Dispatch outside lock + if (was_waiting) + { + if (ec_out) + *ec_out = make_error_code(capy::error::canceled); + auto resume_h = d.dispatch(h); + // Resume the handle if executor returned it for symmetric transfer + if (resume_h.address() == h.address()) + resume_h.resume(); + // Call on_work_finished AFTER the coroutine resumes + sched_->on_work_finished(); + } + } + + bool empty() const noexcept override + { + std::lock_guard lock(mutex_); + return heap_.empty(); + } + + time_point nearest_expiry() const noexcept override + { + std::lock_guard lock(mutex_); + return heap_.empty() ? time_point::max() : heap_[0].time_; + } + + std::size_t process_expired() override + { + // Collect expired timers while holding lock + struct expired_entry + { + std::coroutine_handle<> h; + capy::any_executor_ref d; + system::error_code* ec_out; + }; + std::vector expired; + + { + std::lock_guard lock(mutex_); + auto now = clock_type::now(); + + while (!heap_.empty() && heap_[0].time_ <= now) + { + timer_impl* t = heap_[0].timer_; + remove_timer_impl(*t); + + if (t->waiting_) + { + t->waiting_ = false; + expired.push_back({t->h_, std::move(t->d_), t->ec_out_}); + } + // If not waiting, timer is removed but not dispatched - + // wait() will handle this by checking expiry + } + } + + // Dispatch outside lock + for (auto& e : expired) + { + if (e.ec_out) + *e.ec_out = {}; + auto resume_h = e.d.dispatch(e.h); + // Resume the handle if executor returned it for symmetric transfer + // (executor returns our handle if we should resume, noop if it posted) + if (resume_h.address() == e.h.address()) + resume_h.resume(); + // Call on_work_finished AFTER the coroutine resumes, so it has a + // chance to add new work before we potentially trigger stop() + sched_->on_work_finished(); + } + + return expired.size(); + } + +private: + void remove_timer_impl(timer_impl& impl) + { + std::size_t index = impl.heap_index_; + if (index >= heap_.size()) + return; // Not in heap + + if (index == heap_.size() - 1) + { + // Last element, just pop + impl.heap_index_ = (std::numeric_limits::max)(); + heap_.pop_back(); + } + else + { + // Swap with last and reheapify + swap_heap(index, heap_.size() - 1); + impl.heap_index_ = (std::numeric_limits::max)(); + heap_.pop_back(); + + if (index > 0 && heap_[index].time_ < heap_[(index - 1) / 2].time_) + up_heap(index); + else + down_heap(index); + } + } + + void up_heap(std::size_t index) + { + while (index > 0) + { + std::size_t parent = (index - 1) / 2; + if (!(heap_[index].time_ < heap_[parent].time_)) + break; + swap_heap(index, parent); + index = parent; + } + } + + void down_heap(std::size_t index) + { + std::size_t child = index * 2 + 1; + while (child < heap_.size()) + { + std::size_t min_child = (child + 1 == heap_.size() || + heap_[child].time_ < heap_[child + 1].time_) + ? child : child + 1; + + if (heap_[index].time_ < heap_[min_child].time_) + break; + + swap_heap(index, min_child); + index = min_child; + child = index * 2 + 1; + } + } + + void swap_heap(std::size_t i1, std::size_t i2) + { + heap_entry tmp = heap_[i1]; + heap_[i1] = heap_[i2]; + heap_[i2] = tmp; + heap_[i1].timer_->heap_index_ = i1; + heap_[i2].timer_->heap_index_ = i2; + } +}; + +//------------------------------------------------------------------------------ + +void +timer_impl:: +release() +{ + svc_->destroy_impl(*this); +} + +void +timer_impl:: +wait( + std::coroutine_handle<> h, + capy::any_executor_ref d, + std::stop_token token, + system::error_code* ec) +{ + // Check if timer already expired (not in heap anymore) + bool already_expired = (heap_index_ == (std::numeric_limits::max)()); + + if (already_expired) + { + // Timer already expired - dispatch immediately + if (ec) + *ec = {}; + // Note: no work tracking needed - we dispatch synchronously + auto resume_h = d.dispatch(h); + // Resume the handle if executor returned it for symmetric transfer + if (resume_h.address() == h.address()) + resume_h.resume(); + return; + } + + h_ = h; + d_ = std::move(d); + token_ = std::move(token); + ec_out_ = ec; + waiting_ = true; + svc_->get_scheduler().on_work_started(); +} + +//------------------------------------------------------------------------------ +// +// Extern free functions called from timer.cpp +// +//------------------------------------------------------------------------------ + +timer::timer_impl* +timer_service_create(capy::execution_context& ctx) +{ + auto* svc = ctx.find_service(); + if (!svc) + { + // Timer service not yet created - this happens if io_context + // hasn't been constructed yet, or if the scheduler didn't + // initialize the timer service + throw std::runtime_error("timer_service not found"); + } + return svc->create_impl(); +} + +void +timer_service_destroy(timer::timer_impl& base) noexcept +{ + static_cast(base).release(); +} + +timer::time_point +timer_service_expiry(timer::timer_impl& base) noexcept +{ + return static_cast(base).expiry_; +} + +void +timer_service_expires_at(timer::timer_impl& base, timer::time_point t) +{ + auto& impl = static_cast(base); + impl.expiry_ = t; + impl.svc_->update_timer(impl, t); +} + +void +timer_service_expires_after(timer::timer_impl& base, timer::duration d) +{ + auto& impl = static_cast(base); + impl.expiry_ = timer::clock_type::now() + d; + impl.svc_->update_timer(impl, impl.expiry_); +} + +void +timer_service_cancel(timer::timer_impl& base) noexcept +{ + auto& impl = static_cast(base); + impl.svc_->cancel_timer(impl); +} + +timer_service& +get_timer_service(capy::execution_context& ctx, scheduler& sched) +{ + return ctx.make_service(sched); +} + +} // namespace detail +} // namespace corosio +} // namespace boost diff --git a/src/corosio/src/detail/win/signals.cpp b/src/corosio/src/detail/win/signals.cpp index 43f6a82..189f8ba 100644 --- a/src/corosio/src/detail/win/signals.cpp +++ b/src/corosio/src/detail/win/signals.cpp @@ -7,10 +7,12 @@ // Official repository: https://github.com/cppalliance/corosio // -#ifdef _WIN32 +#include "src/detail/config_backend.hpp" + +#if defined(BOOST_COROSIO_SIGNAL_WIN) #include "src/detail/win/signals.hpp" -#include "src/detail/win/scheduler.hpp" +#include "src/detail/iocp/scheduler.hpp" #include #include diff --git a/src/corosio/src/detail/win/signals.hpp b/src/corosio/src/detail/win/signals.hpp index 6c4acde..6803bec 100644 --- a/src/corosio/src/detail/win/signals.hpp +++ b/src/corosio/src/detail/win/signals.hpp @@ -10,6 +10,10 @@ #ifndef BOOST_COROSIO_DETAIL_WIN_SIGNALS_HPP #define BOOST_COROSIO_DETAIL_WIN_SIGNALS_HPP +#include "src/detail/config_backend.hpp" + +#if defined(BOOST_COROSIO_SIGNAL_WIN) + #include #include #include @@ -19,7 +23,7 @@ #include #include -#include "src/detail/win/mutex.hpp" +#include "src/detail/iocp/mutex.hpp" #include "src/detail/scheduler_op.hpp" #include @@ -227,4 +231,6 @@ class win_signals : public capy::execution_context::service } // namespace corosio } // namespace boost -#endif +#endif // BOOST_COROSIO_SIGNAL_WIN + +#endif // BOOST_COROSIO_DETAIL_WIN_SIGNALS_HPP diff --git a/src/corosio/src/io_context.cpp b/src/corosio/src/io_context.cpp index 0ebe046..86e9a84 100644 --- a/src/corosio/src/io_context.cpp +++ b/src/corosio/src/io_context.cpp @@ -9,10 +9,12 @@ #include -#ifdef _WIN32 -#include "src/detail/win/scheduler.hpp" -#else -#include "detail/posix_scheduler.hpp" +#include "src/detail/config_backend.hpp" + +#if defined(BOOST_COROSIO_BACKEND_IOCP) +#include "src/detail/iocp/scheduler.hpp" +#elif defined(BOOST_COROSIO_BACKEND_EPOLL) +#include "src/detail/epoll/scheduler.hpp" #endif #include @@ -20,10 +22,10 @@ namespace boost { namespace corosio { -#ifdef _WIN32 +#if defined(BOOST_COROSIO_BACKEND_IOCP) using scheduler_type = detail::win_scheduler; -#else -using scheduler_type = detail::posix_scheduler; +#elif defined(BOOST_COROSIO_BACKEND_EPOLL) +using scheduler_type = detail::epoll_scheduler; #endif io_context:: diff --git a/src/corosio/src/resolver.cpp b/src/corosio/src/resolver.cpp index cc57db5..3acbfc5 100644 --- a/src/corosio/src/resolver.cpp +++ b/src/corosio/src/resolver.cpp @@ -9,22 +9,24 @@ #include -#ifdef _WIN32 -#include "src/detail/win/resolver_service.hpp" -#else -#include "detail/posix_resolver_service.hpp" +#include "src/detail/config_backend.hpp" + +#if defined(BOOST_COROSIO_BACKEND_IOCP) +#include "src/detail/iocp/resolver_service.hpp" +#elif defined(BOOST_COROSIO_BACKEND_EPOLL) +#include "src/detail/epoll/resolver_service.hpp" #endif namespace boost { namespace corosio { namespace { -#ifdef _WIN32 +#if defined(BOOST_COROSIO_BACKEND_IOCP) using resolver_service = detail::win_resolver_service; using resolver_impl_type = detail::win_resolver_impl; -#else -using resolver_service = detail::posix_resolver_service; -using resolver_impl_type = detail::posix_resolver_impl; +#elif defined(BOOST_COROSIO_BACKEND_EPOLL) +using resolver_service = detail::epoll_resolver_service; +using resolver_impl_type = detail::epoll_resolver_impl; #endif } // namespace diff --git a/src/corosio/src/socket.cpp b/src/corosio/src/socket.cpp index eeff3e1..527a726 100644 --- a/src/corosio/src/socket.cpp +++ b/src/corosio/src/socket.cpp @@ -10,10 +10,12 @@ #include #include -#ifdef _WIN32 -#include "src/detail/win/sockets.hpp" -#else -#include "src/detail/posix_sockets.hpp" +#include "src/detail/config_backend.hpp" + +#if defined(BOOST_COROSIO_BACKEND_IOCP) +#include "src/detail/iocp/sockets.hpp" +#elif defined(BOOST_COROSIO_BACKEND_EPOLL) +#include "src/detail/epoll/sockets.hpp" #endif #include @@ -22,12 +24,12 @@ namespace boost { namespace corosio { namespace { -#ifdef _WIN32 +#if defined(BOOST_COROSIO_BACKEND_IOCP) using socket_service = detail::win_sockets; using socket_impl_type = detail::win_socket_impl; -#else -using socket_service = detail::posix_sockets; -using socket_impl_type = detail::posix_socket_impl; +#elif defined(BOOST_COROSIO_BACKEND_EPOLL) +using socket_service = detail::epoll_sockets; +using socket_impl_type = detail::epoll_socket_impl; #endif } // namespace