Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-08-27 09:14:54

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