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

Generated by: LCOV version 2.3