Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:50:10

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