vfork_launcher.hpp 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. // Copyright (c) 2022 Klemens D. Morgenstern
  2. //
  3. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  4. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  5. #ifndef BOOST_PROCESS_V2_POSIX_VFORK_LAUNCHER_HPP
  6. #define BOOST_PROCESS_V2_POSIX_VFORK_LAUNCHER_HPP
  7. #include <boost/process/v2/posix/default_launcher.hpp>
  8. #include <unistd.h>
  9. BOOST_PROCESS_V2_BEGIN_NAMESPACE
  10. namespace posix
  11. {
  12. /// A launcher using vfork instead of fork.
  13. struct vfork_launcher : default_launcher
  14. {
  15. vfork_launcher() = default;
  16. template<typename ExecutionContext, typename Args, typename ... Inits>
  17. auto operator()(ExecutionContext & context,
  18. const typename std::enable_if<std::is_convertible<
  19. ExecutionContext&, BOOST_PROCESS_V2_ASIO_NAMESPACE::execution_context&>::value,
  20. filesystem::path >::type & executable,
  21. Args && args,
  22. Inits && ... inits ) -> basic_process<typename ExecutionContext::executor_type>
  23. {
  24. error_code ec;
  25. auto proc = (*this)(context, ec, executable, std::forward<Args>(args), std::forward<Inits>(inits)...);
  26. if (ec)
  27. v2::detail::throw_error(ec, "default_launcher");
  28. return proc;
  29. }
  30. template<typename ExecutionContext, typename Args, typename ... Inits>
  31. auto operator()(ExecutionContext & context,
  32. error_code & ec,
  33. const typename std::enable_if<std::is_convertible<
  34. ExecutionContext&, BOOST_PROCESS_V2_ASIO_NAMESPACE::execution_context&>::value,
  35. filesystem::path >::type & executable,
  36. Args && args,
  37. Inits && ... inits ) -> basic_process<typename ExecutionContext::executor_type>
  38. {
  39. return (*this)(context.get_executor(), ec, executable, std::forward<Args>(args), std::forward<Inits>(inits)...);
  40. }
  41. template<typename Executor, typename Args, typename ... Inits>
  42. auto operator()(Executor exec,
  43. const typename std::enable_if<
  44. BOOST_PROCESS_V2_ASIO_NAMESPACE::execution::is_executor<Executor>::value ||
  45. BOOST_PROCESS_V2_ASIO_NAMESPACE::is_executor<Executor>::value,
  46. filesystem::path >::type & executable,
  47. Args && args,
  48. Inits && ... inits ) -> basic_process<Executor>
  49. {
  50. error_code ec;
  51. auto proc = (*this)(std::move(exec), ec, executable, std::forward<Args>(args), std::forward<Inits>(inits)...);
  52. if (ec)
  53. v2::detail::throw_error(ec, "default_launcher");
  54. return proc;
  55. }
  56. template<typename Executor, typename Args, typename ... Inits>
  57. auto operator()(Executor exec,
  58. error_code & ec,
  59. const typename std::enable_if<
  60. BOOST_PROCESS_V2_ASIO_NAMESPACE::execution::is_executor<Executor>::value ||
  61. BOOST_PROCESS_V2_ASIO_NAMESPACE::is_executor<Executor>::value,
  62. filesystem::path >::type & executable,
  63. Args && args,
  64. Inits && ... inits ) -> basic_process<Executor>
  65. {
  66. auto argv = this->build_argv_(executable, std::forward<Args>(args));
  67. ec = detail::on_setup(*this, executable, argv, inits ...);
  68. if (ec)
  69. {
  70. detail::on_error(*this, executable, argv, ec, inits...);
  71. return basic_process<Executor>(exec);
  72. }
  73. auto & ctx = BOOST_PROCESS_V2_ASIO_NAMESPACE::query(
  74. exec, BOOST_PROCESS_V2_ASIO_NAMESPACE::execution::context);
  75. ctx.notify_fork(BOOST_PROCESS_V2_ASIO_NAMESPACE::execution_context::fork_prepare);
  76. pid = ::vfork();
  77. if (pid == -1)
  78. {
  79. ctx.notify_fork(BOOST_PROCESS_V2_ASIO_NAMESPACE::execution_context::fork_parent);
  80. detail::on_fork_error(*this, executable, argv, ec, inits...);
  81. detail::on_error(*this, executable, argv, ec, inits...);
  82. BOOST_PROCESS_V2_ASSIGN_EC(ec, errno, system_category())
  83. return basic_process<Executor>{exec};
  84. }
  85. else if (pid == 0)
  86. {
  87. ec = detail::on_exec_setup(*this, executable, argv, inits...);
  88. if (!ec)
  89. close_all_fds(ec);
  90. if (!ec)
  91. ::execve(executable.c_str(), const_cast<char * const *>(argv), const_cast<char * const *>(env));
  92. BOOST_PROCESS_V2_ASSIGN_EC(ec, errno, system_category())
  93. detail::on_exec_error(*this, executable, argv, ec, inits...);
  94. ::_exit(EXIT_FAILURE);
  95. return basic_process<Executor>{exec};
  96. }
  97. ctx.notify_fork(BOOST_PROCESS_V2_ASIO_NAMESPACE::execution_context::fork_parent);
  98. if (ec)
  99. {
  100. detail::on_error(*this, executable, argv, ec, inits...);
  101. return basic_process<Executor>{exec};
  102. }
  103. basic_process<Executor> proc(exec, pid);
  104. detail::on_success(*this, executable, argv, ec, inits...);
  105. return proc;
  106. }
  107. };
  108. }
  109. BOOST_PROCESS_V2_END_NAMESPACE
  110. #endif //BOOST_PROCESS_V2_POSIX_VFORK_LAUNCHER_HPP