Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-07-11 08:25:09

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_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     /// Rebinds the process_handle to another executor.
0048     template<typename Executor1>
0049     struct rebind_executor
0050     {
0051         /// The socket type when rebound to the specified executor.
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) // error, complete early
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 //BOOST_PROCESS_HANDLE_FD_OR_SIGNAL_HPP