File indexing completed on 2025-01-18 09:50:06
0001
0002
0003
0004
0005
0006
0007 #ifndef BOOST_PROCESS_DETAIL_POSIX_SIGCHLD_SERVICE_HPP_
0008 #define BOOST_PROCESS_DETAIL_POSIX_SIGCHLD_SERVICE_HPP_
0009
0010 #include <boost/asio/bind_executor.hpp>
0011 #include <boost/asio/dispatch.hpp>
0012 #include <boost/asio/post.hpp>
0013 #include <boost/asio/consign.hpp>
0014 #include <boost/asio/append.hpp>
0015 #include <boost/asio/signal_set.hpp>
0016 #include <boost/asio/strand.hpp>
0017 #include <boost/optional.hpp>
0018 #include <signal.h>
0019 #include <functional>
0020 #include <sys/wait.h>
0021 #include <list>
0022
0023 namespace boost { namespace process { namespace detail { namespace posix {
0024
0025 class sigchld_service : public boost::asio::detail::service_base<sigchld_service>
0026 {
0027 boost::asio::strand<boost::asio::io_context::executor_type> _strand{get_io_context().get_executor()};
0028 boost::asio::signal_set _signal_set{get_io_context(), SIGCHLD};
0029
0030 std::list<std::pair<::pid_t, std::function<void(int, std::error_code)>>> _receivers;
0031 inline void _handle_signal(const boost::system::error_code & ec);
0032
0033 struct initiate_async_wait_op
0034 {
0035 sigchld_service * self;
0036 template<typename Initiation>
0037 void operator()(Initiation && init, ::pid_t pid)
0038 {
0039
0040 int status;
0041 auto pid_res = ::waitpid(pid, &status, WNOHANG);
0042 if (pid_res < 0)
0043 {
0044 auto ec = get_last_error();
0045 boost::asio::post(
0046 self->_strand,
0047 asio::append(std::forward<Initiation>(init), pid_res, ec));
0048 }
0049 else if ((pid_res == pid) && (WIFEXITED(status) || WIFSIGNALED(status)))
0050 boost::asio::post(
0051 self->_strand,
0052 boost::asio::append(std::forward<Initiation>(init), status, std::error_code{}));
0053 else
0054 {
0055 sigchld_service * self_ = self;
0056 if (self->_receivers.empty())
0057 self->_signal_set.async_wait(
0058 boost::asio::bind_executor(
0059 self->_strand,
0060 [self_](const boost::system::error_code &ec, int)
0061 {
0062 self_->_handle_signal(ec);
0063 }));
0064 self->_receivers.emplace_back(pid, init);
0065 }
0066 }
0067 };
0068
0069 public:
0070 sigchld_service(boost::asio::io_context & io_context)
0071 : boost::asio::detail::service_base<sigchld_service>(io_context)
0072 {
0073 }
0074
0075 template <typename SignalHandler>
0076 BOOST_ASIO_INITFN_RESULT_TYPE(SignalHandler,
0077 void (int, std::error_code))
0078 async_wait(::pid_t pid, SignalHandler && handler)
0079 {
0080 return boost::asio::async_initiate<
0081 SignalHandler,
0082 void(int, std::error_code)>(
0083 initiate_async_wait_op{this}, handler, pid);
0084 }
0085 void shutdown() override
0086 {
0087 _receivers.clear();
0088 }
0089
0090 void cancel()
0091 {
0092 _signal_set.cancel();
0093 }
0094 void cancel(boost::system::error_code & ec)
0095 {
0096 _signal_set.cancel(ec);
0097 }
0098 };
0099
0100
0101 void sigchld_service::_handle_signal(const boost::system::error_code & ec)
0102 {
0103 std::error_code ec_{ec.value(), std::system_category()};
0104
0105 if (ec_)
0106 {
0107 for (auto & r : _receivers)
0108 r.second(-1, ec_);
0109 return;
0110 }
0111
0112 for (auto & r : _receivers) {
0113 int status;
0114 int pid = ::waitpid(r.first, &status, WNOHANG);
0115 if (pid < 0) {
0116
0117 r.second(-1, get_last_error());
0118 r.first = 0;
0119 } else if (pid == r.first) {
0120 r.second(status, ec_);
0121 r.first = 0;
0122 }
0123
0124 }
0125
0126 _receivers.erase(std::remove_if(_receivers.begin(), _receivers.end(),
0127 [](const std::pair<::pid_t, std::function<void(int, std::error_code)>> & p)
0128 {
0129 return p.first == 0;
0130 }),
0131 _receivers.end());
0132
0133 if (!_receivers.empty())
0134 {
0135 _signal_set.async_wait(
0136 [this](const boost::system::error_code & ec, int)
0137 {
0138 boost::asio::post(_strand, [this, ec]{this->_handle_signal(ec);});
0139 });
0140 }
0141 }
0142
0143
0144 }
0145 }
0146 }
0147 }
0148
0149
0150
0151
0152 #endif