system.hpp 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  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 <type_traits>
  23. #include <mutex>
  24. #include <condition_variable>
  25. #if defined(BOOST_POSIX_API)
  26. #include <boost/process/posix.hpp>
  27. #endif
  28. namespace boost {
  29. namespace process {
  30. namespace detail
  31. {
  32. struct system_impl_success_check : handler
  33. {
  34. bool succeeded = false;
  35. template<typename Exec>
  36. void on_success(Exec &) { succeeded = true; }
  37. };
  38. template<typename IoService, typename ...Args>
  39. inline int system_impl(
  40. std::true_type, /*needs ios*/
  41. std::true_type, /*has io_context*/
  42. Args && ...args)
  43. {
  44. IoService & ios = ::boost::process::detail::get_io_context_var(args...);
  45. system_impl_success_check check;
  46. std::atomic_bool exited{false};
  47. child c(std::forward<Args>(args)...,
  48. check,
  49. ::boost::process::on_exit(
  50. [&](int, const std::error_code&)
  51. {
  52. ios.post([&]{exited.store(true);});
  53. }));
  54. if (!c.valid() || !check.succeeded)
  55. return -1;
  56. while (!exited.load())
  57. ios.poll();
  58. return c.exit_code();
  59. }
  60. template<typename IoService, typename ...Args>
  61. inline int system_impl(
  62. std::true_type, /*needs ios */
  63. std::false_type, /*has io_context*/
  64. Args && ...args)
  65. {
  66. IoService ios;
  67. child c(ios, std::forward<Args>(args)...);
  68. if (!c.valid())
  69. return -1;
  70. ios.run();
  71. return c.exit_code();
  72. }
  73. template<typename IoService, typename ...Args>
  74. inline int system_impl(
  75. std::false_type, /*needs ios*/
  76. std::true_type, /*has io_context*/
  77. Args && ...args)
  78. {
  79. child c(std::forward<Args>(args)...);
  80. if (!c.valid())
  81. return -1;
  82. c.wait();
  83. return c.exit_code();
  84. }
  85. template<typename IoService, typename ...Args>
  86. inline int system_impl(
  87. std::false_type, /*has async */
  88. std::false_type, /*has io_context*/
  89. Args && ...args)
  90. {
  91. child c(std::forward<Args>(args)...
  92. #if defined(BOOST_POSIX_API)
  93. ,::boost::process::posix::sig.dfl()
  94. #endif
  95. );
  96. if (!c.valid())
  97. return -1;
  98. c.wait();
  99. return c.exit_code();
  100. }
  101. }
  102. /** Launches a process and waits for its exit.
  103. It works as std::system, though it allows
  104. all the properties boost.process provides. It will execute the process and wait for it's exit; then return the exit_code.
  105. \code{.cpp}
  106. int ret = system("ls");
  107. \endcode
  108. \attention Using this function with synchronous pipes leads to many potential deadlocks.
  109. When using this function with an asynchronous properties and NOT passing an io_context object,
  110. the system function will create one and run it. When the io_context is passed to the function,
  111. the system function will check if it is active, and call the io_context::run function if not.
  112. */
  113. template<typename ...Args>
  114. inline int system(Args && ...args)
  115. {
  116. typedef typename ::boost::process::detail::needs_io_context<Args...>::type
  117. need_ios;
  118. typedef typename ::boost::process::detail::has_io_context<Args...>::type
  119. has_ios;
  120. return ::boost::process::detail::system_impl<boost::asio::io_context>(
  121. need_ios(), has_ios(),
  122. std::forward<Args>(args)...);
  123. }
  124. }}
  125. #endif