Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:50: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     }
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) // error, complete early
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 //BOOST_PROCESS_HANDLE_FD_OR_SIGNAL_HPP