system.hpp 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. // Copyright (c) 2006, 2007 Julio M. Merino Vidal
  2. // Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
  3. // Copyright (c) 2009 Boris Schaeling
  4. // Copyright (c) 2010 Felipe Tanus, Boris Schaeling
  5. // Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
  6. // Copyright (c) 2016 Klemens D. Morgenstern
  7. //
  8. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  9. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  10. /**
  11. * \file boost/process/system.hpp
  12. *
  13. * Defines a system function.
  14. */
  15. #ifndef BOOST_PROCESS_SYSTEM_HPP
  16. #define BOOST_PROCESS_SYSTEM_HPP
  17. #include <boost/process/detail/config.hpp>
  18. #include <boost/process/detail/on_exit.hpp>
  19. #include <boost/process/child.hpp>
  20. #include <boost/process/detail/async_handler.hpp>
  21. #include <boost/process/detail/execute_impl.hpp>
  22. #include <boost/asio/post.hpp>
  23. #include <type_traits>
  24. #include <mutex>
  25. #include <condition_variable>
  26. #if defined(BOOST_POSIX_API)
  27. #include <boost/process/posix.hpp>
  28. #endif
  29. namespace boost {
  30. namespace process {
  31. namespace detail
  32. {
  33. struct system_impl_success_check : handler
  34. {
  35. bool succeeded = false;
  36. template<typename Exec>
  37. void on_success(Exec &) { succeeded = true; }
  38. };
  39. template<typename IoService, typename ...Args>
  40. inline int system_impl(
  41. std::true_type, /*needs ios*/
  42. std::true_type, /*has io_context*/
  43. Args && ...args)
  44. {
  45. IoService & ios = ::boost::process::detail::get_io_context_var(args...);
  46. system_impl_success_check check;
  47. std::atomic_bool exited{false};
  48. child c(std::forward<Args>(args)...,
  49. check,
  50. ::boost::process::on_exit(
  51. [&](int, const std::error_code&)
  52. {
  53. boost::asio::post(ios.get_executor(), [&]{exited.store(true);});
  54. }));
  55. if (!c.valid() || !check.succeeded)
  56. return -1;
  57. while (!exited.load())
  58. ios.poll();
  59. return c.exit_code();
  60. }
  61. template<typename IoService, typename ...Args>
  62. inline int system_impl(
  63. std::true_type, /*needs ios */
  64. std::false_type, /*has io_context*/
  65. Args && ...args)
  66. {
  67. IoService ios;
  68. child c(ios, std::forward<Args>(args)...);
  69. if (!c.valid())
  70. return -1;
  71. ios.run();
  72. if (c.running())
  73. c.wait();
  74. return c.exit_code();
  75. }
  76. template<typename IoService, typename ...Args>
  77. inline int system_impl(
  78. std::false_type, /*needs ios*/
  79. std::true_type, /*has io_context*/
  80. Args && ...args)
  81. {
  82. child c(std::forward<Args>(args)...);
  83. if (!c.valid())
  84. return -1;
  85. c.wait();
  86. return c.exit_code();
  87. }
  88. template<typename IoService, typename ...Args>
  89. inline int system_impl(
  90. std::false_type, /*has async */
  91. std::false_type, /*has io_context*/
  92. Args && ...args)
  93. {
  94. child c(std::forward<Args>(args)...
  95. #if defined(BOOST_POSIX_API)
  96. ,::boost::process::posix::sig.dfl()
  97. #endif
  98. );
  99. if (!c.valid())
  100. return -1;
  101. c.wait();
  102. return c.exit_code();
  103. }
  104. }
  105. /** Launches a process and waits for its exit.
  106. It works as std::system, though it allows
  107. all the properties boost.process provides. It will execute the process and wait for it's exit; then return the exit_code.
  108. \code{.cpp}
  109. int ret = system("ls");
  110. \endcode
  111. \attention Using this function with synchronous pipes leads to many potential deadlocks.
  112. When using this function with an asynchronous properties and NOT passing an io_context object,
  113. the system function will create one and run it. When the io_context is passed to the function,
  114. the system function will check if it is active, and call the io_context::run function if not.
  115. */
  116. template<typename ...Args>
  117. inline int system(Args && ...args)
  118. {
  119. typedef typename ::boost::process::detail::needs_io_context<Args...>::type
  120. need_ios;
  121. typedef typename ::boost::process::detail::has_io_context<Args...>::type
  122. has_ios;
  123. return ::boost::process::detail::system_impl<boost::asio::io_context>(
  124. need_ios(), has_ios(),
  125. std::forward<Args>(args)...);
  126. }
  127. }}
  128. #endif