Imported Upstream version 1.64.0
[platform/upstream/boost.git] / boost / process / detail / posix / async_out.hpp
1 // Copyright (c) 2006, 2007 Julio M. Merino Vidal\r
2 // Copyright (c) 2008 Ilya Sokolov, Boris Schaeling\r
3 // Copyright (c) 2009 Boris Schaeling\r
4 // Copyright (c) 2010 Felipe Tanus, Boris Schaeling\r
5 // Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling\r
6 //\r
7 // Distributed under the Boost Software License, Version 1.0. (See accompanying\r
8 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\r
9
10 #ifndef BOOST_PROCESS_DETAIL_POSIX_ASYNC_OUT_HPP\r
11 #define BOOST_PROCESS_DETAIL_POSIX_ASYNC_OUT_HPP\r
12
13
14 #include <boost/process/detail/posix/handler.hpp>\r
15 #include <boost/asio/posix/stream_descriptor.hpp>\r
16 #include <boost/asio/read.hpp>\r
17 #include <boost/process/async_pipe.hpp>\r
18 #include <istream>\r
19 #include <memory>\r
20 #include <exception>\r
21 #include <future>\r
22
23 namespace boost { namespace process { namespace detail { namespace posix {\r
24
25
26 inline int apply_out_handles(int handle, std::integral_constant<int, 1>, std::integral_constant<int, -1>)\r
27 {\r
28     return ::dup2(handle, STDOUT_FILENO);\r
29 }\r
30
31 inline int apply_out_handles(int handle, std::integral_constant<int, 2>, std::integral_constant<int, -1>)\r
32 {\r
33     return ::dup2(handle, STDERR_FILENO);\r
34 }\r
35
36 inline int apply_out_handles(int handle, std::integral_constant<int, 1>, std::integral_constant<int, 2>)\r
37 {\r
38     if (::dup2(handle, STDOUT_FILENO) == -1)\r
39         return -1;\r
40     if (::dup2(handle, STDERR_FILENO) == -1)\r
41         return -1;\r
42
43     return 0;\r
44 }\r
45
46 template<int p1, int p2, typename Buffer>\r
47 struct async_out_buffer : ::boost::process::detail::posix::handler_base_ext,\r
48                           ::boost::process::detail::posix::require_io_service\r
49 {\r
50     Buffer & buf;\r
51
52     std::shared_ptr<boost::process::async_pipe> pipe;\r
53
54
55     async_out_buffer(Buffer & buf) : buf(buf)\r
56     {\r
57     }\r
58
59     template <typename Executor>\r
60     inline void on_success(Executor &exec)\r
61     {\r
62         auto  pipe              = this->pipe;\r
63         boost::asio::async_read(*pipe, buf,\r
64                 [pipe](const boost::system::error_code&, std::size_t size){});\r
65
66         this->pipe = nullptr;\r
67         std::move(*pipe).sink().close();\r
68     }\r
69
70     template<typename Executor>\r
71     void on_error(Executor &, const std::error_code &) const\r
72     {\r
73         std::move(*pipe).sink().close();\r
74     }\r
75
76     template<typename Executor>\r
77     void on_setup(Executor & exec)\r
78     {\r
79         pipe = std::make_shared<boost::process::async_pipe>(get_io_service(exec.seq));\r
80     }\r
81
82
83     template <typename Executor>\r
84     void on_exec_setup(Executor &exec)\r
85     {\r
86         int res = apply_out_handles(pipe->native_sink(),\r
87                       std::integral_constant<int, p1>(), std::integral_constant<int, p2>());\r
88         if (res == -1)\r
89             exec.set_error(::boost::process::detail::get_last_error(), "dup2() failed");\r
90
91         ::close(pipe->native_sink());\r
92     }\r
93 };\r
94
95
96
97
98 template<int p1, int p2, typename Type>\r
99 struct async_out_future : ::boost::process::detail::posix::handler_base_ext,\r
100                           ::boost::process::detail::posix::require_io_service\r
101 {\r
102     std::shared_ptr<std::promise<Type>> promise = std::make_shared<std::promise<Type>>();\r
103
104     std::shared_ptr<boost::asio::streambuf> buffer = std::make_shared<boost::asio::streambuf>();\r
105
106     std::shared_ptr<boost::process::async_pipe> pipe;\r
107
108     async_out_future(std::future<Type> & fut)\r
109     {\r
110         fut = promise->get_future();\r
111     }\r
112     template <typename Executor>\r
113     inline void on_success(Executor &exec)\r
114     {\r
115         auto pipe = this->pipe;\r
116
117         auto buffer  = this->buffer;\r
118         auto promise = this->promise;\r
119
120         boost::asio::async_read(*pipe, *buffer,\r
121                 [pipe, buffer, promise](const boost::system::error_code& ec, std::size_t size)\r
122                 {\r
123                     if (ec && (ec.value() != ENOENT))\r
124                     {\r
125                         std::error_code e(ec.value(), std::system_category());\r
126                         promise->set_exception(std::make_exception_ptr(process_error(e)));\r
127                     }\r
128                     else\r
129                     {\r
130                         std::istream is (buffer.get());\r
131                         Type arg;\r
132                         arg.resize(buffer->size());\r
133                         is.read(&*arg.begin(), buffer->size());\r
134                         promise->set_value(std::move(arg));\r
135                     }\r
136                 });\r
137
138         std::move(*pipe).sink().close();\r
139         this->pipe = nullptr;\r
140     }\r
141
142     template<typename Executor>\r
143     void on_error(Executor &, const std::error_code &) const\r
144     {\r
145         std::move(*pipe).sink().close();\r
146     }\r
147
148     template<typename Executor>\r
149     void on_setup(Executor & exec)\r
150     {\r
151         pipe = std::make_shared<boost::process::async_pipe>(get_io_service(exec.seq));\r
152     }\r
153
154     template <typename Executor>\r
155     void on_exec_setup(Executor &exec)\r
156     {\r
157
158         int res = apply_out_handles(pipe->native_sink(),\r
159                       std::integral_constant<int, p1>(), std::integral_constant<int, p2>());\r
160         if (res == -1)\r
161             exec.set_error(::boost::process::detail::get_last_error(), "dup2() failed");\r
162
163         ::close(pipe->native_sink());\r
164     }\r
165
166 };\r
167
168 }}}}\r
169
170 #endif\r