Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-17 08:48:46

0001 // Copyright (c) 2022 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 #ifndef BOOST_PROCESS_V2_DETAIL_PROCESS_HANDLE_SIGNAL_HPP
0006 #define BOOST_PROCESS_V2_DETAIL_PROCESS_HANDLE_SIGNAL_HPP
0007 
0008 #include <boost/process/v2/detail/config.hpp>
0009 
0010 #include <sys/types.h>
0011 #include <sys/wait.h>
0012 
0013 #include <boost/process/v2/detail/last_error.hpp>
0014 #include <boost/process/v2/detail/throw_error.hpp>
0015 #include <boost/process/v2/exit_code.hpp>
0016 #include <boost/process/v2/pid.hpp>
0017 
0018 #if defined(BOOST_PROCESS_V2_STANDALONE)
0019 #include <asio/any_io_executor.hpp>
0020 #include <asio/compose.hpp>
0021 #include <asio/dispatch.hpp>
0022 #include <asio/post.hpp>
0023 #include <asio/signal_set.hpp>
0024 #else
0025 #include <boost/asio/any_io_executor.hpp>
0026 #include <boost/asio/compose.hpp>
0027 #include <boost/asio/dispatch.hpp>
0028 #include <boost/asio/post.hpp>
0029 #include <boost/asio/signal_set.hpp>
0030 #endif
0031 
0032 BOOST_PROCESS_V2_BEGIN_NAMESPACE
0033 
0034 namespace detail
0035 {
0036 
0037 template<typename Executor = net::any_io_executor>
0038 struct basic_process_handle_signal
0039 {
0040     struct native_handle_type
0041     {
0042          native_handle_type() = delete;
0043          native_handle_type(const native_handle_type & ) = delete;
0044         ~native_handle_type() = default;
0045     };
0046 
0047     typedef Executor executor_type;
0048 
0049     executor_type get_executor()
0050     { return signal_set_.get_executor(); }
0051 
0052     /// Rebinds the process_handle to another executor.
0053     template<typename Executor1>
0054     struct rebind_executor
0055     {
0056         /// The socket type when rebound to the specified executor.
0057         typedef basic_process_handle_signal<Executor1> other;
0058     };
0059 
0060     template<typename ExecutionContext>
0061     basic_process_handle_signal(ExecutionContext &context,
0062                          typename std::enable_if<
0063                                  std::is_convertible<ExecutionContext &,
0064                                          net::execution_context &>::value
0065                          >::type * = nullptr)
0066             : pid_(-1), signal_set_(context, SIGCHLD)
0067     {
0068     }
0069 
0070     basic_process_handle_signal(Executor executor)
0071             : pid_(-1), signal_set_(executor, SIGCHLD)
0072     {
0073     }
0074 
0075     basic_process_handle_signal(Executor executor, pid_type pid)
0076             : pid_(pid), signal_set_(executor, SIGCHLD)
0077     {
0078     }
0079 
0080     basic_process_handle_signal(basic_process_handle_signal && handle)
0081     : pid_(handle.pid_), signal_set_(handle.signal_set_.get_executor(), SIGCHLD)
0082     {
0083         handle.pid_ = -1;
0084     }
0085 
0086     basic_process_handle_signal& operator=(basic_process_handle_signal && handle)
0087     {
0088         pid_ = handle.id();
0089         signal_set_.~basic_signal_set();
0090         using ss = net::basic_signal_set<Executor>;
0091         new (&signal_set_) ss(handle.get_executor(), SIGCHLD);
0092         handle.pid_ = -1;
0093         return *this;
0094     }
0095 
0096 
0097     template<typename Executor1>
0098     basic_process_handle_signal(basic_process_handle_signal<Executor1> && handle)
0099     : pid_(handle.pid_), signal_set_(Executor1(handle.signal_set_.get_executor()), SIGCHLD)
0100     {
0101         handle.pid_ = -1;
0102     }
0103 
0104     pid_type id() const { return pid_; }
0105     native_handle_type native_handle() {return {};}
0106 
0107     void terminate_if_running(error_code &)
0108     {
0109          terminate_if_running();
0110     }
0111 
0112     void terminate_if_running()
0113     {
0114         if (pid_ <= 0)
0115             return;
0116         if (::waitpid(pid_, nullptr, WNOHANG) == 0)
0117         {
0118             ::kill(pid_, SIGKILL);
0119             ::waitpid(pid_, nullptr, 0);
0120         }
0121     }
0122 
0123     void wait(native_exit_code_type &exit_status, error_code &ec)
0124     {
0125         if (pid_ <= 0)
0126             return;
0127         while (::waitpid(pid_, &exit_status, 0) < 0)
0128         {
0129             if (errno != EINTR)
0130             {
0131                 ec = get_last_error();
0132                 break;
0133             }      
0134         }
0135     }
0136 
0137     void wait(native_exit_code_type &exit_status)
0138     {
0139         if (pid_ <= 0)
0140             return;
0141         error_code ec;
0142         wait(exit_status, ec);
0143         if (ec)
0144             detail::throw_error(ec, "wait(pid)");
0145     }
0146 
0147     void interrupt(error_code &ec)
0148     {
0149         if (pid_ <= 0)
0150             return;
0151         if (::kill(pid_, SIGINT) == -1)
0152             ec = get_last_error();
0153     }
0154 
0155     void interrupt()
0156     {
0157         if (pid_ <= 0)
0158             return;
0159         error_code ec;
0160         interrupt(ec);
0161         if (ec)
0162             detail::throw_error(ec, "interrupt");
0163     }
0164 
0165     void request_exit(error_code &ec)
0166     {
0167         if (pid_ <= 0)
0168             return;
0169         if (::kill(pid_, SIGTERM) == -1)
0170             ec = get_last_error();
0171     }
0172 
0173     void request_exit()
0174     {
0175         if (pid_ <= 0)
0176             return;
0177         error_code ec;
0178         request_exit(ec);
0179         if (ec)
0180             detail::throw_error(ec, "request_exit");
0181     }
0182 
0183     void suspend()
0184     {
0185         if (pid_ <= 0)
0186             return;
0187         error_code ec;
0188         suspend(ec);
0189         if (ec)
0190             detail::throw_error(ec, "suspend");
0191     }
0192 
0193     void suspend(error_code &ec)
0194     {
0195         if (pid_ <= 0)
0196             return;
0197         if (::kill(pid_, SIGSTOP) == -1)
0198             ec = get_last_error();
0199     }
0200 
0201     void resume()
0202     {
0203         if (pid_ <= 0)
0204             return;
0205         error_code ec;
0206         resume(ec);
0207         if (ec)
0208             detail::throw_error(ec, "resume");
0209     }
0210 
0211     void resume(error_code &ec)
0212     {
0213         if (pid_ <= 0)
0214             return;
0215         if (::kill(pid_, SIGCONT) == -1)
0216             ec = get_last_error();
0217     }
0218 
0219     void terminate(native_exit_code_type &exit_status, error_code &ec)
0220     {
0221         if (pid_ <= 0)
0222             return;
0223         if (::kill(pid_, SIGKILL) == -1)
0224             ec = get_last_error();
0225         else
0226             wait(exit_status, ec);
0227     }
0228 
0229     void terminate(native_exit_code_type &exit_status)
0230     {
0231         if (pid_ <= 0)
0232             return;
0233         error_code ec;
0234         terminate(exit_status, ec);
0235         if (ec)
0236             detail::throw_error(ec, "terminate");
0237     }
0238 
0239     bool running(native_exit_code_type &exit_code, error_code & ec)
0240     {
0241         if (pid_ <= 0)
0242             return false;
0243         int code = 0;
0244         int res = ::waitpid(pid_, &code, WNOHANG);
0245         if (res == -1)
0246             ec = get_last_error();
0247         
0248         if (res == 0)
0249             return true;
0250         else
0251             exit_code = code;
0252         return false;
0253     }
0254 
0255     bool running(native_exit_code_type &exit_code)
0256     {
0257         if (pid_ <= 0)
0258             return false;
0259 
0260         error_code ec;
0261         bool res = running(exit_code, ec);
0262         if (ec)
0263             detail::throw_error(ec, "is_running");
0264         return res;
0265     }
0266 
0267     bool is_open() const
0268     {
0269         return pid_ != -1;
0270     }
0271 
0272   private:
0273     template<typename>
0274     friend struct basic_process_handle_signal;
0275     pid_type pid_ = -1;
0276     net::basic_signal_set<Executor> signal_set_;
0277 
0278     struct async_wait_op_
0279     {
0280         net::basic_signal_set<Executor> &handle;
0281         pid_type pid_;
0282         
0283         template<typename Self>
0284         void operator()(Self &&self)
0285         {
0286             self.reset_cancellation_state(asio::enable_total_cancellation());
0287             handle.async_wait(std::move(self));
0288             handle.cancel();
0289             // we cancel so we end up on the signal-sets executor 
0290         }
0291 
0292         template<typename Self>
0293         void operator()(Self &&self, error_code ec, int sig)
0294         {
0295             if (ec == net::error::operation_aborted &&
0296                 self.get_cancellation_state().cancelled() 
0297                     == net::cancellation_type::none)
0298                 ec.clear();
0299 
0300             native_exit_code_type exit_code = -1;
0301             int wait_res = -1;
0302 
0303             if (pid_ <= 0) // error, complete early
0304                 ec = net::error::bad_descriptor;
0305             else if (!ec)
0306             {
0307                 wait_res = ::waitpid(pid_, &exit_code, WNOHANG);
0308                 if (wait_res == -1)
0309                     ec = get_last_error();
0310             }
0311 
0312             if (!ec && (wait_res == 0))
0313             {
0314                 handle.async_wait(std::move(self));
0315                 return;
0316             }
0317 
0318             struct completer
0319             {
0320                 error_code ec;
0321                 native_exit_code_type code;
0322                 typename std::decay<Self>::type self;
0323 
0324                 void operator()()
0325                 {
0326                     self.complete(ec, code);
0327                 }
0328             };
0329 
0330             const auto exec = self.get_executor();
0331             net::dispatch(exec, completer{ec, exit_code, std::move(self)});
0332         }
0333     };
0334  public:
0335     template<BOOST_PROCESS_V2_COMPLETION_TOKEN_FOR(void(error_code, int))
0336              WaitHandler = net::default_completion_token_t<executor_type>>
0337     auto async_wait(WaitHandler &&handler = net::default_completion_token_t<executor_type>())
0338       -> decltype(net::async_compose<WaitHandler, void(error_code, native_exit_code_type)>(
0339                     async_wait_op_{signal_set_, pid_}, handler, signal_set_))
0340     {
0341         return net::async_compose<WaitHandler, void(error_code, native_exit_code_type)>(
0342                 async_wait_op_{signal_set_, pid_}, handler, signal_set_);
0343     }
0344 };
0345 
0346 }
0347 
0348 
0349 BOOST_PROCESS_V2_END_NAMESPACE
0350 
0351 
0352 #endif //BOOST_PROCESS_V2_DETAIL_PROCESS_HANDLE_SIGNAL_HPP