File indexing completed on 2025-07-11 08:25:09
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 = BOOST_PROCESS_V2_ASIO_NAMESPACE::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 BOOST_PROCESS_V2_ASIO_NAMESPACE::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 template<BOOST_PROCESS_V2_COMPLETION_TOKEN_FOR(void(error_code, native_exit_code_type))
0279 WaitHandler BOOST_PROCESS_V2_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
0280 BOOST_PROCESS_V2_INITFN_AUTO_RESULT_TYPE(WaitHandler, void (error_code, native_exit_code_type))
0281 async_wait(WaitHandler &&handler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
0282 {
0283 return BOOST_PROCESS_V2_ASIO_NAMESPACE::async_compose<WaitHandler, void(error_code, native_exit_code_type)>(
0284 async_wait_op_{descriptor_, pid_}, handler, descriptor_);
0285 }
0286
0287 private:
0288 template<typename>
0289 friend
0290 struct basic_process_handle_fd;
0291 pid_type pid_ = -1;
0292 BOOST_PROCESS_V2_ASIO_NAMESPACE::posix::basic_stream_descriptor<Executor> descriptor_;
0293
0294 struct async_wait_op_
0295 {
0296 BOOST_PROCESS_V2_ASIO_NAMESPACE::posix::basic_descriptor<Executor> &descriptor;
0297 pid_type pid_;
0298
0299 template<typename Self>
0300 void operator()(Self &&self)
0301 {
0302 error_code ec;
0303 native_exit_code_type exit_code{};
0304 int wait_res = -1;
0305 if (pid_ <= 0)
0306 ec = BOOST_PROCESS_V2_ASIO_NAMESPACE::error::bad_descriptor;
0307 else
0308 {
0309 wait_res = ::waitpid(pid_, &exit_code, WNOHANG);
0310 if (wait_res == -1)
0311 ec = get_last_error();
0312 }
0313
0314
0315 if (!ec && (wait_res == 0))
0316 {
0317 descriptor.async_wait(
0318 BOOST_PROCESS_V2_ASIO_NAMESPACE::posix::descriptor_base::wait_read, std::move(self));
0319 return;
0320 }
0321
0322 struct completer
0323 {
0324 error_code ec;
0325 native_exit_code_type code;
0326 typename std::decay<Self>::type self;
0327
0328 void operator()()
0329 {
0330 self.complete(ec, code);
0331 }
0332 };
0333 BOOST_PROCESS_V2_ASIO_NAMESPACE::post(descriptor.get_executor(),
0334 completer{ec, exit_code, std::move(self)});
0335
0336 }
0337
0338 template<typename Self>
0339 void operator()(Self &&self, error_code ec, int = 0)
0340 {
0341 native_exit_code_type exit_code{};
0342 if (!ec)
0343 if (::waitpid(pid_, &exit_code, 0) == -1)
0344 ec = get_last_error();
0345 std::move(self).complete(ec, exit_code);
0346 }
0347 };
0348 };
0349 }
0350
0351 BOOST_PROCESS_V2_END_NAMESPACE
0352
0353 #endif