From 0908dd7144296099ec980deaae06441c1abcd32f Mon Sep 17 00:00:00 2001 From: Vinnie Falco Date: Tue, 20 Jan 2026 22:05:47 -0800 Subject: [PATCH] intrusive is an implementation detail --- .../src/detail/epoll/resolver_service.hpp | 6 +- src/corosio/src/detail/epoll/sockets.hpp | 10 +- src/corosio/src/detail/intrusive.hpp | 230 ++++++++++++++++++ .../src/detail/iocp/resolver_service.hpp | 6 +- src/corosio/src/detail/iocp/sockets.hpp | 18 +- src/corosio/src/detail/posix/signals.hpp | 6 +- src/corosio/src/detail/scheduler_op.hpp | 6 +- src/corosio/src/detail/timer_service.cpp | 8 +- src/corosio/src/detail/win/signals.hpp | 7 +- src/corosio/src/test/mocket.cpp | 6 +- 10 files changed, 266 insertions(+), 37 deletions(-) create mode 100644 src/corosio/src/detail/intrusive.hpp diff --git a/src/corosio/src/detail/epoll/resolver_service.hpp b/src/corosio/src/detail/epoll/resolver_service.hpp index 0f09712..e76b2d5 100644 --- a/src/corosio/src/detail/epoll/resolver_service.hpp +++ b/src/corosio/src/detail/epoll/resolver_service.hpp @@ -20,7 +20,7 @@ #include #include #include -#include +#include "src/detail/intrusive.hpp" #include #include @@ -44,7 +44,7 @@ class epoll_resolver_impl; */ class epoll_resolver_impl : public resolver::resolver_impl - , public capy::intrusive_list::node + , public intrusive_list::node { friend class epoll_resolver_service; @@ -137,7 +137,7 @@ class epoll_resolver_service private: std::mutex mutex_; - capy::intrusive_list resolver_list_; + intrusive_list resolver_list_; }; //------------------------------------------------------------------------------ diff --git a/src/corosio/src/detail/epoll/sockets.hpp b/src/corosio/src/detail/epoll/sockets.hpp index 656af39..1abe566 100644 --- a/src/corosio/src/detail/epoll/sockets.hpp +++ b/src/corosio/src/detail/epoll/sockets.hpp @@ -20,7 +20,7 @@ #include #include #include -#include +#include "src/detail/intrusive.hpp" #include "src/detail/epoll/op.hpp" #include "src/detail/epoll/scheduler.hpp" @@ -105,7 +105,7 @@ class epoll_acceptor_impl; class epoll_socket_impl : public socket::socket_impl , public std::enable_shared_from_this - , public capy::intrusive_list::node + , public intrusive_list::node { friend class epoll_sockets; @@ -173,7 +173,7 @@ class epoll_socket_impl class epoll_acceptor_impl : public acceptor::acceptor_impl , public std::enable_shared_from_this - , public capy::intrusive_list::node + , public intrusive_list::node { friend class epoll_sockets; @@ -239,8 +239,8 @@ class epoll_sockets // Dual tracking: intrusive_list for fast shutdown iteration, // vectors for shared_ptr ownership. See "Impl Lifetime" in file header. - capy::intrusive_list socket_list_; - capy::intrusive_list acceptor_list_; + intrusive_list socket_list_; + intrusive_list acceptor_list_; std::vector> socket_ptrs_; std::vector> acceptor_ptrs_; }; diff --git a/src/corosio/src/detail/intrusive.hpp b/src/corosio/src/detail/intrusive.hpp new file mode 100644 index 0000000..e195e3b --- /dev/null +++ b/src/corosio/src/detail/intrusive.hpp @@ -0,0 +1,230 @@ +// +// 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 +// + +#ifndef BOOST_COROSIO_DETAIL_INTRUSIVE_HPP +#define BOOST_COROSIO_DETAIL_INTRUSIVE_HPP + +namespace boost { +namespace corosio { +namespace detail { + +//------------------------------------------------ + +/** An intrusive doubly linked list. + + This container provides O(1) push and pop operations for + elements that derive from @ref node. Elements are not + copied or moved; they are linked directly into the list. + + @tparam T The element type. Must derive from `intrusive_list::node`. +*/ +template +class intrusive_list +{ +public: + /** Base class for list elements. + + Derive from this class to make a type usable with + @ref intrusive_list. The `next_` and `prev_` pointers + are private and accessible only to the list. + */ + class node + { + friend class intrusive_list; + + private: + T* next_; + T* prev_; + }; + +private: + T* head_ = nullptr; + T* tail_ = nullptr; + +public: + intrusive_list() = default; + + intrusive_list(intrusive_list&& other) noexcept + : head_(other.head_) + , tail_(other.tail_) + { + other.head_ = nullptr; + other.tail_ = nullptr; + } + + intrusive_list(intrusive_list const&) = delete; + intrusive_list& operator=(intrusive_list const&) = delete; + intrusive_list& operator=(intrusive_list&&) = delete; + + bool + empty() const noexcept + { + return head_ == nullptr; + } + + void + push_back(T* w) noexcept + { + w->next_ = nullptr; + w->prev_ = tail_; + if(tail_) + tail_->next_ = w; + else + head_ = w; + tail_ = w; + } + + void + splice_back(intrusive_list& other) noexcept + { + if(other.empty()) + return; + if(tail_) + { + tail_->next_ = other.head_; + other.head_->prev_ = tail_; + tail_ = other.tail_; + } + else + { + head_ = other.head_; + tail_ = other.tail_; + } + other.head_ = nullptr; + other.tail_ = nullptr; + } + + T* + pop_front() noexcept + { + if(!head_) + return nullptr; + T* w = head_; + head_ = head_->next_; + if(head_) + head_->prev_ = nullptr; + else + tail_ = nullptr; + return w; + } + + void + remove(T* w) noexcept + { + if(w->prev_) + w->prev_->next_ = w->next_; + else + head_ = w->next_; + if(w->next_) + w->next_->prev_ = w->prev_; + else + tail_ = w->prev_; + } +}; + +//------------------------------------------------ + +/** An intrusive singly linked FIFO queue. + + This container provides O(1) push and pop operations for + elements that derive from @ref node. Elements are not + copied or moved; they are linked directly into the queue. + + Unlike @ref intrusive_list, this uses only a single `next_` + pointer per node, saving memory at the cost of not supporting + O(1) removal of arbitrary elements. + + @tparam T The element type. Must derive from `intrusive_queue::node`. +*/ +template +class intrusive_queue +{ +public: + /** Base class for queue elements. + + Derive from this class to make a type usable with + @ref intrusive_queue. The `next_` pointer is private + and accessible only to the queue. + */ + class node + { + friend class intrusive_queue; + + private: + T* next_; + }; + +private: + T* head_ = nullptr; + T* tail_ = nullptr; + +public: + intrusive_queue() = default; + + intrusive_queue(intrusive_queue&& other) noexcept + : head_(other.head_) + , tail_(other.tail_) + { + other.head_ = nullptr; + other.tail_ = nullptr; + } + + intrusive_queue(intrusive_queue const&) = delete; + intrusive_queue& operator=(intrusive_queue const&) = delete; + intrusive_queue& operator=(intrusive_queue&&) = delete; + + bool + empty() const noexcept + { + return head_ == nullptr; + } + + void + push(T* w) noexcept + { + w->next_ = nullptr; + if(tail_) + tail_->next_ = w; + else + head_ = w; + tail_ = w; + } + + void + splice(intrusive_queue& other) noexcept + { + if(other.empty()) + return; + if(tail_) + tail_->next_ = other.head_; + else + head_ = other.head_; + tail_ = other.tail_; + other.head_ = nullptr; + other.tail_ = nullptr; + } + + T* + pop() noexcept + { + if(!head_) + return nullptr; + T* w = head_; + head_ = head_->next_; + if(!head_) + tail_ = nullptr; + return w; + } +}; + +} // detail +} // corosio +} // boost + +#endif diff --git a/src/corosio/src/detail/iocp/resolver_service.hpp b/src/corosio/src/detail/iocp/resolver_service.hpp index 141a258..4a846e5 100644 --- a/src/corosio/src/detail/iocp/resolver_service.hpp +++ b/src/corosio/src/detail/iocp/resolver_service.hpp @@ -26,7 +26,7 @@ #include #include #include -#include +#include "src/detail/intrusive.hpp" #include "src/detail/iocp/windows.hpp" #include "src/detail/iocp/overlapped_op.hpp" @@ -82,7 +82,7 @@ struct resolve_op : overlapped_op */ class win_resolver_impl : public resolver::resolver_impl - , public capy::intrusive_list::node + , public intrusive_list::node { friend class win_resolver_service; friend struct resolve_op; @@ -166,7 +166,7 @@ class win_resolver_service private: win_scheduler& sched_; win_mutex mutex_; - capy::intrusive_list resolver_list_; + intrusive_list resolver_list_; }; } // namespace detail diff --git a/src/corosio/src/detail/iocp/sockets.hpp b/src/corosio/src/detail/iocp/sockets.hpp index 714a696..ac55e5b 100644 --- a/src/corosio/src/detail/iocp/sockets.hpp +++ b/src/corosio/src/detail/iocp/sockets.hpp @@ -20,7 +20,7 @@ #include #include #include -#include +#include "src/detail/intrusive.hpp" #include "src/detail/iocp/windows.hpp" #include "src/detail/iocp/completion_key.hpp" @@ -119,7 +119,7 @@ struct accept_op : overlapped_op @note Internal implementation detail. Users interact with socket class. */ class win_socket_impl_internal - : public capy::intrusive_list::node + : public intrusive_list::node , public std::enable_shared_from_this { friend class win_sockets; @@ -181,7 +181,7 @@ class win_socket_impl_internal */ class win_socket_impl : public socket::socket_impl - , public capy::intrusive_list::node + , public intrusive_list::node { std::shared_ptr internal_; @@ -254,7 +254,7 @@ class win_socket_impl @note Internal implementation detail. Users interact with acceptor class. */ class win_acceptor_impl_internal - : public capy::intrusive_list::node + : public intrusive_list::node , public std::enable_shared_from_this { friend class win_sockets; @@ -296,7 +296,7 @@ class win_acceptor_impl_internal */ class win_acceptor_impl : public acceptor::acceptor_impl - , public capy::intrusive_list::node + , public intrusive_list::node { std::shared_ptr internal_; @@ -450,10 +450,10 @@ class win_sockets win_scheduler& sched_; overlapped_key overlapped_key_; win_mutex mutex_; - capy::intrusive_list socket_list_; - capy::intrusive_list acceptor_list_; - capy::intrusive_list socket_wrapper_list_; - capy::intrusive_list acceptor_wrapper_list_; + intrusive_list socket_list_; + intrusive_list acceptor_list_; + intrusive_list socket_wrapper_list_; + intrusive_list acceptor_wrapper_list_; void* iocp_; LPFN_CONNECTEX connect_ex_ = nullptr; LPFN_ACCEPTEX accept_ex_ = nullptr; diff --git a/src/corosio/src/detail/posix/signals.hpp b/src/corosio/src/detail/posix/signals.hpp index 3e60f7f..eb13553 100644 --- a/src/corosio/src/detail/posix/signals.hpp +++ b/src/corosio/src/detail/posix/signals.hpp @@ -19,7 +19,7 @@ #include #include #include -#include +#include "src/detail/intrusive.hpp" #include #include @@ -83,7 +83,7 @@ struct signal_registration */ class posix_signal_impl : public signal_set::signal_set_impl - , public capy::intrusive_list::node + , public intrusive_list::node { friend class posix_signals; @@ -214,7 +214,7 @@ class posix_signals : public capy::execution_context::service epoll_scheduler& sched_; std::mutex mutex_; - capy::intrusive_list impl_list_; + intrusive_list impl_list_; // Per-signal registration table signal_registration* registrations_[max_signal_number]; diff --git a/src/corosio/src/detail/scheduler_op.hpp b/src/corosio/src/detail/scheduler_op.hpp index 801a409..25d4654 100644 --- a/src/corosio/src/detail/scheduler_op.hpp +++ b/src/corosio/src/detail/scheduler_op.hpp @@ -11,7 +11,7 @@ #define BOOST_COROSIO_DETAIL_SCHEDULER_OP_HPP #include -#include +#include "src/detail/intrusive.hpp" namespace boost { namespace corosio { @@ -83,7 +83,7 @@ namespace detail { @see scheduler_op_queue */ -class scheduler_op : public capy::intrusive_queue::node +class scheduler_op : public intrusive_queue::node { public: virtual void operator()() = 0; @@ -113,7 +113,7 @@ class scheduler_op : public capy::intrusive_queue::node //------------------------------------------------------------------------------ -using op_queue = capy::intrusive_queue; +using op_queue = intrusive_queue; //------------------------------------------------------------------------------ diff --git a/src/corosio/src/detail/timer_service.cpp b/src/corosio/src/detail/timer_service.cpp index fd7af98..2f74201 100644 --- a/src/corosio/src/detail/timer_service.cpp +++ b/src/corosio/src/detail/timer_service.cpp @@ -10,7 +10,7 @@ #include "src/detail/timer_service.hpp" #include -#include +#include "src/detail/intrusive.hpp" #include #include #include @@ -31,7 +31,7 @@ class timer_service_impl; struct timer_impl : timer::timer_impl - , capy::intrusive_list::node + , intrusive_list::node { using clock_type = std::chrono::steady_clock; using time_point = clock_type::time_point; @@ -81,8 +81,8 @@ class timer_service_impl : public timer_service scheduler* sched_ = nullptr; mutable std::mutex mutex_; std::vector heap_; - capy::intrusive_list timers_; - capy::intrusive_list free_list_; + intrusive_list timers_; + intrusive_list free_list_; callback on_earliest_changed_; public: diff --git a/src/corosio/src/detail/win/signals.hpp b/src/corosio/src/detail/win/signals.hpp index e163982..7732ab3 100644 --- a/src/corosio/src/detail/win/signals.hpp +++ b/src/corosio/src/detail/win/signals.hpp @@ -19,8 +19,7 @@ #include #include #include -#include -#include +#include "src/detail/intrusive.hpp" #include #include @@ -85,7 +84,7 @@ struct signal_registration */ class win_signal_impl : public signal_set::signal_set_impl - , public capy::intrusive_list::node + , public intrusive_list::node { friend class win_signals; @@ -218,7 +217,7 @@ class win_signals : public capy::execution_context::service win_scheduler& sched_; win_mutex mutex_; - capy::intrusive_list impl_list_; + intrusive_list impl_list_; // Per-signal registration table for this service signal_registration* registrations_[max_signal_number]; diff --git a/src/corosio/src/test/mocket.cpp b/src/corosio/src/test/mocket.cpp index 979db59..9304602 100644 --- a/src/corosio/src/test/mocket.cpp +++ b/src/corosio/src/test/mocket.cpp @@ -11,7 +11,7 @@ #include #include #include -#include +#include "src/detail/intrusive.hpp" #include #include #include @@ -41,7 +41,7 @@ class mocket_service; class mocket_impl : public io_stream::io_stream_impl - , public capy::intrusive_list::node + , public detail::intrusive_list::node { mocket_service& svc_; capy::test::fuse& fuse_; @@ -122,7 +122,7 @@ class mocket_service : public capy::execution_context::service { capy::execution_context& ctx_; - capy::intrusive_list impls_; + detail::intrusive_list impls_; public: explicit mocket_service(capy::execution_context& ctx)