Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-08-20 08:59:21

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_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 /// A launcher using `pipe_fork`. Default on FreeBSD
0018 struct pipe_fork_launcher : default_launcher
0019 {
0020     /// The file descriptor of the subprocess. Set after fork.
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 //BOOST_PROCESS_V2_POSIX_PIPE_FORK_LAUNCHER_HPP