Back to home page

EIC code displayed by LXR

 
 

    


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

0001 // Copyright (c) 2022 Klemens D. Morgenstern
0002 //
0003 // Distributed under the Boost Software License, Version 1.0. (See accompanying
0004 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0005 #ifndef BOOST_PROCESS_V2_DETAIL_PROCESS_HANDLE_SIGNAL_HPP
0006 #define BOOST_PROCESS_V2_DETAIL_PROCESS_HANDLE_SIGNAL_HPP
0007 
0008 #include <boost/process/v2/detail/config.hpp>
0009 
0010 #include <sys/types.h>
0011 #include <sys/wait.h>
0012 
0013 #include <boost/process/v2/detail/last_error.hpp>
0014 #include <boost/process/v2/detail/throw_error.hpp>
0015 #include <boost/process/v2/exit_code.hpp>
0016 #include <boost/process/v2/pid.hpp>
0017 
0018 #if defined(BOOST_PROCESS_V2_STANDALONE)
0019 #include <asio/any_io_executor.hpp>
0020 #include <asio/compose.hpp>
0021 #include <asio/dispatch.hpp>
0022 #include <asio/post.hpp>
0023 #include <asio/signal_set.hpp>
0024 #else
0025 #include <boost/asio/any_io_executor.hpp>
0026 #include <boost/asio/compose.hpp>
0027 #include <boost/asio/dispatch.hpp>
0028 #include <boost/asio/post.hpp>
0029 #include <boost/asio/signal_set.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_signal
0039 {
0040     struct native_handle_type
0041     {
0042          native_handle_type() = delete;
0043          native_handle_type(const native_handle_type & ) = delete;
0044         ~native_handle_type() = default;
0045     };
0046 
0047     typedef Executor executor_type;
0048 
0049     executor_type get_executor()
0050     { return signal_set_.get_executor(); }
0051 
0052     /// Rebinds the process_handle to another executor.
0053     template<typename Executor1>
0054     struct rebind_executor
0055     {
0056         /// The socket type when rebound to the specified executor.
0057         typedef basic_process_handle_signal<Executor1> other;
0058     };
0059 
0060     template<typename ExecutionContext>
0061     basic_process_handle_signal(ExecutionContext &context,
0062                          typename std::enable_if<
0063                                  std::is_convertible<ExecutionContext &,
0064                                          BOOST_PROCESS_V2_ASIO_NAMESPACE::execution_context &>::value
0065                          >::type * = nullptr)
0066             : pid_(-1), signal_set_(context, SIGCHLD)
0067     {
0068     }
0069 
0070     basic_process_handle_signal(Executor executor)
0071             : pid_(-1), signal_set_(executor, SIGCHLD)
0072     {
0073     }
0074 
0075     basic_process_handle_signal(Executor executor, pid_type pid)
0076             : pid_(pid), signal_set_(executor, SIGCHLD)
0077     {
0078     }
0079 
0080     basic_process_handle_signal(basic_process_handle_signal && handle)
0081     : pid_(handle.pid_), signal_set_(handle.signal_set_.get_executor(), SIGCHLD)
0082     {
0083         handle.pid_ = -1;
0084     }
0085 
0086     basic_process_handle_signal& operator=(basic_process_handle_signal && handle)
0087     {
0088         pid_ = handle.id();
0089         signal_set_.~basic_signal_set();
0090         using ss = BOOST_PROCESS_V2_ASIO_NAMESPACE::basic_signal_set<Executor>;
0091         new (&signal_set_) ss(handle.get_executor(), SIGCHLD);
0092         handle.pid_ = -1;
0093         return *this;
0094     }
0095 
0096 
0097     template<typename Executor1>
0098     basic_process_handle_signal(basic_process_handle_signal<Executor1> && handle)
0099     : pid_(handle.pid_), signal_set_(Executor1(handle.signal_set_.get_executor()), SIGCHLD)
0100     {
0101         handle.pid_ = -1;
0102     }
0103 
0104     pid_type id() const { return pid_; }
0105     native_handle_type native_handle() {return {};}
0106 
0107     void terminate_if_running(error_code &)
0108     {
0109          terminate_if_running();
0110     }
0111 
0112     void terminate_if_running()
0113     {
0114         if (pid_ <= 0)
0115             return;
0116         if (::waitpid(pid_, nullptr, WNOHANG) == 0)
0117         {
0118             ::kill(pid_, SIGKILL);
0119             ::waitpid(pid_, nullptr, 0);
0120         }
0121     }
0122 
0123     void wait(native_exit_code_type &exit_status, error_code &ec)
0124     {
0125         if (pid_ <= 0)
0126             return;
0127         while (::waitpid(pid_, &exit_status, 0) < 0)
0128         {
0129             if (errno != EINTR)
0130             {
0131                 ec = get_last_error();
0132                 break;
0133             }      
0134         }
0135     }
0136 
0137     void wait(native_exit_code_type &exit_status)
0138     {
0139         if (pid_ <= 0)
0140             return;
0141         error_code ec;
0142         wait(exit_status, ec);
0143         if (ec)
0144             detail::throw_error(ec, "wait(pid)");
0145     }
0146 
0147     void interrupt(error_code &ec)
0148     {
0149         if (pid_ <= 0)
0150             return;
0151         if (::kill(pid_, SIGTERM) == -1)
0152             ec = get_last_error();
0153     }
0154 
0155     void interrupt()
0156     {
0157         if (pid_ <= 0)
0158             return;
0159         error_code ec;
0160         interrupt(ec);
0161         if (ec)
0162             detail::throw_error(ec, "interrupt");
0163     }
0164 
0165     void request_exit(error_code &ec)
0166     {
0167         if (pid_ <= 0)
0168             return;
0169         if (::kill(pid_, SIGTERM) == -1)
0170             ec = get_last_error();
0171     }
0172 
0173     void request_exit()
0174     {
0175         if (pid_ <= 0)
0176             return;
0177         error_code ec;
0178         request_exit(ec);
0179         if (ec)
0180             detail::throw_error(ec, "request_exit");
0181     }
0182 
0183     void suspend()
0184     {
0185         if (pid_ <= 0)
0186             return;
0187         error_code ec;
0188         suspend(ec);
0189         if (ec)
0190             detail::throw_error(ec, "suspend");
0191     }
0192 
0193     void suspend(error_code &ec)
0194     {
0195         if (pid_ <= 0)
0196             return;
0197         if (::kill(pid_, SIGCONT) == -1)
0198             ec = get_last_error();
0199     }
0200 
0201     void resume()
0202     {
0203         if (pid_ <= 0)
0204             return;
0205         error_code ec;
0206         resume(ec);
0207         if (ec)
0208             detail::throw_error(ec, "resume");
0209     }
0210 
0211     void resume(error_code &ec)
0212     {
0213         if (pid_ <= 0)
0214             return;
0215         if (::kill(pid_, SIGTERM) == -1)
0216             ec = get_last_error();
0217     }
0218 
0219     void terminate(native_exit_code_type &exit_status, error_code &ec)
0220     {
0221         if (pid_ <= 0)
0222             return;
0223         if (::kill(pid_, SIGKILL) == -1)
0224             ec = get_last_error();
0225     }
0226 
0227     void terminate(native_exit_code_type &exit_status)
0228     {
0229         if (pid_ <= 0)
0230             return;
0231         error_code ec;
0232         terminate(exit_status, ec);
0233         if (ec)
0234             detail::throw_error(ec, "terminate");
0235     }
0236 
0237     bool running(native_exit_code_type &exit_code, error_code & ec)
0238     {
0239         if (pid_ <= 0)
0240             return false;
0241         int code = 0;
0242         int res = ::waitpid(pid_, &code, WNOHANG);
0243         if (res == -1)
0244             ec = get_last_error();
0245         
0246         if (res == 0)
0247             return true;
0248         else
0249         {
0250             exit_code = code;
0251             return false;
0252         }
0253     }
0254 
0255     bool running(native_exit_code_type &exit_code)
0256     {
0257         if (pid_ <= 0)
0258             return false;
0259 
0260         error_code ec;
0261         bool res = running(exit_code, ec);
0262         if (ec)
0263             detail::throw_error(ec, "is_running");
0264         return res;
0265     }
0266 
0267     bool is_open() const
0268     {
0269         return pid_ != -1;
0270     }
0271 
0272     template<BOOST_PROCESS_V2_COMPLETION_TOKEN_FOR(void(error_code, int))
0273     WaitHandler BOOST_PROCESS_V2_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
0274     BOOST_PROCESS_V2_INITFN_AUTO_RESULT_TYPE(WaitHandler, void (error_code, native_exit_code_type))
0275     async_wait(WaitHandler &&handler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
0276     {
0277         return BOOST_PROCESS_V2_ASIO_NAMESPACE::async_compose<WaitHandler, void(error_code, native_exit_code_type)>(
0278                 async_wait_op_{signal_set_, pid_}, handler, signal_set_);
0279     }
0280 
0281   private:
0282     template<typename>
0283     friend struct basic_process_handle_signal;
0284     pid_type pid_ = -1;
0285     BOOST_PROCESS_V2_ASIO_NAMESPACE::basic_signal_set<Executor> signal_set_;
0286 
0287     struct async_wait_op_
0288     {
0289         BOOST_PROCESS_V2_ASIO_NAMESPACE::basic_signal_set<Executor> &handle;
0290         pid_type pid_;
0291         
0292         template<typename Self>
0293         void operator()(Self &&self)
0294         {
0295             handle.async_wait(std::move(self));
0296             handle.cancel();
0297             // we cancel so we end up on the signal-sets executor 
0298         }
0299 
0300         template<typename Self>
0301         void operator()(Self &&self, error_code ec, int sig)
0302         {
0303             if (ec == BOOST_PROCESS_V2_ASIO_NAMESPACE::error::operation_aborted && 
0304                 self.get_cancellation_state().cancelled() 
0305                     == BOOST_PROCESS_V2_ASIO_NAMESPACE::cancellation_type::none)
0306                 ec.clear();
0307 
0308             native_exit_code_type exit_code = -1;
0309             int wait_res = -1;
0310 
0311             if (pid_ <= 0) // error, complete early
0312                 ec = BOOST_PROCESS_V2_ASIO_NAMESPACE::error::bad_descriptor;
0313             else if (!ec)
0314             {
0315                 wait_res = ::waitpid(pid_, &exit_code, WNOHANG);
0316                 if (wait_res == -1)
0317                     ec = get_last_error();
0318             }
0319 
0320             if (!ec && (wait_res == 0))
0321             {
0322                 handle.async_wait(std::move(self));
0323                 return;
0324             }
0325 
0326             struct completer
0327             {
0328                 error_code ec;
0329                 native_exit_code_type code;
0330                 typename std::decay<Self>::type self;
0331 
0332                 void operator()()
0333                 {
0334                     self.complete(ec, code);
0335                 }
0336             };
0337 
0338             const auto exec = self.get_executor();
0339             BOOST_PROCESS_V2_ASIO_NAMESPACE::dispatch(exec, completer{ec, exit_code, std::move(self)});
0340         }
0341     };
0342 };
0343 
0344 }
0345 
0346 
0347 BOOST_PROCESS_V2_END_NAMESPACE
0348 
0349 
0350 #endif //BOOST_PROCESS_V2_DETAIL_PROCESS_HANDLE_SIGNAL_HPP