vfork_launcher.hpp 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  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&, net::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&, net::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. net::execution::is_executor<Executor>::value ||
  45. net::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. net::execution::is_executor<Executor>::value ||
  61. net::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 = net::query(exec, net::execution::context);
  74. #if !defined(BOOST_PROCESS_V2_DISABLE_NOTIFY_FORK)
  75. ctx.notify_fork(net::execution_context::fork_prepare);
  76. #endif
  77. pid = ::vfork();
  78. if (pid == -1)
  79. {
  80. #if !defined(BOOST_PROCESS_V2_DISABLE_NOTIFY_FORK)
  81. ctx.notify_fork(net::execution_context::fork_parent);
  82. #endif
  83. detail::on_fork_error(*this, executable, argv, ec, inits...);
  84. detail::on_error(*this, executable, argv, ec, inits...);
  85. BOOST_PROCESS_V2_ASSIGN_EC(ec, errno, system_category());
  86. return basic_process<Executor>{exec};
  87. }
  88. else if (pid == 0)
  89. {
  90. ec = detail::on_exec_setup(*this, executable, argv, inits...);
  91. if (!ec)
  92. close_all_fds(ec);
  93. if (!ec)
  94. ::execve(executable.c_str(), const_cast<char * const *>(argv), const_cast<char * const *>(env));
  95. BOOST_PROCESS_V2_ASSIGN_EC(ec, errno, system_category());
  96. detail::on_exec_error(*this, executable, argv, ec, inits...);
  97. ::_exit(EXIT_FAILURE);
  98. return basic_process<Executor>{exec};
  99. }
  100. #if !defined(BOOST_PROCESS_V2_DISABLE_NOTIFY_FORK)
  101. ctx.notify_fork(net::execution_context::fork_parent);
  102. #endif
  103. if (ec)
  104. {
  105. detail::on_error(*this, executable, argv, ec, inits...);
  106. do { ::waitpid(pid, nullptr, 0); } while (errno == EINTR);
  107. return basic_process<Executor>{exec};
  108. }
  109. basic_process<Executor> proc(exec, pid);
  110. detail::on_success(*this, executable, argv, ec, inits...);
  111. return proc;
  112. }
  113. };
  114. }
  115. BOOST_PROCESS_V2_END_NAMESPACE
  116. #endif //BOOST_PROCESS_V2_POSIX_VFORK_LAUNCHER_HPP