include/boost/corosio/native/detail/posix/posix_resolver_service.hpp

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