File indexing completed on 2025-01-18 09:50:13
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #ifndef BOOST_PROCESS_V2_PROCESS_HPP
0012 #define BOOST_PROCESS_V2_PROCESS_HPP
0013
0014 #include <boost/process/v2/detail/config.hpp>
0015 #include <boost/process/v2/default_launcher.hpp>
0016 #include <boost/process/v2/exit_code.hpp>
0017 #include <boost/process/v2/pid.hpp>
0018 #include <boost/process/v2/ext/exe.hpp>
0019 #include <boost/process/v2/process_handle.hpp>
0020
0021 #if defined(BOOST_PROCESS_V2_STANDALONE)
0022 #include <asio/any_io_executor.hpp>
0023 #include <asio/post.hpp>
0024 #include <utility>
0025 #else
0026 #include <boost/asio/any_io_executor.hpp>
0027 #include <boost/asio/post.hpp>
0028 #include <boost/core/exchange.hpp>
0029 #endif
0030
0031 BOOST_PROCESS_V2_BEGIN_NAMESPACE
0032
0033
0034
0035
0036
0037 template<typename Executor = BOOST_PROCESS_V2_ASIO_NAMESPACE::any_io_executor>
0038 struct basic_process
0039 {
0040
0041 using executor_type = Executor;
0042
0043 executor_type get_executor() {return process_handle_.get_executor();}
0044
0045
0046 using handle_type = basic_process_handle<executor_type>;
0047
0048
0049 handle_type & handle() { return process_handle_; }
0050
0051
0052 const handle_type & handle() const { return process_handle_; }
0053
0054
0055 using native_handle_type = typename handle_type::native_handle_type;
0056
0057
0058 template <typename Executor1>
0059 struct rebind_executor
0060 {
0061
0062 typedef basic_process<Executor1> other;
0063 };
0064
0065
0066
0067 basic_process() = default;
0068
0069 basic_process(const basic_process&) = delete;
0070 basic_process& operator=(const basic_process&) = delete;
0071
0072
0073 basic_process(basic_process&& lhs) = default;
0074
0075
0076 basic_process& operator=(basic_process&& lhs) = default;
0077
0078
0079 template<typename Executor1>
0080 basic_process(basic_process<Executor1>&& lhs)
0081 : process_handle_(std::move(lhs.process_handle_)),
0082 exit_status_{lhs.exit_status_}
0083 {
0084 }
0085
0086
0087 template<typename ... Inits>
0088 explicit basic_process(
0089 executor_type executor,
0090 const filesystem::path& exe,
0091 std::initializer_list<string_view> args,
0092 Inits&&... inits)
0093 : basic_process(default_process_launcher()(std::move(executor), exe, args, std::forward<Inits>(inits)...))
0094 {
0095 }
0096
0097
0098 template<typename Args, typename ... Inits>
0099 explicit basic_process(
0100 executor_type executor,
0101 const filesystem::path& exe,
0102 Args&& args, Inits&&... inits)
0103 : basic_process(default_process_launcher()(std::move(executor), exe,
0104 std::forward<Args>(args), std::forward<Inits>(inits)...))
0105 {
0106 }
0107
0108
0109 template<typename ExecutionContext, typename ... Inits>
0110 explicit basic_process(
0111 ExecutionContext & context,
0112 typename std::enable_if<
0113 std::is_convertible<ExecutionContext&,
0114 BOOST_PROCESS_V2_ASIO_NAMESPACE::execution_context&>::value,
0115 const filesystem::path&>::type exe,
0116 std::initializer_list<string_view> args,
0117 Inits&&... inits)
0118 : basic_process(default_process_launcher()(executor_type(context.get_executor()),
0119 exe, args, std::forward<Inits>(inits)...))
0120 {
0121 }
0122
0123 template<typename ExecutionContext, typename Args, typename ... Inits>
0124 explicit basic_process(
0125 ExecutionContext & context,
0126 typename std::enable_if<
0127 std::is_convertible<ExecutionContext&,
0128 BOOST_PROCESS_V2_ASIO_NAMESPACE::execution_context&>::value,
0129 const filesystem::path&>::type exe,
0130 Args&& args, Inits&&... inits)
0131 : basic_process(default_process_launcher()(executor_type(context.get_executor()),
0132 exe, std::forward<Args>(args), std::forward<Inits>(inits)...))
0133 {
0134 }
0135
0136
0137 explicit basic_process(executor_type exec, pid_type pid) : process_handle_(std::move(exec), pid) {}
0138
0139
0140 explicit basic_process(executor_type exec, pid_type pid, native_handle_type native_handle)
0141 : process_handle_(std::move(exec), pid, native_handle) {}
0142
0143
0144 explicit basic_process(executor_type exec) : process_handle_{std::move(exec)} {}
0145
0146
0147 template <typename ExecutionContext>
0148 explicit basic_process(ExecutionContext & context, pid_type pid,
0149 typename std::enable_if<
0150 std::is_convertible<ExecutionContext&,
0151 BOOST_PROCESS_V2_ASIO_NAMESPACE::execution_context&>::value, void *>::type = nullptr)
0152 : process_handle_(context, pid) {}
0153
0154
0155 template <typename ExecutionContext>
0156 explicit basic_process(ExecutionContext & context, pid_type pid, native_handle_type native_handle,
0157 typename std::enable_if<
0158 std::is_convertible<ExecutionContext&,
0159 BOOST_PROCESS_V2_ASIO_NAMESPACE::execution_context&>::value, void *>::type = nullptr)
0160 : process_handle_(context.get_executor(), pid, native_handle) {}
0161
0162
0163 template <typename ExecutionContext>
0164 explicit basic_process(ExecutionContext & context,
0165 typename std::enable_if<
0166 is_convertible<ExecutionContext&,
0167 BOOST_PROCESS_V2_ASIO_NAMESPACE::execution_context&>::value, void *>::type = nullptr)
0168 : process_handle_(context.get_executor()) {}
0169
0170
0171
0172
0173 ~basic_process()
0174 {
0175 process_handle_.terminate_if_running();
0176 }
0177
0178
0179
0180 void interrupt()
0181 {
0182 error_code ec;
0183 interrupt(ec);
0184 if (ec)
0185 throw system_error(ec, "interrupt failed");
0186
0187 }
0188
0189 void interrupt(error_code & ec)
0190 {
0191 process_handle_.interrupt(ec);
0192 }
0193
0194
0195 void request_exit()
0196 {
0197 error_code ec;
0198 request_exit(ec);
0199 if (ec)
0200 throw system_error(ec, "request_exit failed");
0201 }
0202
0203 void request_exit(error_code & ec)
0204 {
0205 process_handle_.request_exit(ec);
0206 }
0207
0208
0209 void suspend(error_code &ec)
0210 {
0211 process_handle_.suspend(ec);
0212 }
0213
0214
0215 void suspend()
0216 {
0217 error_code ec;
0218 suspend(ec);
0219 if (ec)
0220 detail::throw_error(ec, "suspend");
0221 }
0222
0223
0224
0225 void resume(error_code &ec)
0226 {
0227 process_handle_.resume(ec);
0228 }
0229
0230
0231 void resume()
0232 {
0233 error_code ec;
0234 suspend(ec);
0235 if (ec)
0236 detail::throw_error(ec, "resume");
0237 }
0238
0239
0240 void terminate()
0241 {
0242 error_code ec;
0243 terminate(ec);
0244 if (ec)
0245 detail::throw_error(ec, "terminate failed");
0246 }
0247
0248 void terminate(error_code & ec)
0249 {
0250 process_handle_.terminate(exit_status_, ec);
0251 }
0252
0253
0254 int wait()
0255 {
0256 error_code ec;
0257 if (running(ec))
0258 process_handle_.wait(exit_status_, ec);
0259 if (ec)
0260 detail::throw_error(ec, "wait failed");
0261 return exit_code();
0262 }
0263
0264 int wait(error_code & ec)
0265 {
0266 if (running(ec))
0267 process_handle_.wait(exit_status_, ec);
0268 return exit_code();
0269 }
0270
0271
0272 handle_type detach()
0273 {
0274 #if defined(BOOST_PROCESS_V2_STANDALONE)
0275 return std::exchange(process_handle_, get_executor());
0276 #else
0277 return boost::exchange(process_handle_, get_executor());
0278 #endif
0279 }
0280
0281 native_handle_type native_handle() {return process_handle_.native_handle(); }
0282
0283 int exit_code() const
0284 {
0285 return evaluate_exit_code(exit_status_);
0286 }
0287
0288
0289 pid_type id() const {return process_handle_.id();}
0290
0291
0292
0293 native_exit_code_type native_exit_code() const
0294 {
0295 return exit_status_;
0296 }
0297
0298
0299
0300
0301 bool running()
0302 {
0303 error_code ec;
0304 native_exit_code_type exit_code{};
0305 auto r = process_handle_.running(exit_code, ec);
0306 if (!ec && !r)
0307 exit_status_ = exit_code;
0308 else
0309 detail::throw_error(ec, "running failed");
0310
0311 return r;
0312 }
0313
0314
0315 bool running(error_code & ec) noexcept
0316 {
0317 native_exit_code_type exit_code{};
0318 auto r = process_handle_.running(exit_code, ec);
0319 if (!ec && !r)
0320 exit_status_ = exit_code;
0321 return r;
0322 }
0323
0324
0325
0326 bool is_open() const { return process_handle_.is_open(); }
0327
0328
0329 template <BOOST_PROCESS_V2_COMPLETION_TOKEN_FOR(void (error_code, int))
0330 WaitHandler BOOST_PROCESS_V2_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
0331 BOOST_PROCESS_V2_INITFN_AUTO_RESULT_TYPE(WaitHandler, void (error_code, int))
0332 async_wait(WaitHandler && handler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
0333 {
0334 return BOOST_PROCESS_V2_ASIO_NAMESPACE::async_compose<WaitHandler, void (error_code, int)>(
0335 async_wait_op_{process_handle_, exit_status_}, handler, process_handle_);
0336 }
0337
0338 private:
0339 template<typename Executor1>
0340 friend struct basic_process;
0341
0342 basic_process_handle<Executor> process_handle_;
0343 native_exit_code_type exit_status_{detail::still_active};
0344
0345
0346 struct async_wait_op_
0347 {
0348 basic_process_handle<Executor> & handle;
0349 native_exit_code_type & res;
0350
0351 template<typename Self>
0352 void operator()(Self && self)
0353 {
0354 if (!process_is_running(res))
0355 {
0356 struct completer
0357 {
0358 int code;
0359 typename std::decay<Self>::type self;
0360 void operator()()
0361 {
0362 self.complete(error_code{}, evaluate_exit_code(code));
0363 }
0364 };
0365
0366 BOOST_PROCESS_V2_ASIO_NAMESPACE::post(handle.get_executor(),
0367 completer{static_cast<int>(res), std::move(self)});
0368 }
0369 else
0370 handle.async_wait(std::move(self));
0371 }
0372
0373 template<typename Self>
0374 void operator()(Self && self, error_code ec, native_exit_code_type code)
0375 {
0376 if (!ec && process_is_running(code))
0377 handle.async_wait(std::move(self));
0378 else
0379 {
0380 if (!ec)
0381 res = code;
0382 std::move(self).complete(ec, evaluate_exit_code(code));
0383 }
0384 }
0385 };
0386 };
0387
0388
0389 typedef basic_process<> process;
0390
0391 BOOST_PROCESS_V2_END_NAMESPACE
0392
0393
0394 #endif