Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-15 08:50:44

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