// Copyright (c) 2022 Klemens D. Morgenstern // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_PROCESS_V2_POSIX_VFORK_LAUNCHER_HPP #define BOOST_PROCESS_V2_POSIX_VFORK_LAUNCHER_HPP #include #include BOOST_PROCESS_V2_BEGIN_NAMESPACE namespace posix { /// A launcher using vfork instead of fork. struct vfork_launcher : default_launcher { vfork_launcher() = default; template auto operator()(ExecutionContext & context, const typename std::enable_if::value, filesystem::path >::type & executable, Args && args, Inits && ... inits ) -> basic_process { error_code ec; auto proc = (*this)(context, ec, executable, std::forward(args), std::forward(inits)...); if (ec) asio::detail::throw_error(ec, "default_launcher"); return proc; } template auto operator()(ExecutionContext & context, error_code & ec, const typename std::enable_if::value, filesystem::path >::type & executable, Args && args, Inits && ... inits ) -> basic_process { return (*this)(context.get_executor(), executable, std::forward(args), std::forward(inits)...); } template auto operator()(Executor exec, const typename std::enable_if< BOOST_PROCESS_V2_ASIO_NAMESPACE::execution::is_executor::value || BOOST_PROCESS_V2_ASIO_NAMESPACE::is_executor::value, filesystem::path >::type & executable, Args && args, Inits && ... inits ) -> basic_process { error_code ec; auto proc = (*this)(std::move(exec), ec, executable, std::forward(args), std::forward(inits)...); if (ec) asio::detail::throw_error(ec, "default_launcher"); return proc; } template auto operator()(Executor exec, error_code & ec, const typename std::enable_if< BOOST_PROCESS_V2_ASIO_NAMESPACE::execution::is_executor::value || BOOST_PROCESS_V2_ASIO_NAMESPACE::is_executor::value, filesystem::path >::type & executable, Args && args, Inits && ... inits ) -> basic_process { auto argv = this->build_argv_(executable, std::forward(args)); ec = detail::on_setup(*this, executable, argv, inits ...); if (ec) { detail::on_error(*this, executable, argv, ec, inits...); return basic_process(exec); } auto & ctx = BOOST_PROCESS_V2_ASIO_NAMESPACE::query( exec, BOOST_PROCESS_V2_ASIO_NAMESPACE::execution::context); ctx.notify_fork(BOOST_PROCESS_V2_ASIO_NAMESPACE::execution_context::fork_prepare); pid = ::vfork(); if (pid == -1) { ctx.notify_fork(BOOST_PROCESS_V2_ASIO_NAMESPACE::execution_context::fork_parent); detail::on_fork_error(*this, executable, argv, ec, inits...); detail::on_error(*this, executable, argv, ec, inits...); ec.assign(errno, system_category()); return basic_process{exec}; } else if (pid == 0) { ctx.notify_fork(BOOST_PROCESS_V2_ASIO_NAMESPACE::execution_context::fork_child); ec = detail::on_exec_setup(*this, executable, argv, inits...); if (!ec) close_all_fds(ec); if (!ec) ::execve(executable.c_str(), const_cast(argv), const_cast(env)); ec.assign(errno, system_category()); detail::on_exec_error(*this, executable, argv, ec, inits...); ::exit(EXIT_FAILURE); return basic_process{exec}; } ctx.notify_fork(BOOST_PROCESS_V2_ASIO_NAMESPACE::execution_context::fork_parent); if (ec) { detail::on_error(*this, executable, argv, ec, inits...); return basic_process{exec}; } basic_process proc(exec, pid); detail::on_success(*this, executable, argv, ec, inits...); return proc; } }; } BOOST_PROCESS_V2_END_NAMESPACE #endif //BOOST_PROCESS_V2_POSIX_VFORK_LAUNCHER_HPP