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