77#ifndef BOOST_PROCESS_DETAIL_POSIX_SIGCHLD_SERVICE_HPP_
88#define BOOST_PROCESS_DETAIL_POSIX_SIGCHLD_SERVICE_HPP_
99
10+ #include < boost/asio/bind_executor.hpp>
1011#include < boost/asio/dispatch.hpp>
1112#include < boost/asio/post.hpp>
13+ #include < boost/asio/consign.hpp>
14+ #include < boost/asio/append.hpp>
1215#include < boost/asio/signal_set.hpp>
1316#include < boost/asio/strand.hpp>
1417#include < boost/optional.hpp>
@@ -26,6 +29,43 @@ class sigchld_service : public boost::asio::detail::service_base<sigchld_service
2629
2730 std::list<std::pair<::pid_t , std::function<void (int , std::error_code)>>> _receivers;
2831 inline void _handle_signal (const boost::system::error_code & ec);
32+
33+ struct initiate_async_wait_op
34+ {
35+ sigchld_service * self;
36+ template <typename Initiation>
37+ void operator ()(Initiation && init, ::pid_t pid)
38+ {
39+ // check if the child actually is running first
40+ int status;
41+ auto pid_res = ::waitpid (pid, &status, WNOHANG);
42+ if (pid_res < 0 )
43+ {
44+ auto ec = get_last_error ();
45+ boost::asio::post (
46+ self->_strand ,
47+ asio::append (std::forward<Initiation>(init), pid_res, ec));
48+ }
49+ else if ((pid_res == pid) && (WIFEXITED (status) || WIFSIGNALED (status)))
50+ boost::asio::post (
51+ self->_strand ,
52+ boost::asio::append (std::forward<Initiation>(init), status, std::error_code{}));
53+ else // still running
54+ {
55+ sigchld_service * self_ = self;
56+ if (self->_receivers .empty ())
57+ self->_signal_set .async_wait (
58+ boost::asio::bind_executor (
59+ self->_strand ,
60+ [self_](const boost::system::error_code &ec, int )
61+ {
62+ self_->_handle_signal (ec);
63+ }));
64+ self->_receivers .emplace_back (pid, init);
65+ }
66+ }
67+ };
68+
2969public:
3070 sigchld_service (boost::asio::io_context & io_context)
3171 : boost::asio::detail::service_base<sigchld_service>(io_context)
@@ -37,47 +77,10 @@ class sigchld_service : public boost::asio::detail::service_base<sigchld_service
3777 void (int , std::error_code))
3878 async_wait(::pid_t pid, SignalHandler && handler)
3979 {
40- boost::asio::async_completion<
41- SignalHandler, void (boost::system::error_code)> init{handler};
42-
43- auto & h = init.completion_handler ;
44- boost::asio::dispatch (
45- _strand,
46- [this , pid, h]
47- {
48- // check if the child actually is running first
49- int status;
50- auto pid_res = ::waitpid (pid, &status, WNOHANG);
51- if (pid_res < 0 )
52- {
53- auto ec = get_last_error ();
54- boost::asio::post (
55- _strand,
56- [pid_res, ec, h]
57- {
58- h (pid_res, ec);
59- });
60- }
61- else if ((pid_res == pid) && (WIFEXITED (status) || WIFSIGNALED (status)))
62- boost::asio::post (
63- _strand,
64- [status, h]
65- {
66- h (status, {}); // successfully exited already
67- });
68- else // still running
69- {
70- if (_receivers.empty ())
71- _signal_set.async_wait (
72- [this ](const boost::system::error_code &ec, int )
73- {
74- boost::asio::dispatch (_strand, [this , ec]{this ->_handle_signal (ec);});
75- });
76- _receivers.emplace_back (pid, h);
77- }
78- });
79-
80- return init.result .get ();
80+ return boost::asio::async_initiate<
81+ SignalHandler,
82+ void (int , std::error_code)>(
83+ initiate_async_wait_op{this }, handler, pid);
8184 }
8285 void shutdown () override
8386 {
0 commit comments