]>
Commit | Line | Data |
---|---|---|
b32b8144 FG |
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> | |
92f5a8d4 | 25 | #include <boost/asio/post.hpp> |
b32b8144 FG |
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> | |
46 | void on_success(Exec &) { succeeded = true; } | |
47 | }; | |
48 | ||
49 | template<typename IoService, typename ...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 | { | |
92f5a8d4 | 66 | boost::asio::post(ios.get_executor(), [&]{exited.store(true);}); |
b32b8144 FG |
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> | |
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(); | |
92f5a8d4 TL |
89 | if (c.running()) |
90 | c.wait(); | |
b32b8144 FG |
91 | return c.exit_code(); |
92 | } | |
93 | ||
94 | ||
95 | template<typename IoService, typename ...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> | |
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> | |
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 |