Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-08-07 09:03:14

0001 
0002 // Copyright (c) 2022 Klemens D. Morgenstern
0003 //
0004 // Distributed under the Boost Software License, Version 1.0. (See accompanying
0005 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0006 #ifndef BOOST_PROCESS_V2_DETAIL_PROCESS_HANDLE_FD_OR_SIGNAL_HPP
0007 #define BOOST_PROCESS_V2_DETAIL_PROCESS_HANDLE_FD_OR_SIGNAL_HPP
0008 
0009 #include <boost/process/v2/detail/config.hpp>
0010 
0011 #include <sys/types.h>
0012 #include <sys/wait.h>
0013 
0014 #include <boost/process/v2/detail/last_error.hpp>
0015 #include <boost/process/v2/detail/throw_error.hpp>
0016 #include <boost/process/v2/exit_code.hpp>
0017 #include <boost/process/v2/pid.hpp>
0018 
0019 #if defined(BOOST_PROCESS_V2_STANDALONE)
0020 #include <asio/any_io_executor.hpp>
0021 #include <asio/append.hpp>
0022 #include <asio/associated_immediate_executor.hpp>
0023 #include <asio/compose.hpp>
0024 #include <asio/dispatch.hpp>
0025 #include <asio/posix/basic_stream_descriptor.hpp>
0026 #include <asio/post.hpp>
0027 #if !defined(BOOST_PROCESS_V2_DISABLE_SIGNALSET)
0028 #include <asio/signal_set.hpp>
0029 #endif
0030 #else
0031 #include <boost/asio/any_io_executor.hpp>
0032 #include <boost/asio/append.hpp>
0033 #include <boost/asio/associated_immediate_executor.hpp>
0034 #include <boost/asio/compose.hpp>
0035 #include <boost/asio/dispatch.hpp>
0036 #include <boost/asio/posix/basic_stream_descriptor.hpp>
0037 #include <boost/asio/post.hpp>
0038 #if !defined(BOOST_PROCESS_V2_DISABLE_SIGNALSET)
0039 #include <boost/asio/signal_set.hpp>
0040 #endif
0041 #endif
0042 
0043 BOOST_PROCESS_V2_BEGIN_NAMESPACE
0044 
0045 namespace detail
0046 {
0047 
0048 template<typename Executor = net::any_io_executor>
0049 struct basic_process_handle_fd_or_signal
0050 {
0051     using native_handle_type = int;
0052     
0053     typedef Executor executor_type;
0054 
0055     executor_type get_executor()
0056     { return descriptor_.get_executor(); }
0057 
0058     /// Rebinds the process_handle to another executor.
0059     template<typename Executor1>
0060     struct rebind_executor
0061     {
0062         /// The socket type when rebound to the specified executor.
0063         typedef basic_process_handle_fd_or_signal<Executor1> other;
0064     };
0065 
0066     template<typename ExecutionContext>
0067     basic_process_handle_fd_or_signal(ExecutionContext &context,
0068                                 typename std::enable_if<
0069                                         std::is_convertible<ExecutionContext &,
0070                                                 net::execution_context &>::value
0071                                 >::type * = nullptr)
0072             : pid_(-1), descriptor_(context)
0073     {
0074     }
0075 
0076     template<typename ExecutionContext>
0077     basic_process_handle_fd_or_signal(ExecutionContext &context,
0078                                       pid_type pid,
0079                                       typename std::enable_if<
0080                                           std::is_convertible<ExecutionContext &,
0081                                               net::execution_context &>::value
0082                                           >::type * = nullptr)
0083             : pid_(pid), descriptor_(context)
0084     {
0085     }
0086     
0087     template<typename ExecutionContext>
0088     basic_process_handle_fd_or_signal(ExecutionContext &context,
0089                                       pid_type pid, native_handle_type process_handle,
0090                                       typename std::enable_if<
0091                                           std::is_convertible<ExecutionContext &,
0092                                               net::execution_context &>::value
0093                                           >::type * = nullptr)
0094             : pid_(pid), descriptor_(context, process_handle)
0095     {
0096     }
0097     
0098 
0099     basic_process_handle_fd_or_signal(Executor executor)
0100             : pid_(-1), descriptor_(executor)
0101     {
0102     }
0103 
0104     basic_process_handle_fd_or_signal(Executor executor, pid_type pid)
0105             : pid_(pid), descriptor_(executor)
0106     {
0107     }
0108 
0109     basic_process_handle_fd_or_signal(Executor executor, pid_type pid, native_handle_type process_handle)
0110             : pid_(pid), descriptor_(executor, process_handle)
0111     {
0112     }
0113 
0114 
0115     basic_process_handle_fd_or_signal(basic_process_handle_fd_or_signal &&handle)
0116             : pid_(handle.pid_), descriptor_(std::move(handle.descriptor_))
0117     {
0118         handle.pid_ = -1;
0119     }
0120     // Warn: does not change the executor of the signal-set.
0121     basic_process_handle_fd_or_signal& operator=(basic_process_handle_fd_or_signal &&handle)
0122     {
0123         pid_ = handle.pid_;
0124         descriptor_ = std::move(handle.descriptor_);
0125         handle.pid_ = -1;
0126         return *this;
0127     }
0128 
0129 
0130     template<typename Executor1>
0131     basic_process_handle_fd_or_signal(basic_process_handle_fd_or_signal<Executor1> &&handle)
0132             : pid_(handle.pid_), descriptor_(std::move(handle.descriptor_))
0133     {
0134         handle.pid_ = -1;
0135     }
0136 
0137     pid_type id() const
0138     { return pid_; }
0139     native_handle_type native_handle() {return pid_;}
0140 
0141     void terminate_if_running(error_code &)
0142     {
0143         if (pid_ <= 0)
0144             return;
0145         if (::waitpid(pid_, nullptr, WNOHANG) == 0)
0146         {
0147             ::kill(pid_, SIGKILL);
0148             ::waitpid(pid_, nullptr, 0);
0149         }
0150     }
0151 
0152     void terminate_if_running()
0153     {
0154         if (pid_ <= 0)
0155             return;
0156         if (::waitpid(pid_, nullptr, WNOHANG) == 0)
0157         {
0158             ::kill(pid_, SIGKILL);
0159             ::waitpid(pid_, nullptr, 0);
0160         }
0161     }
0162 
0163     void wait(native_exit_code_type &exit_status, error_code &ec)
0164     {
0165         if (pid_ <= 0)
0166             return;
0167         while (::waitpid(pid_, &exit_status, 0) < 0)
0168         {
0169             if (errno != EINTR)
0170             {
0171                 ec = get_last_error();
0172                 break;
0173             }               
0174         }
0175             
0176     }
0177 
0178     void wait(native_exit_code_type &exit_status)
0179     {
0180         if (pid_ <= 0)
0181             return;
0182         error_code ec;
0183         wait(exit_status, ec);
0184         if (ec)
0185             detail::throw_error(ec, "wait(pid)");
0186     }
0187 
0188     void interrupt(error_code &ec)
0189     {
0190         if (pid_ <= 0)
0191             return;
0192         if (::kill(pid_, SIGINT) == -1)
0193             ec = get_last_error();
0194     }
0195 
0196     void interrupt()
0197     {
0198         if (pid_ <= 0)
0199             return;
0200         error_code ec;
0201         interrupt(ec);
0202         if (ec)
0203             detail::throw_error(ec, "interrupt");
0204     }
0205 
0206     void request_exit(error_code &ec)
0207     {
0208         if (pid_ <= 0)
0209             return;
0210         if (::kill(pid_, SIGTERM) == -1)
0211             ec = get_last_error();
0212     }
0213 
0214     void request_exit()
0215     {
0216         if (pid_ <= 0)
0217             return;
0218         error_code ec;
0219         request_exit(ec);
0220         if (ec)
0221             detail::throw_error(ec, "request_exit");
0222     }
0223     
0224     void suspend()
0225     {
0226         if (pid_ <= 0)
0227             return ;
0228         error_code ec;
0229         suspend(ec);
0230         if (ec)
0231             detail::throw_error(ec, "suspend");
0232     }
0233 
0234     void suspend(error_code &ec)
0235     {
0236         if (pid_ <= 0)
0237             return ;
0238         if (::kill(pid_, SIGSTOP) == -1)
0239             ec = get_last_error();
0240     }
0241 
0242     void resume()
0243     {
0244         if (pid_ <= 0)
0245             return ;
0246         error_code ec;
0247         resume(ec);
0248         if (ec)
0249             detail::throw_error(ec, "resume");
0250     }
0251 
0252     void resume(error_code &ec)
0253     {
0254         if (pid_ <= 0)
0255             return ;
0256         if (::kill(pid_, SIGCONT) == -1)
0257             ec = get_last_error();
0258     }
0259 
0260     void terminate(native_exit_code_type &exit_status, error_code &ec)
0261     {
0262         if (pid_ <= 0)
0263             return;
0264         if (::kill(pid_, SIGKILL) == -1)
0265             ec = get_last_error();
0266         else
0267             wait(exit_status, ec);
0268     }
0269 
0270     void terminate(native_exit_code_type &exit_status)
0271     {
0272         if (pid_ <= 0)
0273             return;
0274         error_code ec;
0275         terminate(exit_status, ec);
0276         if (ec)
0277             detail::throw_error(ec, "terminate");
0278     }
0279 
0280     bool running(native_exit_code_type &exit_code, error_code & ec)
0281     {
0282         if (pid_ <= 0)
0283             return false;
0284         int code = 0;
0285         int res = ::waitpid(pid_, &code, WNOHANG);
0286         if (res == -1)
0287             ec = get_last_error();
0288         else if (res == 0)
0289             return true;
0290         else
0291         {
0292             ec.clear();
0293             exit_code = code;
0294         }
0295         return false;
0296     }
0297 
0298     bool running(native_exit_code_type &exit_code)
0299     {
0300         if (pid_ <= 0)
0301             return false;
0302 
0303         error_code ec;
0304         bool res = running(exit_code, ec);
0305         if (ec)
0306             detail::throw_error(ec, "is_running");
0307         return res;
0308     }
0309 
0310     bool is_open() const
0311     {
0312         return pid_ != -1;
0313     }
0314 
0315   private:
0316     template<typename>
0317     friend
0318     struct basic_process_handle_fd_or_signal;
0319     pid_type pid_ = -1;
0320     net::posix::basic_stream_descriptor<Executor> descriptor_;
0321 #if !defined(BOOST_PROCESS_V2_DISABLE_SIGNALSET)
0322     net::basic_signal_set<Executor> signal_set_{descriptor_.get_executor(), SIGCHLD};
0323 #else
0324     int signal_set_;
0325 #endif
0326     struct async_wait_op_
0327     {
0328         net::posix::basic_descriptor<Executor> &descriptor;
0329 #if !defined(BOOST_PROCESS_V2_DISABLE_SIGNALSET)
0330         net::basic_signal_set<Executor> &handle;
0331 #else
0332         int dummy;
0333 #endif
0334         pid_type pid_;
0335         native_exit_code_type & exit_code;
0336         bool needs_post = true;
0337 
0338         template<typename Self>
0339         void operator()(Self && self)
0340         {
0341           self.reset_cancellation_state(asio::enable_total_cancellation());
0342           (*this)(std::move(self), error_code{});
0343         }
0344 
0345         template<typename Self>
0346         void operator()(Self &&self, error_code ec, int = 0)
0347         {
0348             int wait_res = -1;
0349             if (pid_ <= 0) // error, complete early
0350                 ec = net::error::bad_descriptor;
0351             else if (process_is_running(exit_code))
0352             {
0353                 wait_res = ::waitpid(pid_, &exit_code, WNOHANG);
0354                 if (wait_res == -1)
0355                     ec = get_last_error();
0356             }
0357 
0358             if (!ec && (wait_res == 0))
0359             {
0360                 if (descriptor.is_open())
0361                 {
0362                   needs_post = false;
0363                   descriptor.async_wait(
0364                       net::posix::descriptor_base::wait_read,
0365                       std::move(self));
0366                   return;
0367                 }
0368                 else
0369                 {
0370 #if !defined(BOOST_PROCESS_V2_DISABLE_SIGNALSET)
0371                   needs_post = false;
0372                   handle.async_wait(std::move(self));
0373                   return;
0374 #else
0375                   BOOST_PROCESS_V2_ASSIGN_EC(ec, net::error::operation_not_supported);
0376 #endif
0377                 }
0378             }
0379 
0380             if (needs_post)
0381             {
0382               auto exec = net::get_associated_immediate_executor(self, descriptor.get_executor());
0383               net::dispatch(exec, net::append(std::move(self), exit_code, ec));
0384             }
0385             else
0386             {
0387               auto exec = net::get_associated_executor(self);
0388               net::dispatch(exec, net::append(std::move(self), exit_code, ec));
0389             }
0390         }
0391         template<typename Self>
0392         void operator()(Self &&self, native_exit_code_type code, error_code ec)
0393         {
0394           self.complete(ec);
0395         }
0396     };
0397  public:
0398     template<BOOST_PROCESS_V2_COMPLETION_TOKEN_FOR(void(error_code))
0399              WaitHandler = net::default_completion_token_t<executor_type>>
0400     auto async_wait(native_exit_code_type & exit_code,
0401                     WaitHandler &&handler = net::default_completion_token_t<executor_type>())
0402       -> decltype(net::async_compose<WaitHandler, void(error_code)>(
0403                   async_wait_op_{descriptor_, signal_set_, pid_, exit_code}, handler, descriptor_))
0404     {
0405         return net::async_compose<WaitHandler, void(error_code)>(
0406                 async_wait_op_{descriptor_, signal_set_, pid_, exit_code}, handler, descriptor_);
0407     }
0408 };
0409 }
0410 
0411 BOOST_PROCESS_V2_END_NAMESPACE
0412 
0413 #endif //BOOST_PROCESS_HANDLE_FD_OR_SIGNAL_HPP