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++/detail/auto_array.hpp" 40 #include "../atf-c++/noncopyable.hpp" 41 42 namespace atf { 43 namespace atf_run { 44 45 // ------------------------------------------------------------------------ 46 // The "file_handle" class. 47 // ------------------------------------------------------------------------ 48 49 //! 50 //! \brief Simple RAII model for system file handles. 51 //! 52 //! The \a file_handle class is a simple RAII model for native system file 53 //! handles. This class wraps one of such handles grabbing its ownership, 54 //! and automaticaly closes it upon destruction. It is basically used 55 //! inside the library to avoid leaking open file handles, shall an 56 //! unexpected execution trace occur. 57 //! 58 //! A \a file_handle object can be copied but doing so invalidates the 59 //! source object. There can only be a single valid \a file_handle object 60 //! for a given system file handle. This is similar to std::auto_ptr\<\>'s 61 //! semantics. 62 //! 63 //! This class also provides some convenience methods to issue special file 64 //! operations under their respective platforms. 65 //! 66 class file_handle 67 { 68 public: 69 //! 70 //! \brief Opaque name for the native handle type. 71 //! 72 //! Each operating system identifies file handles using a specific type. 73 //! The \a handle_type type is used to transparently refer to file 74 //! handles regarless of the operating system in which this class is 75 //! used. 76 //! 77 //! If this class is used in a POSIX system, \a NativeSystemHandle is 78 //! an integer type while it is a \a HANDLE in a Win32 system. 79 //! 80 typedef int handle_type; 81 82 //! 83 //! \brief Constructs an invalid file handle. 84 //! 85 //! This constructor creates a new \a file_handle object that represents 86 //! an invalid file handle. An invalid file handle can be copied but 87 //! cannot be manipulated in any way (except checking for its validity). 88 //! 89 //! \see is_valid() 90 //! 91 file_handle(void); 92 93 //! 94 //! \brief Constructs a new file handle from a native file handle. 95 //! 96 //! This constructor creates a new \a file_handle object that takes 97 //! ownership of the given \a h native file handle. The user must not 98 //! close \a h on his own during the lifetime of the new object. 99 //! Ownership can be reclaimed using disown(). 100 //! 101 //! \pre The native file handle must be valid; a close operation must 102 //! succeed on it. 103 //! 104 //! \see disown() 105 //! 106 file_handle(handle_type h); 107 108 //! 109 //! \brief Copy constructor; invalidates the source handle. 110 //! 111 //! This copy constructor creates a new file handle from a given one. 112 //! Ownership of the native file handle is transferred to the new 113 //! object, effectively invalidating the source file handle. This 114 //! avoids having two live \a file_handle objects referring to the 115 //! same native file handle. The source file handle need not be 116 //! valid in the name of simplicity. 117 //! 118 //! \post The source file handle is invalid. 119 //! \post The new file handle owns the source's native file handle. 120 //! 121 file_handle(const file_handle& fh); 122 123 //! 124 //! \brief Releases resources if the handle is valid. 125 //! 126 //! If the file handle is valid, the destructor closes it. 127 //! 128 //! \see is_valid() 129 //! 130 ~file_handle(void); 131 132 //! 133 //! \brief Assignment operator; invalidates the source handle. 134 //! 135 //! This assignment operator transfers ownership of the RHS file 136 //! handle to the LHS one, effectively invalidating the source file 137 //! handle. This avoids having two live \a file_handle objects 138 //! referring to the same native file handle. The source file 139 //! handle need not be valid in the name of simplicity. 140 //! 141 //! \post The RHS file handle is invalid. 142 //! \post The LHS file handle owns RHS' native file handle. 143 //! \return A reference to the LHS file handle. 144 //! 145 file_handle& operator=(const file_handle& fh); 146 147 //! 148 //! \brief Checks whether the file handle is valid or not. 149 //! 150 //! Returns a boolean indicating whether the file handle is valid or 151 //! not. If the file handle is invalid, no other applications can be 152 //! executed other than the destructor. 153 //! 154 //! \return True if the file handle is valid; false otherwise. 155 //! 156 bool is_valid(void) const; 157 158 //! 159 //! \brief Closes the file handle. 160 //! 161 //! Explicitly closes the file handle, which must be valid. Upon 162 //! exit, the handle is not valid any more. 163 //! 164 //! \pre The file handle is valid. 165 //! \post The file handle is invalid. 166 //! \post The native file handle is closed. 167 //! 168 void close(void); 169 170 //! 171 //! \brief Reclaims ownership of the native file handle. 172 //! 173 //! Explicitly reclaims ownership of the native file handle contained 174 //! in the \a file_handle object, returning the native file handle. 175 //! The caller is responsible of closing it later on. 176 //! 177 //! \pre The file handle is valid. 178 //! \post The file handle is invalid. 179 //! \return The native file handle. 180 //! 181 handle_type disown(void); 182 183 //! 184 //! \brief Gets the native file handle. 185 //! 186 //! Returns the native file handle for the \a file_handle object. 187 //! The caller can issue any operation on it except closing it. 188 //! If closing is required, disown() shall be used. 189 //! 190 //! \pre The file handle is valid. 191 //! \return The native file handle. 192 //! 193 handle_type get(void) const; 194 195 //! 196 //! \brief Changes the native file handle to the given one. 197 //! 198 //! Given a new native file handle \a h, this operation assigns this 199 //! handle to the current object, closing its old native file handle. 200 //! In other words, it first calls dup2() to remap the old handle to 201 //! the new one and then closes the old handle. 202 //! 203 //! If \a h matches the current value of the handle, this is a no-op. 204 //! This is done for simplicity, to avoid the caller having to check 205 //! this condition on its own. 206 //! 207 //! If \a h is open, it is automatically closed by dup2(). 208 //! 209 //! This operation is only available in POSIX systems. 210 //! 211 //! \pre The file handle is valid. 212 //! \pre The native file handle \a h is valid; i.e., it must be 213 //! closeable. 214 //! \post The file handle's native file handle is \a h. 215 //! \throw system_error If the internal remapping operation fails. 216 //! 217 void posix_remap(handle_type h); 218 219 private: 220 //! 221 //! \brief Internal handle value. 222 //! 223 //! This variable holds the native handle value for the file handle 224 //! hold by this object. It is interesting to note that this needs 225 //! to be mutable because the copy constructor and the assignment 226 //! operator invalidate the source object. 227 //! 228 mutable handle_type m_handle; 229 230 //! 231 //! \brief Constant function representing an invalid handle value. 232 //! 233 //! Returns the platform-specific handle value that represents an 234 //! invalid handle. This is a constant function rather than a regular 235 //! constant because, in the latter case, we cannot define it under 236 //! Win32 due to the value being of a complex type. 237 //! 238 static handle_type invalid_value(void); 239 }; 240 241 // ------------------------------------------------------------------------ 242 // The "systembuf" class. 243 // ------------------------------------------------------------------------ 244 245 //! 246 //! \brief std::streambuf implementation for system file handles. 247 //! 248 //! systembuf provides a std::streambuf implementation for system file 249 //! handles. Contrarywise to file_handle, this class does \b not take 250 //! ownership of the native file handle; this should be taken care of 251 //! somewhere else. 252 //! 253 //! This class follows the expected semantics of a std::streambuf object. 254 //! However, it is not copyable to avoid introducing inconsistences with 255 //! the on-disk file and the in-memory buffers. 256 //! 257 class systembuf : public std::streambuf, atf::noncopyable 258 { 259 public: 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 279 private: 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 300 protected: 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 //! 377 class pistream : public std::istream, noncopyable 378 { 379 //! 380 //! \brief The systembuf object used to manage this stream's data. 381 //! 382 systembuf m_systembuf; 383 384 public: 385 //! 386 //! \brief Creates a new process' output stream. 387 //! 388 //! Given a file handle, this constructor creates a new pistream 389 //! object that owns the given file handle \a fh. Ownership of 390 //! \a fh is transferred to the created pistream object. 391 //! 392 //! \pre \a fh is valid. 393 //! \post \a fh is invalid. 394 //! \post The new pistream object owns \a fh. 395 //! 396 explicit pistream(const int); 397 }; 398 399 // ------------------------------------------------------------------------ 400 // The "muxer" class. 401 // ------------------------------------------------------------------------ 402 403 class muxer : noncopyable { 404 const int* m_fds; 405 const size_t m_nfds; 406 407 const size_t m_bufsize; 408 atf::auto_array< std::string > m_buffers; 409 410 protected: 411 virtual void line_callback(const size_t, const std::string&) = 0; 412 413 size_t read_one(const size_t, const int, std::string&, const bool); 414 415 public: 416 muxer(const int*, const size_t, const size_t bufsize = 1024); 417 virtual ~muxer(void); 418 419 void mux(volatile const bool&); 420 void flush(void); 421 }; 422 423 } // namespace atf_run 424 } // namespace atf 425 426 #endif // !defined(_ATF_RUN_IO_HPP_) 427