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