File indexing completed on 2025-09-15 08:50:44
0001
0002
0003
0004
0005 #ifndef BOOST_PROCESS_V2_POSIX_PDFORK_LAUNCHER_HPP
0006 #define BOOST_PROCESS_V2_POSIX_PDFORK_LAUNCHER_HPP
0007
0008 #include <boost/process/v2/posix/default_launcher.hpp>
0009
0010 #include <unistd.h>
0011 #include <sys/procdesc.h>
0012
0013 BOOST_PROCESS_V2_BEGIN_NAMESPACE
0014
0015 namespace posix
0016 {
0017
0018
0019 struct pdfork_launcher : default_launcher
0020 {
0021
0022 int fd;
0023 pdfork_launcher() = default;
0024
0025 template<typename ExecutionContext, typename Args, typename ... Inits>
0026 auto operator()(ExecutionContext & context,
0027 const typename std::enable_if<is_convertible<
0028 ExecutionContext&, net::execution_context&>::value,
0029 filesystem::path >::type & executable,
0030 Args && args,
0031 Inits && ... inits ) -> basic_process<typename ExecutionContext::executor_type>
0032 {
0033 error_code ec;
0034 auto proc = (*this)(context, ec, executable, std::forward<Args>(args), std::forward<Inits>(inits)...);
0035
0036 if (ec)
0037 v2::detail::throw_error(ec, "pdfork_launcher");
0038
0039 return proc;
0040 }
0041
0042
0043 template<typename ExecutionContext, typename Args, typename ... Inits>
0044 auto operator()(ExecutionContext & context,
0045 error_code & ec,
0046 const typename std::enable_if<is_convertible<
0047 ExecutionContext&, net::execution_context&>::value,
0048 filesystem::path >::type & executable,
0049 Args && args,
0050 Inits && ... inits ) -> basic_process<typename ExecutionContext::executor_type>
0051 {
0052 return (*this)(context.get_executor(), ec, executable, std::forward<Args>(args), std::forward<Inits>(inits)...);
0053 }
0054
0055 template<typename Executor, typename Args, typename ... Inits>
0056 auto operator()(Executor exec,
0057 const typename std::enable_if<
0058 net::execution::is_executor<Executor>::value ||
0059 net::is_executor<Executor>::value,
0060 filesystem::path >::type & executable,
0061 Args && args,
0062 Inits && ... inits ) -> basic_process<Executor>
0063 {
0064 error_code ec;
0065 auto proc = (*this)(std::move(exec), ec, executable, std::forward<Args>(args), std::forward<Inits>(inits)...);
0066
0067 if (ec)
0068 v2::detail::throw_error(ec, "pdfork_launcher");
0069
0070 return proc;
0071 }
0072
0073 template<typename Executor, typename Args, typename ... Inits>
0074 auto operator()(Executor exec,
0075 error_code & ec,
0076 const typename std::enable_if<
0077 net::execution::is_executor<Executor>::value ||
0078 net::is_executor<Executor>::value,
0079 filesystem::path >::type & executable,
0080 Args && args,
0081 Inits && ... inits ) -> basic_process<Executor>
0082 {
0083 auto argv = this->build_argv_(executable, std::forward<Args>(args));
0084 {
0085 pipe_guard pg;
0086 if (::pipe(pg.p))
0087 {
0088 BOOST_PROCESS_V2_ASSIGN_EC(ec, errno, system_category());
0089 return basic_process<Executor>{exec};
0090 }
0091 if (::fcntl(pg.p[1], F_SETFD, FD_CLOEXEC))
0092 {
0093 BOOST_PROCESS_V2_ASSIGN_EC(ec, errno, system_category());
0094 return basic_process<Executor>{exec};
0095 }
0096 ec = detail::on_setup(*this, executable, argv, inits ...);
0097 if (ec)
0098 {
0099 detail::on_error(*this, executable, argv, ec, inits...);
0100 return basic_process<Executor>(exec);
0101 }
0102 fd_whitelist.push_back(pg.p[1]);
0103
0104 auto & ctx = net::query(
0105 exec, net::execution::context);
0106 #if !defined(BOOST_PROCESS_V2_DISABLE_NOTIFY_FORK)
0107 ctx.notify_fork(net::execution_context::fork_prepare);
0108 #endif
0109 pid = ::pdfork(&fd, PD_DAEMON | PD_CLOEXEC);
0110 if (pid == -1)
0111 {
0112 #if !defined(BOOST_PROCESS_V2_DISABLE_NOTIFY_FORK)
0113 ctx.notify_fork(net::execution_context::fork_parent);
0114 #endif
0115 detail::on_fork_error(*this, executable, argv, ec, inits...);
0116 detail::on_error(*this, executable, argv, ec, inits...);
0117
0118 BOOST_PROCESS_V2_ASSIGN_EC(ec, errno, system_category());
0119 return basic_process<Executor>{exec};
0120 }
0121 else if (pid == 0)
0122 {
0123 #if !defined(BOOST_PROCESS_V2_DISABLE_NOTIFY_FORK)
0124 ctx.notify_fork(net::execution_context::fork_child);
0125 #endif
0126 ::close(pg.p[0]);
0127
0128 ec = detail::on_exec_setup(*this, executable, argv, inits...);
0129 if (!ec)
0130 {
0131 close_all_fds(ec);
0132 }
0133 if (!ec)
0134 ::execve(executable.c_str(), const_cast<char * const *>(argv), const_cast<char * const *>(env));
0135
0136 default_launcher::ignore_unused(::write(pg.p[1], &errno, sizeof(int)));
0137 BOOST_PROCESS_V2_ASSIGN_EC(ec, errno, system_category());
0138 detail::on_exec_error(*this, executable, argv, ec, inits...);
0139 ::exit(EXIT_FAILURE);
0140 return basic_process<Executor>{exec};
0141 }
0142 #if !defined(BOOST_PROCESS_V2_DISABLE_NOTIFY_FORK)
0143 ctx.notify_fork(net::execution_context::fork_parent);
0144 #endif
0145 ::close(pg.p[1]);
0146 pg.p[1] = -1;
0147 int child_error{0};
0148 int count = -1;
0149 while ((count = ::read(pg.p[0], &child_error, sizeof(child_error))) == -1)
0150 {
0151 int err = errno;
0152 if ((err != EAGAIN) && (err != EINTR))
0153 {
0154 BOOST_PROCESS_V2_ASSIGN_EC(ec, err, system_category());
0155 break;
0156 }
0157 }
0158 if (count != 0)
0159 BOOST_PROCESS_V2_ASSIGN_EC(ec, child_error, system_category());
0160
0161 if (ec)
0162 {
0163 detail::on_error(*this, executable, argv, ec, inits...);
0164 do { ::waitpid(pid, nullptr, 0); } while (errno == EINTR);
0165 return basic_process<Executor>{exec};
0166 }
0167 }
0168 basic_process<Executor> proc(exec, pid, fd);
0169 detail::on_success(*this, executable, argv, ec, inits...);
0170 return proc;
0171 }
0172 };
0173
0174
0175 }
0176
0177 BOOST_PROCESS_V2_END_NAMESPACE
0178
0179
0180 #endif