Back to home page

EIC code displayed by LXR

 
 

    


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

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&, BOOST_PROCESS_V2_ASIO_NAMESPACE::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&, BOOST_PROCESS_V2_ASIO_NAMESPACE::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(), 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                             BOOST_PROCESS_V2_ASIO_NAMESPACE::execution::is_executor<Executor>::value ||
0059                             BOOST_PROCESS_V2_ASIO_NAMESPACE::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                             BOOST_PROCESS_V2_ASIO_NAMESPACE::execution::is_executor<Executor>::value ||
0078                             BOOST_PROCESS_V2_ASIO_NAMESPACE::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 = BOOST_PROCESS_V2_ASIO_NAMESPACE::query(
0105                     exec, BOOST_PROCESS_V2_ASIO_NAMESPACE::execution::context);
0106             ctx.notify_fork(BOOST_PROCESS_V2_ASIO_NAMESPACE::execution_context::fork_prepare);
0107             pid = ::pdfork(&fd, PD_DAEMON | PD_CLOEXEC);
0108             if (pid == -1)
0109             {
0110                 ctx.notify_fork(BOOST_PROCESS_V2_ASIO_NAMESPACE::execution_context::fork_parent);
0111                 detail::on_fork_error(*this, executable, argv, ec, inits...);
0112                 detail::on_error(*this, executable, argv, ec, inits...);
0113 
0114                 BOOST_PROCESS_V2_ASSIGN_EC(ec, errno, system_category())
0115                 return basic_process<Executor>{exec};
0116             }
0117             else if (pid == 0)
0118             {
0119                 ctx.notify_fork(BOOST_PROCESS_V2_ASIO_NAMESPACE::execution_context::fork_child);
0120                 ::close(pg.p[0]);
0121 
0122                 ec = detail::on_exec_setup(*this, executable, argv, inits...);
0123                 if (!ec)
0124                 {
0125                     close_all_fds(ec);
0126                 }                
0127                 if (!ec)
0128                     ::execve(executable.c_str(), const_cast<char * const *>(argv), const_cast<char * const *>(env));
0129 
0130                 default_launcher::ignore_unused(::write(pg.p[1], &errno, sizeof(int)));
0131                 BOOST_PROCESS_V2_ASSIGN_EC(ec, errno, system_category())
0132                 detail::on_exec_error(*this, executable, argv, ec, inits...);
0133                 ::exit(EXIT_FAILURE);
0134                 return basic_process<Executor>{exec};
0135             }
0136             ctx.notify_fork(BOOST_PROCESS_V2_ASIO_NAMESPACE::execution_context::fork_parent);
0137             ::close(pg.p[1]);
0138             pg.p[1] = -1;
0139             int child_error{0};
0140             int count = -1;
0141             while ((count = ::read(pg.p[0], &child_error, sizeof(child_error))) == -1)
0142             {
0143                 int err = errno;
0144                 if ((err != EAGAIN) && (err != EINTR))
0145                 {
0146                     BOOST_PROCESS_V2_ASSIGN_EC(ec, err, system_category())
0147                     break;
0148                 }
0149             }
0150             if (count != 0)
0151                 BOOST_PROCESS_V2_ASSIGN_EC(ec, child_error, system_category())
0152 
0153             if (ec)
0154             {
0155                 detail::on_error(*this, executable, argv, ec, inits...);
0156                 return basic_process<Executor>{exec};
0157             }
0158         }
0159         basic_process<Executor> proc(exec, pid, fd);
0160         detail::on_success(*this, executable, argv, ec, inits...);
0161         return proc;
0162     }
0163 };
0164 
0165 
0166 }
0167 
0168 BOOST_PROCESS_V2_END_NAMESPACE
0169 
0170 
0171 #endif //BOOST_PROCESS_V2_POSIX_PDFORK_LAUNCHER_HPP