File indexing completed on 2025-01-18 09:50:10
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 = BOOST_PROCESS_V2_ASIO_NAMESPACE::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 BOOST_PROCESS_V2_ASIO_NAMESPACE::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 = BOOST_PROCESS_V2_ASIO_NAMESPACE::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_, SIGTERM) == -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_, SIGCONT) == -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_, SIGTERM) == -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 }
0226
0227 void terminate(native_exit_code_type &exit_status)
0228 {
0229 if (pid_ <= 0)
0230 return;
0231 error_code ec;
0232 terminate(exit_status, ec);
0233 if (ec)
0234 detail::throw_error(ec, "terminate");
0235 }
0236
0237 bool running(native_exit_code_type &exit_code, error_code & ec)
0238 {
0239 if (pid_ <= 0)
0240 return false;
0241 int code = 0;
0242 int res = ::waitpid(pid_, &code, WNOHANG);
0243 if (res == -1)
0244 ec = get_last_error();
0245
0246 if (res == 0)
0247 return true;
0248 else
0249 {
0250 exit_code = code;
0251 return false;
0252 }
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 template<BOOST_PROCESS_V2_COMPLETION_TOKEN_FOR(void(error_code, int))
0273 WaitHandler BOOST_PROCESS_V2_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
0274 BOOST_PROCESS_V2_INITFN_AUTO_RESULT_TYPE(WaitHandler, void (error_code, native_exit_code_type))
0275 async_wait(WaitHandler &&handler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
0276 {
0277 return BOOST_PROCESS_V2_ASIO_NAMESPACE::async_compose<WaitHandler, void(error_code, native_exit_code_type)>(
0278 async_wait_op_{signal_set_, pid_}, handler, signal_set_);
0279 }
0280
0281 private:
0282 template<typename>
0283 friend struct basic_process_handle_signal;
0284 pid_type pid_ = -1;
0285 BOOST_PROCESS_V2_ASIO_NAMESPACE::basic_signal_set<Executor> signal_set_;
0286
0287 struct async_wait_op_
0288 {
0289 BOOST_PROCESS_V2_ASIO_NAMESPACE::basic_signal_set<Executor> &handle;
0290 pid_type pid_;
0291
0292 template<typename Self>
0293 void operator()(Self &&self)
0294 {
0295 handle.async_wait(std::move(self));
0296 handle.cancel();
0297
0298 }
0299
0300 template<typename Self>
0301 void operator()(Self &&self, error_code ec, int sig)
0302 {
0303 if (ec == BOOST_PROCESS_V2_ASIO_NAMESPACE::error::operation_aborted &&
0304 self.get_cancellation_state().cancelled()
0305 == BOOST_PROCESS_V2_ASIO_NAMESPACE::cancellation_type::none)
0306 ec.clear();
0307
0308 native_exit_code_type exit_code = -1;
0309 int wait_res = -1;
0310
0311 if (pid_ <= 0)
0312 ec = BOOST_PROCESS_V2_ASIO_NAMESPACE::error::bad_descriptor;
0313 else if (!ec)
0314 {
0315 wait_res = ::waitpid(pid_, &exit_code, WNOHANG);
0316 if (wait_res == -1)
0317 ec = get_last_error();
0318 }
0319
0320 if (!ec && (wait_res == 0))
0321 {
0322 handle.async_wait(std::move(self));
0323 return;
0324 }
0325
0326 struct completer
0327 {
0328 error_code ec;
0329 native_exit_code_type code;
0330 typename std::decay<Self>::type self;
0331
0332 void operator()()
0333 {
0334 self.complete(ec, code);
0335 }
0336 };
0337
0338 const auto exec = self.get_executor();
0339 BOOST_PROCESS_V2_ASIO_NAMESPACE::dispatch(exec, completer{ec, exit_code, std::move(self)});
0340 }
0341 };
0342 };
0343
0344 }
0345
0346
0347 BOOST_PROCESS_V2_END_NAMESPACE
0348
0349
0350 #endif