2 // Automated Testing Framework (atf)
4 // Copyright (c) 2007 The NetBSD Foundation, Inc.
5 // All rights reserved.
7 // Redistribution and use in source and binary forms, with or without
8 // modification, are permitted provided that the following conditions
10 // 1. Redistributions of source code must retain the above copyright
11 // notice, this list of conditions and the following disclaimer.
12 // 2. Redistributions in binary form must reproduce the above copyright
13 // notice, this list of conditions and the following disclaimer in the
14 // documentation and/or other materials provided with the distribution.
16 // THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
17 // CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
18 // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 // IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
21 // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
23 // GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25 // IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26 // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27 // IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
41 #include "../atf-c/error.h"
44 #include "../atf-c++/detail/auto_array.hpp"
45 #include "../atf-c++/detail/exceptions.hpp"
46 #include "../atf-c++/detail/sanity.hpp"
50 namespace impl
= atf::atf_run
;
51 #define IMPL_NAME "atf::atf_run"
53 // ------------------------------------------------------------------------
54 // The "file_handle" class.
55 // ------------------------------------------------------------------------
57 impl::file_handle::file_handle(void) :
58 m_handle(invalid_value())
62 impl::file_handle::file_handle(handle_type h
) :
65 PRE(m_handle
!= invalid_value());
68 impl::file_handle::file_handle(const file_handle
& fh
) :
71 fh
.m_handle
= invalid_value();
74 impl::file_handle::~file_handle(void)
81 impl::file_handle::operator=(const file_handle
& fh
)
83 m_handle
= fh
.m_handle
;
84 fh
.m_handle
= invalid_value();
90 impl::file_handle::is_valid(void)
93 return m_handle
!= invalid_value();
97 impl::file_handle::close(void)
103 m_handle
= invalid_value();
106 impl::file_handle::handle_type
107 impl::file_handle::disown(void)
111 handle_type h
= m_handle
;
112 m_handle
= invalid_value();
116 impl::file_handle::handle_type
117 impl::file_handle::get(void)
126 impl::file_handle::posix_remap(handle_type h
)
133 if (::dup2(m_handle
, h
) == -1)
134 throw system_error(IMPL_NAME
"::file_handle::posix_remap",
135 "dup2(2) failed", errno
);
137 if (::close(m_handle
) == -1) {
139 throw system_error(IMPL_NAME
"::file_handle::posix_remap",
140 "close(2) failed", errno
);
146 impl::file_handle::handle_type
147 impl::file_handle::invalid_value(void)
152 // ------------------------------------------------------------------------
153 // The "systembuf" class.
154 // ------------------------------------------------------------------------
156 impl::systembuf::systembuf(handle_type h
, std::size_t bufsize
) :
166 m_read_buf
= new char[bufsize
];
167 m_write_buf
= new char[bufsize
];
169 if (m_read_buf
!= NULL
)
170 delete [] m_read_buf
;
171 if (m_write_buf
!= NULL
)
172 delete [] m_write_buf
;
176 setp(m_write_buf
, m_write_buf
+ m_bufsize
);
179 impl::systembuf::~systembuf(void)
181 delete [] m_read_buf
;
182 delete [] m_write_buf
;
185 impl::systembuf::int_type
186 impl::systembuf::underflow(void)
188 PRE(gptr() >= egptr());
191 ssize_t cnt
= ::read(m_handle
, m_read_buf
, m_bufsize
);
192 ok
= (cnt
!= -1 && cnt
!= 0);
195 return traits_type::eof();
197 setg(m_read_buf
, m_read_buf
, m_read_buf
+ cnt
);
198 return traits_type::to_int_type(*gptr());
202 impl::systembuf::int_type
203 impl::systembuf::overflow(int c
)
205 PRE(pptr() >= epptr());
207 return traits_type::eof();
208 if (!traits_type::eq_int_type(c
, traits_type::eof())) {
209 traits_type::assign(*pptr(), c
);
212 return traits_type::not_eof(c
);
216 impl::systembuf::sync(void)
218 ssize_t cnt
= pptr() - pbase();
221 ok
= ::write(m_handle
, pbase(), cnt
) == cnt
;
228 // ------------------------------------------------------------------------
229 // The "pistream" class.
230 // ------------------------------------------------------------------------
232 impl::pistream::pistream(const int fd
) :
239 // ------------------------------------------------------------------------
240 // The "muxer" class.
241 // ------------------------------------------------------------------------
244 safe_poll(struct pollfd fds
[], nfds_t nfds
, int timeout
)
246 int ret
= ::poll(fds
, nfds
, timeout
);
251 throw atf::system_error(IMPL_NAME
"::safe_poll", "poll(2) failed",
259 safe_read(const int fd
, void* buffer
, const size_t nbytes
,
260 const bool report_errors
)
263 while ((ret
= ::read(fd
, buffer
, nbytes
)) == -1 && errno
== EINTR
) {}
268 throw atf::system_error(IMPL_NAME
"::safe_read", "read(2) failed",
274 return static_cast< size_t >(ret
);
277 impl::muxer::muxer(const int* fds
, const size_t nfds
, const size_t bufsize
) :
281 m_buffers(new std::string
[nfds
])
285 impl::muxer::~muxer(void)
290 impl::muxer::read_one(const size_t index
, const int fd
, std::string
& accum
,
291 const bool report_errors
)
293 atf::auto_array
< char > buffer(new char[m_bufsize
]);
294 const size_t nbytes
= safe_read(fd
, buffer
.get(), m_bufsize
- 1,
296 INV(nbytes
< m_bufsize
);
297 buffer
[nbytes
] = '\0';
299 std::string
line(accum
);
301 size_t line_start
= 0;
302 for (size_t i
= 0; i
< nbytes
; i
++) {
303 if (buffer
[i
] == '\n') {
304 line_callback(index
, line
);
308 } else if (buffer
[i
] == '\r') {
311 line
.append(1, buffer
[i
]);
314 accum
.append(&buffer
[line_start
]);
320 impl::muxer::mux(volatile const bool& terminate
)
322 atf::auto_array
< struct pollfd
> poll_fds(new struct pollfd
[m_nfds
]);
323 for (size_t i
= 0; i
< m_nfds
; i
++) {
324 poll_fds
[i
].fd
= m_fds
[i
];
325 poll_fds
[i
].events
= POLLIN
;
328 size_t nactive
= m_nfds
;
329 while (nactive
> 0 && !terminate
) {
331 while (!terminate
&& (ret
= safe_poll(poll_fds
.get(), 2, 250)) == 0) {}
333 for (size_t i
= 0; !terminate
&& i
< m_nfds
; i
++) {
334 if (poll_fds
[i
].events
== 0)
337 if (poll_fds
[i
].revents
& POLLHUP
) {
338 // Any data still available at this point will be processed by
339 // a call to the flush method.
340 poll_fds
[i
].events
= 0;
344 } else if (poll_fds
[i
].revents
& (POLLIN
| POLLRDNORM
| POLLRDBAND
|
346 (void)read_one(i
, poll_fds
[i
].fd
, m_buffers
[i
], true);
353 impl::muxer::flush(void)
355 for (size_t i
= 0; i
< m_nfds
; i
++) {
356 while (read_one(i
, m_fds
[i
], m_buffers
[i
], false) > 0) {}
358 if (!m_buffers
[i
].empty())
359 line_callback(i
, m_buffers
[i
]);