Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:50:06

0001 // Copyright (c) 2017 Klemens D. Morgenstern
0002 //
0003 // Distributed under the Boost Software License, Version 1.0. (See accompanying
0004 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
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             // check if the child actually is running first
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 //still running
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             // error (eg: the process no longer exists)
0117             r.second(-1, get_last_error());
0118             r.first = 0; // mark for deletion
0119         } else if (pid == r.first) {
0120             r.second(status, ec_);
0121             r.first = 0; // mark for deletion
0122         }
0123         // otherwise the process is still around
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