1// 2// Automated Testing Framework (atf) 3// 4// Copyright (c) 2007 The NetBSD Foundation, Inc. 5// All rights reserved. 6// 7// Redistribution and use in source and binary forms, with or without 8// modification, are permitted provided that the following conditions 9// are met: 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. 15// 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. 28// 29 30#if !defined(_ATF_RUN_IO_HPP_) 31#define _ATF_RUN_IO_HPP_ 32 33#include <istream> 34#include <ostream> 35#include <streambuf> 36 37#include "fs.hpp" 38 39#include "../atf-c++/utils.hpp" 40 41namespace atf { 42namespace atf_run { 43 44// ------------------------------------------------------------------------ 45// The "file_handle" class. 46// ------------------------------------------------------------------------ 47 48//! 49//! \brief Simple RAII model for system file handles. 50//! 51//! The \a file_handle class is a simple RAII model for native system file 52//! handles. This class wraps one of such handles grabbing its ownership, 53//! and automaticaly closes it upon destruction. It is basically used 54//! inside the library to avoid leaking open file handles, shall an 55//! unexpected execution trace occur. 56//! 57//! A \a file_handle object can be copied but doing so invalidates the 58//! source object. There can only be a single valid \a file_handle object 59//! for a given system file handle. This is similar to std::auto_ptr\<\>'s 60//! semantics. 61//! 62//! This class also provides some convenience methods to issue special file 63//! operations under their respective platforms. 64//! 65class file_handle 66{ 67public: 68 //! 69 //! \brief Opaque name for the native handle type. 70 //! 71 //! Each operating system identifies file handles using a specific type. 72 //! The \a handle_type type is used to transparently refer to file 73 //! handles regarless of the operating system in which this class is 74 //! used. 75 //! 76 //! If this class is used in a POSIX system, \a NativeSystemHandle is 77 //! an integer type while it is a \a HANDLE in a Win32 system. 78 //! 79 typedef int handle_type; 80 81 //! 82 //! \brief Constructs an invalid file handle. 83 //! 84 //! This constructor creates a new \a file_handle object that represents 85 //! an invalid file handle. An invalid file handle can be copied but 86 //! cannot be manipulated in any way (except checking for its validity). 87 //! 88 //! \see is_valid() 89 //! 90 file_handle(void); 91 92 //! 93 //! \brief Constructs a new file handle from a native file handle. 94 //! 95 //! This constructor creates a new \a file_handle object that takes 96 //! ownership of the given \a h native file handle. The user must not 97 //! close \a h on his own during the lifetime of the new object. 98 //! Ownership can be reclaimed using disown(). 99 //! 100 //! \pre The native file handle must be valid; a close operation must 101 //! succeed on it. 102 //! 103 //! \see disown() 104 //! 105 file_handle(handle_type h); 106 107 //! 108 //! \brief Copy constructor; invalidates the source handle. 109 //! 110 //! This copy constructor creates a new file handle from a given one. 111 //! Ownership of the native file handle is transferred to the new 112 //! object, effectively invalidating the source file handle. This 113 //! avoids having two live \a file_handle objects referring to the 114 //! same native file handle. The source file handle need not be 115 //! valid in the name of simplicity. 116 //! 117 //! \post The source file handle is invalid. 118 //! \post The new file handle owns the source's native file handle. 119 //! 120 file_handle(const file_handle& fh); 121 122 //! 123 //! \brief Releases resources if the handle is valid. 124 //! 125 //! If the file handle is valid, the destructor closes it. 126 //! 127 //! \see is_valid() 128 //! 129 ~file_handle(void); 130 131 //! 132 //! \brief Assignment operator; invalidates the source handle. 133 //! 134 //! This assignment operator transfers ownership of the RHS file 135 //! handle to the LHS one, effectively invalidating the source file 136 //! handle. This avoids having two live \a file_handle objects 137 //! referring to the same native file handle. The source file 138 //! handle need not be valid in the name of simplicity. 139 //! 140 //! \post The RHS file handle is invalid. 141 //! \post The LHS file handle owns RHS' native file handle. 142 //! \return A reference to the LHS file handle. 143 //! 144 file_handle& operator=(const file_handle& fh); 145 146 //! 147 //! \brief Checks whether the file handle is valid or not. 148 //! 149 //! Returns a boolean indicating whether the file handle is valid or 150 //! not. If the file handle is invalid, no other applications can be 151 //! executed other than the destructor. 152 //! 153 //! \return True if the file handle is valid; false otherwise. 154 //! 155 bool is_valid(void) const; 156 157 //! 158 //! \brief Closes the file handle. 159 //! 160 //! Explicitly closes the file handle, which must be valid. Upon 161 //! exit, the handle is not valid any more. 162 //! 163 //! \pre The file handle is valid. 164 //! \post The file handle is invalid. 165 //! \post The native file handle is closed. 166 //! 167 void close(void); 168 169 //! 170 //! \brief Reclaims ownership of the native file handle. 171 //! 172 //! Explicitly reclaims ownership of the native file handle contained 173 //! in the \a file_handle object, returning the native file handle. 174 //! The caller is responsible of closing it later on. 175 //! 176 //! \pre The file handle is valid. 177 //! \post The file handle is invalid. 178 //! \return The native file handle. 179 //! 180 handle_type disown(void); 181 182 //! 183 //! \brief Gets the native file handle. 184 //! 185 //! Returns the native file handle for the \a file_handle object. 186 //! The caller can issue any operation on it except closing it. 187 //! If closing is required, disown() shall be used. 188 //! 189 //! \pre The file handle is valid. 190 //! \return The native file handle. 191 //! 192 handle_type get(void) const; 193 194 //! 195 //! \brief Changes the native file handle to the given one. 196 //! 197 //! Given a new native file handle \a h, this operation assigns this 198 //! handle to the current object, closing its old native file handle. 199 //! In other words, it first calls dup2() to remap the old handle to 200 //! the new one and then closes the old handle. 201 //! 202 //! If \a h matches the current value of the handle, this is a no-op. 203 //! This is done for simplicity, to avoid the caller having to check 204 //! this condition on its own. 205 //! 206 //! If \a h is open, it is automatically closed by dup2(). 207 //! 208 //! This operation is only available in POSIX systems. 209 //! 210 //! \pre The file handle is valid. 211 //! \pre The native file handle \a h is valid; i.e., it must be 212 //! closeable. 213 //! \post The file handle's native file handle is \a h. 214 //! \throw system_error If the internal remapping operation fails. 215 //! 216 void posix_remap(handle_type h); 217 218private: 219 //! 220 //! \brief Internal handle value. 221 //! 222 //! This variable holds the native handle value for the file handle 223 //! hold by this object. It is interesting to note that this needs 224 //! to be mutable because the copy constructor and the assignment 225 //! operator invalidate the source object. 226 //! 227 mutable handle_type m_handle; 228 229 //! 230 //! \brief Constant function representing an invalid handle value. 231 //! 232 //! Returns the platform-specific handle value that represents an 233 //! invalid handle. This is a constant function rather than a regular 234 //! constant because, in the latter case, we cannot define it under 235 //! Win32 due to the value being of a complex type. 236 //! 237 static handle_type invalid_value(void); 238}; 239 240// ------------------------------------------------------------------------ 241// The "systembuf" class. 242// ------------------------------------------------------------------------ 243 244//! 245//! \brief std::streambuf implementation for system file handles. 246//! 247//! systembuf provides a std::streambuf implementation for system file 248//! handles. Contrarywise to file_handle, this class does \b not take 249//! ownership of the native file handle; this should be taken care of 250//! somewhere else. 251//! 252//! This class follows the expected semantics of a std::streambuf object. 253//! However, it is not copyable to avoid introducing inconsistences with 254//! the on-disk file and the in-memory buffers. 255//! 256class systembuf : 257 public std::streambuf, atf::utils::noncopyable 258{ 259public: 260 typedef int handle_type; 261 262 //! 263 //! \brief Constructs a new systembuf for the given file handle. 264 //! 265 //! This constructor creates a new systembuf object that reads or 266 //! writes data from/to the \a h native file handle. This handle 267 //! is \b not owned by the created systembuf object; the code 268 //! should take care of it externally. 269 //! 270 //! This class buffers input and output; the buffer size may be 271 //! tuned through the \a bufsize parameter, which defaults to 8192 272 //! bytes. 273 //! 274 //! \see pistream. 275 //! 276 explicit systembuf(handle_type h, std::size_t bufsize = 8192); 277 ~systembuf(void); 278 279private: 280 //! 281 //! \brief Native file handle used by the systembuf object. 282 //! 283 handle_type m_handle; 284 285 //! 286 //! \brief Internal buffer size used during read and write operations. 287 //! 288 std::size_t m_bufsize; 289 290 //! 291 //! \brief Internal buffer used during read operations. 292 //! 293 char* m_read_buf; 294 295 //! 296 //! \brief Internal buffer used during write operations. 297 //! 298 char* m_write_buf; 299 300protected: 301 //! 302 //! \brief Reads new data from the native file handle. 303 //! 304 //! This operation is called by input methods when there are no more 305 //! data in the input buffer. The function fills the buffer with new 306 //! data, if available. 307 //! 308 //! \pre All input positions are exhausted (gptr() >= egptr()). 309 //! \post The input buffer has new data, if available. 310 //! \returns traits_type::eof() if a read error occurrs or there are 311 //! no more data to be read. Otherwise returns 312 //! traits_type::to_int_type(*gptr()). 313 //! 314 virtual int_type underflow(void); 315 316 //! 317 //! \brief Makes room in the write buffer for additional data. 318 //! 319 //! This operation is called by output methods when there is no more 320 //! space in the output buffer to hold a new element. The function 321 //! first flushes the buffer's contents to disk and then clears it to 322 //! leave room for more characters. The given \a c character is 323 //! stored at the beginning of the new space. 324 //! 325 //! \pre All output positions are exhausted (pptr() >= epptr()). 326 //! \post The output buffer has more space if no errors occurred 327 //! during the write to disk. 328 //! \post *(pptr() - 1) is \a c. 329 //! \returns traits_type::eof() if a write error occurrs. Otherwise 330 //! returns traits_type::not_eof(c). 331 //! 332 virtual int_type overflow(int c); 333 334 //! 335 //! \brief Flushes the output buffer to disk. 336 //! 337 //! Synchronizes the systembuf buffers with the contents of the file 338 //! associated to this object through the native file handle. The 339 //! output buffer is flushed to disk and cleared to leave new room 340 //! for more data. 341 //! 342 //! \returns 0 on success, -1 if an error occurred. 343 //! 344 virtual int sync(void); 345}; 346 347// ------------------------------------------------------------------------ 348// The "pistream" class. 349// ------------------------------------------------------------------------ 350 351//! 352//! \brief Child process' output stream. 353//! 354//! The pistream class represents an output communication channel with the 355//! child process. The child process writes data to this stream and the 356//! parent process can read it through the pistream object. In other 357//! words, from the child's point of view, the communication channel is an 358//! output one, but from the parent's point of view it is an input one; 359//! hence the confusing pistream name. 360//! 361//! pistream objects cannot be copied because they own the file handle 362//! they use to communicate with the child and because they buffer data 363//! that flows through the communication channel. 364//! 365//! A pistream object behaves as a std::istream stream in all senses. 366//! The class is only provided because it must provide a method to let 367//! the caller explicitly close the communication channel. 368//! 369//! \remark <b>Blocking remarks</b>: Functions that read data from this 370//! stream can block if the associated file handle blocks during the read. 371//! As this class is used to communicate with child processes through 372//! anonymous pipes, the most typical blocking condition happens when the 373//! child has no more data to send to the pipe's system buffer. When 374//! this happens, the buffer eventually empties and the system blocks 375//! until the writer generates some data. 376//! 377class pistream : 378 public std::istream, utils::noncopyable 379{ 380 //! 381 //! \brief The systembuf object used to manage this stream's data. 382 //! 383 systembuf m_systembuf; 384 385public: 386 //! 387 //! \brief Creates a new process' output stream. 388 //! 389 //! Given a file handle, this constructor creates a new pistream 390 //! object that owns the given file handle \a fh. Ownership of 391 //! \a fh is transferred to the created pistream object. 392 //! 393 //! \pre \a fh is valid. 394 //! \post \a fh is invalid. 395 //! \post The new pistream object owns \a fh. 396 //! 397 explicit pistream(const int); 398}; 399 400// ------------------------------------------------------------------------ 401// The "muxer" class. 402// ------------------------------------------------------------------------ 403 404class muxer : utils::noncopyable { 405 const int* m_fds; 406 const size_t m_nfds; 407 408 const size_t m_bufsize; 409 atf::utils::auto_array< std::string > m_buffers; 410 411protected: 412 virtual void line_callback(const size_t, const std::string&) = 0; 413 414 size_t read_one(const size_t, const int, std::string&, const bool); 415 416public: 417 muxer(const int*, const size_t, const size_t bufsize = 1024); 418 virtual ~muxer(void); 419 420 void mux(volatile const bool&); 421 void flush(void); 422}; 423 424} // namespace atf_run 425} // namespace atf 426 427#endif // !defined(_ATF_RUN_IO_HPP_) 428