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