diff options
Diffstat (limited to '')
-rw-r--r-- | unit/atf-src/tools/io.hpp | 436 |
1 files changed, 436 insertions, 0 deletions
diff --git a/unit/atf-src/tools/io.hpp b/unit/atf-src/tools/io.hpp new file mode 100644 index 0000000..3fb417b --- /dev/null +++ b/unit/atf-src/tools/io.hpp @@ -0,0 +1,436 @@ +// +// Automated Testing Framework (atf) +// +// Copyright (c) 2007 The NetBSD Foundation, Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND +// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, +// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER +// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// + +#if !defined(TOOLS_IO_HPP) +#define TOOLS_IO_HPP + +#include <istream> +#include <ostream> +#include <streambuf> + +#include "auto_array.hpp" +#include "fs.hpp" + +namespace tools { +namespace io { + +// ------------------------------------------------------------------------ +// The "file_handle" class. +// ------------------------------------------------------------------------ + +//! +//! \brief Simple RAII model for system file handles. +//! +//! The \a file_handle class is a simple RAII model for native system file +//! handles. This class wraps one of such handles grabbing its ownership, +//! and automaticaly closes it upon destruction. It is basically used +//! inside the library to avoid leaking open file handles, shall an +//! unexpected execution trace occur. +//! +//! A \a file_handle object can be copied but doing so invalidates the +//! source object. There can only be a single valid \a file_handle object +//! for a given system file handle. This is similar to std::auto_ptr\<\>'s +//! semantics. +//! +//! This class also provides some convenience methods to issue special file +//! operations under their respective platforms. +//! +class file_handle +{ +public: + //! + //! \brief Opaque name for the native handle type. + //! + //! Each operating system identifies file handles using a specific type. + //! The \a handle_type type is used to transparently refer to file + //! handles regarless of the operating system in which this class is + //! used. + //! + //! If this class is used in a POSIX system, \a NativeSystemHandle is + //! an integer type while it is a \a HANDLE in a Win32 system. + //! + typedef int handle_type; + + //! + //! \brief Constructs an invalid file handle. + //! + //! This constructor creates a new \a file_handle object that represents + //! an invalid file handle. An invalid file handle can be copied but + //! cannot be manipulated in any way (except checking for its validity). + //! + //! \see is_valid() + //! + file_handle(void); + + //! + //! \brief Constructs a new file handle from a native file handle. + //! + //! This constructor creates a new \a file_handle object that takes + //! ownership of the given \a h native file handle. The user must not + //! close \a h on his own during the lifetime of the new object. + //! Ownership can be reclaimed using disown(). + //! + //! \pre The native file handle must be valid; a close operation must + //! succeed on it. + //! + //! \see disown() + //! + file_handle(handle_type h); + + //! + //! \brief Copy constructor; invalidates the source handle. + //! + //! This copy constructor creates a new file handle from a given one. + //! Ownership of the native file handle is transferred to the new + //! object, effectively invalidating the source file handle. This + //! avoids having two live \a file_handle objects referring to the + //! same native file handle. The source file handle need not be + //! valid in the name of simplicity. + //! + //! \post The source file handle is invalid. + //! \post The new file handle owns the source's native file handle. + //! + file_handle(const file_handle& fh); + + //! + //! \brief Releases resources if the handle is valid. + //! + //! If the file handle is valid, the destructor closes it. + //! + //! \see is_valid() + //! + ~file_handle(void); + + //! + //! \brief Assignment operator; invalidates the source handle. + //! + //! This assignment operator transfers ownership of the RHS file + //! handle to the LHS one, effectively invalidating the source file + //! handle. This avoids having two live \a file_handle objects + //! referring to the same native file handle. The source file + //! handle need not be valid in the name of simplicity. + //! + //! \post The RHS file handle is invalid. + //! \post The LHS file handle owns RHS' native file handle. + //! \return A reference to the LHS file handle. + //! + file_handle& operator=(const file_handle& fh); + + //! + //! \brief Checks whether the file handle is valid or not. + //! + //! Returns a boolean indicating whether the file handle is valid or + //! not. If the file handle is invalid, no other applications can be + //! executed other than the destructor. + //! + //! \return True if the file handle is valid; false otherwise. + //! + bool is_valid(void) const; + + //! + //! \brief Closes the file handle. + //! + //! Explicitly closes the file handle, which must be valid. Upon + //! exit, the handle is not valid any more. + //! + //! \pre The file handle is valid. + //! \post The file handle is invalid. + //! \post The native file handle is closed. + //! + void close(void); + + //! + //! \brief Reclaims ownership of the native file handle. + //! + //! Explicitly reclaims ownership of the native file handle contained + //! in the \a file_handle object, returning the native file handle. + //! The caller is responsible of closing it later on. + //! + //! \pre The file handle is valid. + //! \post The file handle is invalid. + //! \return The native file handle. + //! + handle_type disown(void); + + //! + //! \brief Gets the native file handle. + //! + //! Returns the native file handle for the \a file_handle object. + //! The caller can issue any operation on it except closing it. + //! If closing is required, disown() shall be used. + //! + //! \pre The file handle is valid. + //! \return The native file handle. + //! + handle_type get(void) const; + + //! + //! \brief Changes the native file handle to the given one. + //! + //! Given a new native file handle \a h, this operation assigns this + //! handle to the current object, closing its old native file handle. + //! In other words, it first calls dup2() to remap the old handle to + //! the new one and then closes the old handle. + //! + //! If \a h matches the current value of the handle, this is a no-op. + //! This is done for simplicity, to avoid the caller having to check + //! this condition on its own. + //! + //! If \a h is open, it is automatically closed by dup2(). + //! + //! This operation is only available in POSIX systems. + //! + //! \pre The file handle is valid. + //! \pre The native file handle \a h is valid; i.e., it must be + //! closeable. + //! \post The file handle's native file handle is \a h. + //! \throw system_error If the internal remapping operation fails. + //! + void posix_remap(handle_type h); + +private: + //! + //! \brief Internal handle value. + //! + //! This variable holds the native handle value for the file handle + //! hold by this object. It is interesting to note that this needs + //! to be mutable because the copy constructor and the assignment + //! operator invalidate the source object. + //! + mutable handle_type m_handle; + + //! + //! \brief Constant function representing an invalid handle value. + //! + //! Returns the platform-specific handle value that represents an + //! invalid handle. This is a constant function rather than a regular + //! constant because, in the latter case, we cannot define it under + //! Win32 due to the value being of a complex type. + //! + static handle_type invalid_value(void); +}; + +// ------------------------------------------------------------------------ +// The "systembuf" class. +// ------------------------------------------------------------------------ + +//! +//! \brief std::streambuf implementation for system file handles. +//! +//! systembuf provides a std::streambuf implementation for system file +//! handles. Contrarywise to file_handle, this class does \b not take +//! ownership of the native file handle; this should be taken care of +//! somewhere else. +//! +//! This class follows the expected semantics of a std::streambuf object. +//! However, it is not copyable to avoid introducing inconsistences with +//! the on-disk file and the in-memory buffers. +//! +class systembuf : public std::streambuf +{ + // Non-copyable. + systembuf(const systembuf&); + systembuf& operator=(const systembuf&); + +public: + typedef int handle_type; + + //! + //! \brief Constructs a new systembuf for the given file handle. + //! + //! This constructor creates a new systembuf object that reads or + //! writes data from/to the \a h native file handle. This handle + //! is \b not owned by the created systembuf object; the code + //! should take care of it externally. + //! + //! This class buffers input and output; the buffer size may be + //! tuned through the \a bufsize parameter, which defaults to 8192 + //! bytes. + //! + //! \see pistream. + //! + explicit systembuf(handle_type h, std::size_t bufsize = 8192); + ~systembuf(void); + +private: + //! + //! \brief Native file handle used by the systembuf object. + //! + handle_type m_handle; + + //! + //! \brief Internal buffer size used during read and write operations. + //! + std::size_t m_bufsize; + + //! + //! \brief Internal buffer used during read operations. + //! + char* m_read_buf; + + //! + //! \brief Internal buffer used during write operations. + //! + char* m_write_buf; + +protected: + //! + //! \brief Reads new data from the native file handle. + //! + //! This operation is called by input methods when there are no more + //! data in the input buffer. The function fills the buffer with new + //! data, if available. + //! + //! \pre All input positions are exhausted (gptr() >= egptr()). + //! \post The input buffer has new data, if available. + //! \returns traits_type::eof() if a read error occurrs or there are + //! no more data to be read. Otherwise returns + //! traits_type::to_int_type(*gptr()). + //! + virtual int_type underflow(void); + + //! + //! \brief Makes room in the write buffer for additional data. + //! + //! This operation is called by output methods when there is no more + //! space in the output buffer to hold a new element. The function + //! first flushes the buffer's contents to disk and then clears it to + //! leave room for more characters. The given \a c character is + //! stored at the beginning of the new space. + //! + //! \pre All output positions are exhausted (pptr() >= epptr()). + //! \post The output buffer has more space if no errors occurred + //! during the write to disk. + //! \post *(pptr() - 1) is \a c. + //! \returns traits_type::eof() if a write error occurrs. Otherwise + //! returns traits_type::not_eof(c). + //! + virtual int_type overflow(int c); + + //! + //! \brief Flushes the output buffer to disk. + //! + //! Synchronizes the systembuf buffers with the contents of the file + //! associated to this object through the native file handle. The + //! output buffer is flushed to disk and cleared to leave new room + //! for more data. + //! + //! \returns 0 on success, -1 if an error occurred. + //! + virtual int sync(void); +}; + +// ------------------------------------------------------------------------ +// The "pistream" class. +// ------------------------------------------------------------------------ + +//! +//! \brief Child process' output stream. +//! +//! The pistream class represents an output communication channel with the +//! child process. The child process writes data to this stream and the +//! parent process can read it through the pistream object. In other +//! words, from the child's point of view, the communication channel is an +//! output one, but from the parent's point of view it is an input one; +//! hence the confusing pistream name. +//! +//! pistream objects cannot be copied because they own the file handle +//! they use to communicate with the child and because they buffer data +//! that flows through the communication channel. +//! +//! A pistream object behaves as a std::istream stream in all senses. +//! The class is only provided because it must provide a method to let +//! the caller explicitly close the communication channel. +//! +//! \remark <b>Blocking remarks</b>: Functions that read data from this +//! stream can block if the associated file handle blocks during the read. +//! As this class is used to communicate with child processes through +//! anonymous pipes, the most typical blocking condition happens when the +//! child has no more data to send to the pipe's system buffer. When +//! this happens, the buffer eventually empties and the system blocks +//! until the writer generates some data. +//! +class pistream : public std::istream +{ + // Non-copyable. + pistream(const pistream&); + pistream& operator=(const pistream&); + + //! + //! \brief The systembuf object used to manage this stream's data. + //! + systembuf m_systembuf; + +public: + //! + //! \brief Creates a new process' output stream. + //! + //! Given a file handle, this constructor creates a new pistream + //! object that owns the given file handle \a fh. Ownership of + //! \a fh is transferred to the created pistream object. + //! + //! \pre \a fh is valid. + //! \post \a fh is invalid. + //! \post The new pistream object owns \a fh. + //! + explicit pistream(const int); +}; + +// ------------------------------------------------------------------------ +// The "muxer" class. +// ------------------------------------------------------------------------ + +class muxer { + // Non-copyable. + muxer(const muxer&); + muxer& operator=(const muxer&); + + const int* m_fds; + const size_t m_nfds; + + const size_t m_bufsize; + tools::auto_array< std::string > m_buffers; + +protected: + virtual void line_callback(const size_t, const std::string&) = 0; + + size_t read_one(const size_t, const int, std::string&, const bool); + +public: + muxer(const int*, const size_t, const size_t bufsize = 1024); + virtual ~muxer(void); + + void mux(volatile const bool&); + void flush(void); +}; + +} // namespace io +} // namespace tools + +#endif // !defined(TOOLS_IO_HPP) |