LCOV - code coverage report
Current view: top level - corosio/native/detail/reactor - reactor_descriptor_service.hpp (source / functions) Coverage Total Hit Missed
Test: coverage_remapped.info Lines: 100.0 % 47 47
Test Date: 2026-10-08 17:58:26 Functions: 91.7 % 24 22 2

           TLA  Line data    Source code
       1                 : //
       2                 : // Copyright (c) 2026 Michael Vandeberg
       3                 : //
       4                 : // Distributed under the Boost Software License, Version 1.0. (See accompanying
       5                 : // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
       6                 : //
       7                 : // Official repository: https://github.com/cppalliance/corosio
       8                 : //
       9                 : 
      10                 : #ifndef BOOST_COROSIO_NATIVE_DETAIL_REACTOR_REACTOR_DESCRIPTOR_SERVICE_HPP
      11                 : #define BOOST_COROSIO_NATIVE_DETAIL_REACTOR_REACTOR_DESCRIPTOR_SERVICE_HPP
      12                 : 
      13                 : #include <boost/corosio/detail/platform.hpp>
      14                 : 
      15                 : #if BOOST_COROSIO_POSIX
      16                 : 
      17                 : #include <boost/corosio/detail/descriptor_service.hpp>
      18                 : #include <boost/corosio/detail/scheduler_op.hpp>
      19                 : #include <boost/corosio/native/detail/validate_fd.hpp>
      20                 : #include <boost/corosio/native/detail/reactor/reactor_descriptor.hpp>
      21                 : #include <boost/corosio/native/detail/reactor/reactor_service_state.hpp>
      22                 : #include <boost/capy/ex/execution_context.hpp>
      23                 : 
      24                 : #include <memory>
      25                 : #include <mutex>
      26                 : #include <system_error>
      27                 : 
      28                 : /* Reactor-backed descriptor_service.
      29                 : 
      30                 :    assign_descriptor is the validate-before-mutate core the public
      31                 :    assign() contract rests on, modelled on do_assign_fd in
      32                 :    reactor_service_finals.hpp.
      33                 : 
      34                 :    PARALLEL COPY: construct, destroy, close and shutdown here mirror the
      35                 :    same four members of reactor_socket_service.hpp, which this cannot
      36                 :    reuse because it calls close_socket() by name. A fix to the service
      37                 :    lifecycle -- the construct/destroy bookkeeping under state_->mutex_,
      38                 :    or shutdown's deliberate retention of impl_ptrs_ so impls outlive the
      39                 :    scheduler's drain -- belongs in both files.
      40                 : */
      41                 : 
      42                 : namespace boost::corosio::detail {
      43                 : 
      44                 : /** CRTP base for reactor-backed descriptor services.
      45                 : 
      46                 :     @tparam Derived   The named final service type (CRTP self).
      47                 :     @tparam Traits    Backend traits (epoll_traits, kqueue_traits, ...).
      48                 :     @tparam DescFinal The named final descriptor impl type.
      49                 : */
      50                 : template<class Derived, class Traits, class DescFinal>
      51                 : class reactor_descriptor_service : public descriptor_service
      52                 : {
      53                 :     using scheduler_type = typename Traits::scheduler_type;
      54                 :     using state_type     = reactor_service_state<scheduler_type, DescFinal>;
      55                 : 
      56                 :     friend Derived;
      57                 : 
      58                 : protected:
      59                 :     // NOLINTNEXTLINE(bugprone-crtp-constructor-accessibility)
      60 HIT         105 :     explicit reactor_descriptor_service(capy::execution_context& ctx)
      61             105 :         : state_(
      62                 :               std::make_unique<state_type>(
      63             105 :                   ctx.template use_service<scheduler_type>()))
      64                 :     {
      65             105 :     }
      66                 : 
      67                 : public:
      68                 :     /// True when any parked op must wake the reactor.
      69                 :     static constexpr bool needs_park_notification =
      70                 :         Traits::needs_park_notification;
      71                 : 
      72             105 :     ~reactor_descriptor_service() override = default;
      73                 : 
      74                 :     std::error_code assign_descriptor(
      75                 :         posix_stream_descriptor::implementation& impl,
      76                 :         native_handle_type fd) override;
      77                 : 
      78             105 :     void shutdown() override
      79                 :     {
      80             105 :         std::lock_guard lock(state_->mutex_);
      81                 : 
      82             119 :         while (auto* impl = state_->impl_list_.pop_front())
      83              14 :             impl->close_descriptor();
      84                 : 
      85                 :         // Don't clear impl_ptrs_ here: the scheduler shuts down after us
      86                 :         // and drains completed_ops_, so every impl must outlive that.
      87             105 :     }
      88                 : 
      89             121 :     io_object::implementation* construct() override
      90                 :     {
      91             121 :         auto impl = std::make_shared<DescFinal>(static_cast<Derived&>(*this));
      92             121 :         auto* raw = impl.get();
      93                 : 
      94                 :         {
      95             121 :             std::lock_guard lock(state_->mutex_);
      96             121 :             state_->impl_ptrs_.emplace(raw, std::move(impl));
      97             121 :             state_->impl_list_.push_back(raw);
      98             121 :         }
      99                 : 
     100             121 :         return raw;
     101             121 :     }
     102                 : 
     103             107 :     void destroy(io_object::implementation* impl) override
     104                 :     {
     105             107 :         auto* typed = static_cast<DescFinal*>(impl);
     106             107 :         typed->close_descriptor();
     107             107 :         std::lock_guard lock(state_->mutex_);
     108             107 :         state_->impl_list_.remove(typed);
     109             107 :         state_->impl_ptrs_.erase(typed);
     110             107 :     }
     111                 : 
     112             195 :     void close(io_object::handle& h) override
     113                 :     {
     114             195 :         static_cast<DescFinal*>(h.get())->close_descriptor();
     115             195 :     }
     116                 : 
     117             296 :     scheduler_type& scheduler() const noexcept
     118                 :     {
     119             296 :         return state_->sched_;
     120                 :     }
     121                 : 
     122              71 :     void post(scheduler_op* op)
     123                 :     {
     124              71 :         state_->sched_.post(op);
     125              71 :     }
     126                 : 
     127              55 :     void work_started() noexcept
     128                 :     {
     129              55 :         state_->sched_.work_started();
     130              55 :     }
     131                 : 
     132              30 :     void work_finished() noexcept
     133                 :     {
     134              30 :         state_->sched_.work_finished();
     135              30 :     }
     136                 : 
     137                 : protected:
     138                 :     std::unique_ptr<state_type> state_;
     139                 : 
     140                 : private:
     141                 :     reactor_descriptor_service(reactor_descriptor_service const&) = delete;
     142                 :     reactor_descriptor_service&
     143                 :     operator=(reactor_descriptor_service const&) = delete;
     144                 : };
     145                 : 
     146                 : template<class Derived, class Traits, class DescFinal>
     147                 : std::error_code
     148             111 : reactor_descriptor_service<Derived, Traits, DescFinal>::assign_descriptor(
     149                 :     posix_stream_descriptor::implementation& impl_base, native_handle_type fd)
     150                 : {
     151             111 :     auto* impl = static_cast<DescFinal*>(&impl_base);
     152                 : 
     153                 :     // The public assign() guarantees the object is closed.
     154             111 :     if (auto ec = validate_descriptor_fd(fd))
     155               4 :         return ec;
     156                 : 
     157                 :     if constexpr (requires { Traits::max_descriptor; })
     158                 :     {
     159              53 :         if (fd >= Traits::max_descriptor)
     160               1 :             return make_err(EMFILE);
     161                 :     }
     162                 : 
     163             106 :     return impl->init_and_register(fd);
     164                 : }
     165                 : 
     166                 : } // namespace boost::corosio::detail
     167                 : 
     168                 : #endif // BOOST_COROSIO_POSIX
     169                 : 
     170                 : #endif // BOOST_COROSIO_NATIVE_DETAIL_REACTOR_REACTOR_DESCRIPTOR_SERVICE_HPP
        

Generated by: LCOV version 2.3