File indexing completed on 2025-09-17 08:48:46
0001
0002
0003
0004
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
0053 template<typename Executor1>
0054 struct rebind_executor
0055 {
0056
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
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)
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