File indexing completed on 2025-01-18 09:50: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 }
0230
0231 void terminate(native_exit_code_type &exit_status)
0232 {
0233 if (pid_ <= 0)
0234 return;
0235 error_code ec;
0236 terminate(exit_status, ec);
0237 if (ec)
0238 detail::throw_error(ec, "terminate");
0239 }
0240
0241 bool running(native_exit_code_type &exit_code, error_code & ec)
0242 {
0243 if (pid_ <= 0)
0244 return false;
0245 int code = 0;
0246 int res = ::waitpid(pid_, &code, WNOHANG);
0247 if (res == -1)
0248 ec = get_last_error();
0249 else if (res == 0)
0250 return true;
0251 else
0252 ec.clear();
0253
0254 if (res == 0)
0255 return true;
0256 else
0257 {
0258 exit_code = code;
0259 return false;
0260 }
0261 }
0262
0263 bool running(native_exit_code_type &exit_code)
0264 {
0265 if (pid_ <= 0)
0266 return false;
0267
0268 error_code ec;
0269 bool res = running(exit_code, ec);
0270 if (ec)
0271 detail::throw_error(ec, "is_running");
0272 return res;
0273 }
0274
0275 bool is_open() const
0276 {
0277 return pid_ != -1;
0278 }
0279
0280 template<BOOST_PROCESS_V2_COMPLETION_TOKEN_FOR(void(error_code, native_exit_code_type))
0281 WaitHandler BOOST_PROCESS_V2_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
0282 BOOST_PROCESS_V2_INITFN_AUTO_RESULT_TYPE(WaitHandler, void (error_code, native_exit_code_type))
0283 async_wait(WaitHandler &&handler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
0284 {
0285 return BOOST_PROCESS_V2_ASIO_NAMESPACE::async_compose<WaitHandler, void(error_code, native_exit_code_type)>(
0286 async_wait_op_{descriptor_, pid_}, handler, descriptor_);
0287 }
0288
0289 private:
0290 template<typename>
0291 friend
0292 struct basic_process_handle_fd;
0293 pid_type pid_ = -1;
0294 BOOST_PROCESS_V2_ASIO_NAMESPACE::posix::basic_stream_descriptor<Executor> descriptor_;
0295
0296 struct async_wait_op_
0297 {
0298 BOOST_PROCESS_V2_ASIO_NAMESPACE::posix::basic_descriptor<Executor> &descriptor;
0299 pid_type pid_;
0300
0301 template<typename Self>
0302 void operator()(Self &&self)
0303 {
0304 error_code ec;
0305 native_exit_code_type exit_code{};
0306 int wait_res = -1;
0307 if (pid_ <= 0)
0308 ec = BOOST_PROCESS_V2_ASIO_NAMESPACE::error::bad_descriptor;
0309 else
0310 {
0311 wait_res = ::waitpid(pid_, &exit_code, WNOHANG);
0312 if (wait_res == -1)
0313 ec = get_last_error();
0314 }
0315
0316
0317 if (!ec && (wait_res == 0))
0318 {
0319 descriptor.async_wait(
0320 BOOST_PROCESS_V2_ASIO_NAMESPACE::posix::descriptor_base::wait_read, std::move(self));
0321 return;
0322 }
0323
0324 struct completer
0325 {
0326 error_code ec;
0327 native_exit_code_type code;
0328 typename std::decay<Self>::type self;
0329
0330 void operator()()
0331 {
0332 self.complete(ec, code);
0333 }
0334 };
0335 BOOST_PROCESS_V2_ASIO_NAMESPACE::post(descriptor.get_executor(),
0336 completer{ec, exit_code, std::move(self)});
0337
0338 }
0339
0340 template<typename Self>
0341 void operator()(Self &&self, error_code ec, int = 0)
0342 {
0343 native_exit_code_type exit_code{};
0344 if (!ec)
0345 if (::waitpid(pid_, &exit_code, 0) == -1)
0346 ec = get_last_error();
0347 std::move(self).complete(ec, exit_code);
0348 }
0349 };
0350 };
0351 }
0352
0353 BOOST_PROCESS_V2_END_NAMESPACE
0354
0355 #endif