LCOV - code coverage report
Current view: top level - corosio/native/detail/posix - posix_resolver_service.hpp (source / functions) Coverage Total Hit Missed
Test: coverage_remapped.info Lines: 95.2 % 290 276 14
Test Date: 2026-06-02 22:30:31 Functions: 93.8 % 32 30 2

           TLA  Line data    Source code
       1                 : //
       2                 : // Copyright (c) 2026 Steve Gerbino
       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_POSIX_POSIX_RESOLVER_SERVICE_HPP
      11                 : #define BOOST_COROSIO_NATIVE_DETAIL_POSIX_POSIX_RESOLVER_SERVICE_HPP
      12                 : 
      13                 : #include <boost/corosio/detail/platform.hpp>
      14                 : 
      15                 : #if BOOST_COROSIO_POSIX
      16                 : 
      17                 : #include <boost/corosio/native/detail/posix/posix_resolver.hpp>
      18                 : #include <boost/corosio/native/detail/reactor/reactor_scheduler.hpp>
      19                 : #include <boost/corosio/detail/thread_pool.hpp>
      20                 : 
      21                 : #include <unordered_map>
      22                 : 
      23                 : namespace boost::corosio::detail {
      24                 : 
      25                 : /** Resolver service for POSIX backends.
      26                 : 
      27                 :     Owns all posix_resolver instances. Thread lifecycle is managed
      28                 :     by the thread_pool service.
      29                 : */
      30                 : class BOOST_COROSIO_DECL posix_resolver_service final
      31                 :     : public capy::execution_context::service
      32                 :     , public io_object::io_service
      33                 : {
      34                 : public:
      35                 :     using key_type = posix_resolver_service;
      36                 : 
      37 HIT        1021 :     posix_resolver_service(capy::execution_context& ctx, scheduler& sched)
      38            2042 :         : sched_(&sched)
      39            1021 :         , pool_(ctx.use_service<thread_pool>())
      40                 :     {
      41            1021 :     }
      42                 : 
      43            2042 :     ~posix_resolver_service() override = default;
      44                 : 
      45                 :     posix_resolver_service(posix_resolver_service const&)            = delete;
      46                 :     posix_resolver_service& operator=(posix_resolver_service const&) = delete;
      47                 : 
      48                 :     io_object::implementation* construct() override;
      49                 : 
      50              42 :     void destroy(io_object::implementation* p) override
      51                 :     {
      52              42 :         auto& impl = static_cast<posix_resolver&>(*p);
      53              42 :         impl.cancel();
      54              42 :         destroy_impl(impl);
      55              42 :     }
      56                 : 
      57                 :     void shutdown() override;
      58                 :     void destroy_impl(posix_resolver& impl);
      59                 : 
      60                 :     void post(scheduler_op* op);
      61                 :     void work_started() noexcept;
      62                 :     void work_finished() noexcept;
      63                 : 
      64                 :     /** Return the resolver thread pool. */
      65              33 :     thread_pool& pool() noexcept
      66                 :     {
      67              33 :         return pool_;
      68                 :     }
      69                 : 
      70                 :     /** Return true if single-threaded mode is active. */
      71              35 :     bool single_threaded() const noexcept
      72                 :     {
      73              35 :         return sched_->is_single_threaded();
      74                 :     }
      75                 : 
      76                 : private:
      77                 :     scheduler* sched_;
      78                 :     thread_pool& pool_;
      79                 :     std::mutex mutex_;
      80                 :     intrusive_list<posix_resolver> resolver_list_;
      81                 :     std::unordered_map<posix_resolver*, std::shared_ptr<posix_resolver>>
      82                 :         resolver_ptrs_;
      83                 : };
      84                 : 
      85                 : /** Get or create the resolver service for the given context.
      86                 : 
      87                 :     This function is called by the concrete scheduler during initialization
      88                 :     to create the resolver service with a reference to itself.
      89                 : 
      90                 :     @param ctx Reference to the owning execution_context.
      91                 :     @param sched Reference to the scheduler for posting completions.
      92                 :     @return Reference to the resolver service.
      93                 : */
      94                 : posix_resolver_service&
      95                 : get_resolver_service(capy::execution_context& ctx, scheduler& sched);
      96                 : 
      97                 : // ---------------------------------------------------------------------------
      98                 : // Inline implementation
      99                 : // ---------------------------------------------------------------------------
     100                 : 
     101                 : // posix_resolver_detail helpers
     102                 : 
     103                 : inline int
     104              21 : posix_resolver_detail::flags_to_hints(resolve_flags flags)
     105                 : {
     106              21 :     int hints = 0;
     107                 : 
     108              21 :     if ((flags & resolve_flags::passive) != resolve_flags::none)
     109               1 :         hints |= AI_PASSIVE;
     110              21 :     if ((flags & resolve_flags::numeric_host) != resolve_flags::none)
     111              12 :         hints |= AI_NUMERICHOST;
     112              21 :     if ((flags & resolve_flags::numeric_service) != resolve_flags::none)
     113               9 :         hints |= AI_NUMERICSERV;
     114              21 :     if ((flags & resolve_flags::address_configured) != resolve_flags::none)
     115               1 :         hints |= AI_ADDRCONFIG;
     116              21 :     if ((flags & resolve_flags::v4_mapped) != resolve_flags::none)
     117               1 :         hints |= AI_V4MAPPED;
     118              21 :     if ((flags & resolve_flags::all_matching) != resolve_flags::none)
     119               1 :         hints |= AI_ALL;
     120                 : 
     121              21 :     return hints;
     122                 : }
     123                 : 
     124                 : inline int
     125              12 : posix_resolver_detail::flags_to_ni_flags(reverse_flags flags)
     126                 : {
     127              12 :     int ni_flags = 0;
     128                 : 
     129              12 :     if ((flags & reverse_flags::numeric_host) != reverse_flags::none)
     130               6 :         ni_flags |= NI_NUMERICHOST;
     131              12 :     if ((flags & reverse_flags::numeric_service) != reverse_flags::none)
     132               6 :         ni_flags |= NI_NUMERICSERV;
     133              12 :     if ((flags & reverse_flags::name_required) != reverse_flags::none)
     134               1 :         ni_flags |= NI_NAMEREQD;
     135              12 :     if ((flags & reverse_flags::datagram_service) != reverse_flags::none)
     136               1 :         ni_flags |= NI_DGRAM;
     137                 : 
     138              12 :     return ni_flags;
     139                 : }
     140                 : 
     141                 : inline resolver_results
     142              16 : posix_resolver_detail::convert_results(
     143                 :     struct addrinfo* ai, std::string_view host, std::string_view service)
     144                 : {
     145              16 :     std::vector<resolver_entry> entries;
     146              16 :     entries.reserve(4); // Most lookups return 1-4 addresses
     147                 : 
     148              32 :     for (auto* p = ai; p != nullptr; p = p->ai_next)
     149                 :     {
     150              16 :         if (p->ai_family == AF_INET)
     151                 :         {
     152              14 :             auto* addr = reinterpret_cast<sockaddr_in*>(p->ai_addr);
     153              14 :             auto ep    = from_sockaddr_in(*addr);
     154              14 :             entries.emplace_back(ep, host, service);
     155                 :         }
     156               2 :         else if (p->ai_family == AF_INET6)
     157                 :         {
     158               2 :             auto* addr = reinterpret_cast<sockaddr_in6*>(p->ai_addr);
     159               2 :             auto ep    = from_sockaddr_in6(*addr);
     160               2 :             entries.emplace_back(ep, host, service);
     161                 :         }
     162                 :     }
     163                 : 
     164              32 :     return resolver_results(std::move(entries));
     165              16 : }
     166                 : 
     167                 : inline std::error_code
     168              14 : posix_resolver_detail::make_gai_error(int gai_err)
     169                 : {
     170                 :     // Map GAI errors to appropriate generic error codes
     171              14 :     switch (gai_err)
     172                 :     {
     173               1 :     case EAI_AGAIN:
     174                 :         // Temporary failure - try again later
     175               1 :         return std::error_code(
     176                 :             static_cast<int>(std::errc::resource_unavailable_try_again),
     177               1 :             std::generic_category());
     178                 : 
     179               1 :     case EAI_BADFLAGS:
     180                 :         // Invalid flags
     181               1 :         return std::error_code(
     182                 :             static_cast<int>(std::errc::invalid_argument),
     183               1 :             std::generic_category());
     184                 : 
     185               1 :     case EAI_FAIL:
     186                 :         // Non-recoverable failure
     187               1 :         return std::error_code(
     188               1 :             static_cast<int>(std::errc::io_error), std::generic_category());
     189                 : 
     190               1 :     case EAI_FAMILY:
     191                 :         // Address family not supported
     192               1 :         return std::error_code(
     193                 :             static_cast<int>(std::errc::address_family_not_supported),
     194               1 :             std::generic_category());
     195                 : 
     196               1 :     case EAI_MEMORY:
     197                 :         // Memory allocation failure
     198               1 :         return std::error_code(
     199                 :             static_cast<int>(std::errc::not_enough_memory),
     200               1 :             std::generic_category());
     201                 : 
     202               5 :     case EAI_NONAME:
     203                 :         // Host or service not found
     204               5 :         return std::error_code(
     205                 :             static_cast<int>(std::errc::no_such_device_or_address),
     206               5 :             std::generic_category());
     207                 : 
     208               1 :     case EAI_SERVICE:
     209                 :         // Service not supported for socket type
     210               1 :         return std::error_code(
     211                 :             static_cast<int>(std::errc::invalid_argument),
     212               1 :             std::generic_category());
     213                 : 
     214               1 :     case EAI_SOCKTYPE:
     215                 :         // Socket type not supported
     216               1 :         return std::error_code(
     217                 :             static_cast<int>(std::errc::not_supported),
     218               1 :             std::generic_category());
     219                 : 
     220               1 :     case EAI_SYSTEM:
     221                 :         // System error - use errno
     222               1 :         return std::error_code(errno, std::generic_category());
     223                 : 
     224               1 :     default:
     225                 :         // Unknown error
     226               1 :         return std::error_code(
     227               1 :             static_cast<int>(std::errc::io_error), std::generic_category());
     228                 :     }
     229                 : }
     230                 : 
     231                 : // posix_resolver
     232                 : 
     233              42 : inline posix_resolver::posix_resolver(posix_resolver_service& svc) noexcept
     234              42 :     : svc_(svc)
     235                 : {
     236              42 : }
     237                 : 
     238                 : // posix_resolver::resolve_op implementation
     239                 : 
     240                 : inline void
     241              21 : posix_resolver::resolve_op::reset() noexcept
     242                 : {
     243              21 :     host.clear();
     244              21 :     service.clear();
     245              21 :     flags          = resolve_flags::none;
     246              21 :     stored_results = resolver_results{};
     247              21 :     gai_error      = 0;
     248              21 :     cancelled.store(false, std::memory_order_relaxed);
     249              21 :     stop_cb.reset();
     250              21 :     ec_out = nullptr;
     251              21 :     out    = nullptr;
     252              21 : }
     253                 : 
     254                 : inline void
     255              21 : posix_resolver::resolve_op::operator()()
     256                 : {
     257              21 :     stop_cb.reset(); // Disconnect stop callback
     258                 : 
     259              21 :     bool const was_cancelled = cancelled.load(std::memory_order_acquire);
     260                 : 
     261              21 :     if (ec_out)
     262                 :     {
     263              21 :         if (was_cancelled)
     264               1 :             *ec_out = capy::error::canceled;
     265              20 :         else if (gai_error != 0)
     266               4 :             *ec_out = posix_resolver_detail::make_gai_error(gai_error);
     267                 :         else
     268              16 :             *ec_out = {}; // Clear on success
     269                 :     }
     270                 : 
     271              21 :     if (out && !was_cancelled && gai_error == 0)
     272              16 :         *out = std::move(stored_results);
     273                 : 
     274              21 :     impl->svc_.work_finished();
     275              21 :     cont_op.cont.h = h;
     276              21 :     dispatch_coro(ex, cont_op.cont).resume();
     277              21 : }
     278                 : 
     279                 : inline void
     280 MIS           0 : posix_resolver::resolve_op::destroy()
     281                 : {
     282               0 :     stop_cb.reset();
     283               0 : }
     284                 : 
     285                 : inline void
     286 HIT          47 : posix_resolver::resolve_op::request_cancel() noexcept
     287                 : {
     288              47 :     cancelled.store(true, std::memory_order_release);
     289              47 : }
     290                 : 
     291                 : inline void
     292              21 : posix_resolver::resolve_op::start(std::stop_token const& token)
     293                 : {
     294              21 :     cancelled.store(false, std::memory_order_release);
     295              21 :     stop_cb.reset();
     296                 : 
     297              21 :     if (token.stop_possible())
     298               1 :         stop_cb.emplace(token, canceller{this});
     299              21 : }
     300                 : 
     301                 : // posix_resolver::reverse_resolve_op implementation
     302                 : 
     303                 : inline void
     304              12 : posix_resolver::reverse_resolve_op::reset() noexcept
     305                 : {
     306              12 :     ep    = endpoint{};
     307              12 :     flags = reverse_flags::none;
     308              12 :     stored_host.clear();
     309              12 :     stored_service.clear();
     310              12 :     gai_error = 0;
     311              12 :     cancelled.store(false, std::memory_order_relaxed);
     312              12 :     stop_cb.reset();
     313              12 :     ec_out     = nullptr;
     314              12 :     result_out = nullptr;
     315              12 : }
     316                 : 
     317                 : inline void
     318              12 : posix_resolver::reverse_resolve_op::operator()()
     319                 : {
     320              12 :     stop_cb.reset(); // Disconnect stop callback
     321                 : 
     322              12 :     bool const was_cancelled = cancelled.load(std::memory_order_acquire);
     323                 : 
     324              12 :     if (ec_out)
     325                 :     {
     326              12 :         if (was_cancelled)
     327               1 :             *ec_out = capy::error::canceled;
     328              11 :         else if (gai_error != 0)
     329               1 :             *ec_out = posix_resolver_detail::make_gai_error(gai_error);
     330                 :         else
     331              10 :             *ec_out = {}; // Clear on success
     332                 :     }
     333                 : 
     334              12 :     if (result_out && !was_cancelled && gai_error == 0)
     335                 :     {
     336              30 :         *result_out = reverse_resolver_result(
     337              30 :             ep, std::move(stored_host), std::move(stored_service));
     338                 :     }
     339                 : 
     340              12 :     impl->svc_.work_finished();
     341              12 :     cont_op.cont.h = h;
     342              12 :     dispatch_coro(ex, cont_op.cont).resume();
     343              12 : }
     344                 : 
     345                 : inline void
     346 MIS           0 : posix_resolver::reverse_resolve_op::destroy()
     347                 : {
     348               0 :     stop_cb.reset();
     349               0 : }
     350                 : 
     351                 : inline void
     352 HIT          47 : posix_resolver::reverse_resolve_op::request_cancel() noexcept
     353                 : {
     354              47 :     cancelled.store(true, std::memory_order_release);
     355              47 : }
     356                 : 
     357                 : inline void
     358              12 : posix_resolver::reverse_resolve_op::start(std::stop_token const& token)
     359                 : {
     360              12 :     cancelled.store(false, std::memory_order_release);
     361              12 :     stop_cb.reset();
     362                 : 
     363              12 :     if (token.stop_possible())
     364               1 :         stop_cb.emplace(token, canceller{this});
     365              12 : }
     366                 : 
     367                 : // posix_resolver implementation
     368                 : 
     369                 : inline std::coroutine_handle<>
     370              22 : posix_resolver::resolve(
     371                 :     std::coroutine_handle<> h,
     372                 :     capy::executor_ref ex,
     373                 :     std::string_view host,
     374                 :     std::string_view service,
     375                 :     resolve_flags flags,
     376                 :     std::stop_token token,
     377                 :     std::error_code* ec,
     378                 :     resolver_results* out)
     379                 : {
     380              22 :     if (svc_.single_threaded())
     381                 :     {
     382               1 :         *ec = std::make_error_code(std::errc::operation_not_supported);
     383               1 :         op_.cont_op.cont.h = h;
     384               1 :         return dispatch_coro(ex, op_.cont_op.cont);
     385                 :     }
     386                 : 
     387              21 :     auto& op = op_;
     388              21 :     op.reset();
     389              21 :     op.h       = h;
     390              21 :     op.ex      = ex;
     391              21 :     op.impl    = this;
     392              21 :     op.ec_out  = ec;
     393              21 :     op.out     = out;
     394              21 :     op.host    = host;
     395              21 :     op.service = service;
     396              21 :     op.flags   = flags;
     397              21 :     op.start(token);
     398                 : 
     399                 :     // Keep io_context alive while resolution is pending
     400              21 :     op.ex.on_work_started();
     401                 : 
     402                 :     // Prevent impl destruction while work is in flight
     403              21 :     resolve_pool_op_.resolver_ = this;
     404              21 :     resolve_pool_op_.ref_      = this->shared_from_this();
     405              21 :     resolve_pool_op_.func_     = &posix_resolver::do_resolve_work;
     406              21 :     if (!svc_.pool().post(&resolve_pool_op_))
     407                 :     {
     408                 :         // Pool shut down — complete with cancellation
     409 MIS           0 :         resolve_pool_op_.ref_.reset();
     410               0 :         op.cancelled.store(true, std::memory_order_release);
     411               0 :         svc_.post(&op_);
     412                 :     }
     413 HIT          21 :     return std::noop_coroutine();
     414                 : }
     415                 : 
     416                 : inline std::coroutine_handle<>
     417              13 : posix_resolver::reverse_resolve(
     418                 :     std::coroutine_handle<> h,
     419                 :     capy::executor_ref ex,
     420                 :     endpoint const& ep,
     421                 :     reverse_flags flags,
     422                 :     std::stop_token token,
     423                 :     std::error_code* ec,
     424                 :     reverse_resolver_result* result_out)
     425                 : {
     426              13 :     if (svc_.single_threaded())
     427                 :     {
     428               1 :         *ec = std::make_error_code(std::errc::operation_not_supported);
     429               1 :         reverse_op_.cont_op.cont.h = h;
     430               1 :         return dispatch_coro(ex, reverse_op_.cont_op.cont);
     431                 :     }
     432                 : 
     433              12 :     auto& op = reverse_op_;
     434              12 :     op.reset();
     435              12 :     op.h          = h;
     436              12 :     op.ex         = ex;
     437              12 :     op.impl       = this;
     438              12 :     op.ec_out     = ec;
     439              12 :     op.result_out = result_out;
     440              12 :     op.ep         = ep;
     441              12 :     op.flags      = flags;
     442              12 :     op.start(token);
     443                 : 
     444                 :     // Keep io_context alive while resolution is pending
     445              12 :     op.ex.on_work_started();
     446                 : 
     447                 :     // Prevent impl destruction while work is in flight
     448              12 :     reverse_pool_op_.resolver_ = this;
     449              12 :     reverse_pool_op_.ref_      = this->shared_from_this();
     450              12 :     reverse_pool_op_.func_     = &posix_resolver::do_reverse_resolve_work;
     451              12 :     if (!svc_.pool().post(&reverse_pool_op_))
     452                 :     {
     453                 :         // Pool shut down — complete with cancellation
     454 MIS           0 :         reverse_pool_op_.ref_.reset();
     455               0 :         op.cancelled.store(true, std::memory_order_release);
     456               0 :         svc_.post(&reverse_op_);
     457                 :     }
     458 HIT          12 :     return std::noop_coroutine();
     459                 : }
     460                 : 
     461                 : inline void
     462              46 : posix_resolver::cancel() noexcept
     463                 : {
     464              46 :     op_.request_cancel();
     465              46 :     reverse_op_.request_cancel();
     466              46 : }
     467                 : 
     468                 : inline void
     469              21 : posix_resolver::do_resolve_work(pool_work_item* w) noexcept
     470                 : {
     471              21 :     auto* pw   = static_cast<pool_op*>(w);
     472              21 :     auto* self = pw->resolver_;
     473                 : 
     474              21 :     struct addrinfo hints{};
     475              21 :     hints.ai_family   = AF_UNSPEC;
     476              21 :     hints.ai_socktype = SOCK_STREAM;
     477              21 :     hints.ai_flags    = posix_resolver_detail::flags_to_hints(self->op_.flags);
     478                 : 
     479              21 :     struct addrinfo* ai = nullptr;
     480              63 :     int result          = ::getaddrinfo(
     481              42 :         self->op_.host.empty() ? nullptr : self->op_.host.c_str(),
     482              42 :         self->op_.service.empty() ? nullptr : self->op_.service.c_str(), &hints,
     483                 :         &ai);
     484                 : 
     485              21 :     if (!self->op_.cancelled.load(std::memory_order_acquire))
     486                 :     {
     487              20 :         if (result == 0 && ai)
     488                 :         {
     489              32 :             self->op_.stored_results = posix_resolver_detail::convert_results(
     490              16 :                 ai, self->op_.host, self->op_.service);
     491              16 :             self->op_.gai_error = 0;
     492                 :         }
     493                 :         else
     494                 :         {
     495               4 :             self->op_.gai_error = result;
     496                 :         }
     497                 :     }
     498                 : 
     499              21 :     if (ai)
     500              17 :         ::freeaddrinfo(ai);
     501                 : 
     502                 :     // Move ref to stack before post — post may trigger destroy_impl
     503                 :     // which erases the last shared_ptr, destroying *self (and *pw)
     504              21 :     auto ref = std::move(pw->ref_);
     505              21 :     self->svc_.post(&self->op_);
     506              21 : }
     507                 : 
     508                 : inline void
     509              12 : posix_resolver::do_reverse_resolve_work(pool_work_item* w) noexcept
     510                 : {
     511              12 :     auto* pw   = static_cast<pool_op*>(w);
     512              12 :     auto* self = pw->resolver_;
     513                 : 
     514              12 :     sockaddr_storage ss{};
     515                 :     socklen_t ss_len;
     516                 : 
     517              12 :     if (self->reverse_op_.ep.is_v4())
     518                 :     {
     519              10 :         auto sa = to_sockaddr_in(self->reverse_op_.ep);
     520              10 :         std::memcpy(&ss, &sa, sizeof(sa));
     521              10 :         ss_len = sizeof(sockaddr_in);
     522                 :     }
     523                 :     else
     524                 :     {
     525               2 :         auto sa = to_sockaddr_in6(self->reverse_op_.ep);
     526               2 :         std::memcpy(&ss, &sa, sizeof(sa));
     527               2 :         ss_len = sizeof(sockaddr_in6);
     528                 :     }
     529                 : 
     530                 :     char host[NI_MAXHOST];
     531                 :     char service[NI_MAXSERV];
     532                 : 
     533              12 :     int result = ::getnameinfo(
     534                 :         reinterpret_cast<sockaddr*>(&ss), ss_len, host, sizeof(host), service,
     535                 :         sizeof(service),
     536                 :         posix_resolver_detail::flags_to_ni_flags(self->reverse_op_.flags));
     537                 : 
     538              12 :     if (!self->reverse_op_.cancelled.load(std::memory_order_acquire))
     539                 :     {
     540              11 :         if (result == 0)
     541                 :         {
     542              10 :             self->reverse_op_.stored_host    = host;
     543              10 :             self->reverse_op_.stored_service = service;
     544              10 :             self->reverse_op_.gai_error      = 0;
     545                 :         }
     546                 :         else
     547                 :         {
     548               1 :             self->reverse_op_.gai_error = result;
     549                 :         }
     550                 :     }
     551                 : 
     552                 :     // Move ref to stack before post — post may trigger destroy_impl
     553                 :     // which erases the last shared_ptr, destroying *self (and *pw)
     554              12 :     auto ref = std::move(pw->ref_);
     555              12 :     self->svc_.post(&self->reverse_op_);
     556              12 : }
     557                 : 
     558                 : // posix_resolver_service implementation
     559                 : 
     560                 : inline void
     561            1021 : posix_resolver_service::shutdown()
     562                 : {
     563            1021 :     std::lock_guard<std::mutex> lock(mutex_);
     564                 : 
     565                 :     // Cancel all resolvers (sets cancelled flag checked by pool threads)
     566            1021 :     for (auto* impl = resolver_list_.pop_front(); impl != nullptr;
     567 MIS           0 :          impl       = resolver_list_.pop_front())
     568                 :     {
     569               0 :         impl->cancel();
     570                 :     }
     571                 : 
     572                 :     // Clear the map which releases shared_ptrs.
     573                 :     // The thread pool service shuts down separately via
     574                 :     // execution_context service ordering.
     575 HIT        1021 :     resolver_ptrs_.clear();
     576            1021 : }
     577                 : 
     578                 : inline io_object::implementation*
     579              42 : posix_resolver_service::construct()
     580                 : {
     581              42 :     auto ptr   = std::make_shared<posix_resolver>(*this);
     582              42 :     auto* impl = ptr.get();
     583                 : 
     584                 :     {
     585              42 :         std::lock_guard<std::mutex> lock(mutex_);
     586              42 :         resolver_list_.push_back(impl);
     587              42 :         resolver_ptrs_[impl] = std::move(ptr);
     588              42 :     }
     589                 : 
     590              42 :     return impl;
     591              42 : }
     592                 : 
     593                 : inline void
     594              42 : posix_resolver_service::destroy_impl(posix_resolver& impl)
     595                 : {
     596              42 :     std::lock_guard<std::mutex> lock(mutex_);
     597              42 :     resolver_list_.remove(&impl);
     598              42 :     resolver_ptrs_.erase(&impl);
     599              42 : }
     600                 : 
     601                 : inline void
     602              33 : posix_resolver_service::post(scheduler_op* op)
     603                 : {
     604              33 :     sched_->post(op);
     605              33 : }
     606                 : 
     607                 : inline void
     608                 : posix_resolver_service::work_started() noexcept
     609                 : {
     610                 :     sched_->work_started();
     611                 : }
     612                 : 
     613                 : inline void
     614              33 : posix_resolver_service::work_finished() noexcept
     615                 : {
     616              33 :     sched_->work_finished();
     617              33 : }
     618                 : 
     619                 : // Free function to get/create the resolver service
     620                 : 
     621                 : inline posix_resolver_service&
     622            1021 : get_resolver_service(capy::execution_context& ctx, scheduler& sched)
     623                 : {
     624            1021 :     return ctx.make_service<posix_resolver_service>(sched);
     625                 : }
     626                 : 
     627                 : } // namespace boost::corosio::detail
     628                 : 
     629                 : #endif // BOOST_COROSIO_POSIX
     630                 : 
     631                 : #endif // BOOST_COROSIO_NATIVE_DETAIL_POSIX_POSIX_RESOLVER_SERVICE_HPP
        

Generated by: LCOV version 2.3