/// \file child.hpp // // Copyright (C) 2014 MicroNeil Research Corporation. // // This program is part of the MicroNeil Research Open Library Project. For // more information go to http://www.microneil.com/OpenLibrary/index.html // // This program is free software; you can redistribute it and/or modify it // under the terms of the GNU General Public License as published by the // Free Software Foundation; either version 2 of the License, or (at your // option) any later version. // // This program is distributed in the hope that it will be useful, but WITHOUT // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for // more details. // // You should have received a copy of the GNU General Public License along with // this program; if not, write to the Free Software Foundation, Inc., 59 Temple // Place, Suite 330, Boston, MA 02111-1307 USA //============================================================================== /* \brief The child module provides classes to spawn and communicate with child processes. */ #ifndef CHILD_HPP #define CHILD_HPP #ifdef WIN32 #include #endif #include #include #include #include #include #include namespace CodeDweller { /** \namespace CodeDweller The CodeDweller namespace contains components providing high-level functionality for applications. */ /** Class that abstracts the creation of child processes. This class provides functionality to create a child process, communicate with the child process via streams and signals, and obtain the exit code of the child process. */ class Child { private: /// Streambuf class for reading the standard output of the child /// process. class ReadStreambuf : public std::streambuf { public: /// Reader streambuf constructor. // // \param[in] bufferSize is the size in bytes of the input // buffer. // explicit ReadStreambuf(std::size_t bufferSize = 4096); #ifdef WIN32 /// Set the handle to read the standard output of the child /// process. // // \param[in] inHandle is the input handle for the standard // output of the child process. // void setInputHandle(HANDLE inHandle); #else /// Set the file descriptor to read the standard output of the /// child process. // // \param[in] inFd is the input file descriptor for the standard // output of the child process. // void setInputFileDescriptor(int inFd); #endif private: /// Override streambuf::underflow(). int_type underflow(); /// Copy constructor not implemented. ReadStreambuf(const ReadStreambuf &); /// Copy constructor not implemented. ReadStreambuf &operator=(const ReadStreambuf &); /// Input handle. #ifdef WIN32 HANDLE inputHandle; #else int inputFileDescriptor; #endif /// Read buffer. std::vector buffer; }; /// Streambuf class for writing to the standard input of the child /// process. // // Note: If an error occurs when writing the output from the // parent process, the output buffer is cleared. // class WriteStreambuf : public std::streambuf { public: /// Writer streambuf constructor. // // \param[in] bufferSize is the size in bytes of the input // buffer. // explicit WriteStreambuf(std::size_t bufferSize = 4096); #ifdef WIN32 /// Set the handle to write the standard input of the child /// process. // // \param[in] outHandle is the output handle for the standard // input of the child process. // void setOutputHandle(HANDLE outHandle); #else /// Set the file descriptor to write the standard input of the /// child process. // // \param[in] outFd is the output file descriptor for the // standard input of the child process. // void setOutputFileDescriptor(int outFd); #endif private: /// Flush the output buffer. void flushBuffer(); /// Override streambuf::overflow(). int_type overflow(int_type ch); /// Override streambuf::sync(). int sync(); /// Copy constructor not implemented. WriteStreambuf(const WriteStreambuf &); /// Copy constructor not implemented. WriteStreambuf &operator=(const WriteStreambuf &); /// Output handle. #ifdef WIN32 HANDLE outputHandle; #else int outputFileDescriptor; #endif /// Write buffer. std::vector buffer; }; /// Stream buffer for reading to the stdout of the child process; ReadStreambuf readStreambuf; /// Stream buffer for writing to the stdin of the child process; WriteStreambuf writeStreambuf; public: /** Constructor for spawning with command-line parameters. The constructor configures the object, but doesn't spawn the child process. \param[in] args contains the child executable file name and command-line parameters. args[0] contains the full path of the executable, and args[1] thru args[n] are the command-line parameters. \param[in] bufSize is the buffer size of the reader and writer streams used to communicate with the child process. */ Child(std::vector args, size_t bufSize = 4096); /** Constructor for spawning without command-line parameters. The constructor configures the object, but doesn't spawn the child process. \param[in] childpath contains the child executable file name. \param[in] bufSize is the buffer size of the reader and writer streams used to communicate with the child process. */ Child(std::string childpath, size_t bufSize = 4096); /** Destructor terminates the child process. */ ~Child(); /// Input stream to read data from the child's standard output. std::istream reader; /// Output stream to write data to the child's standard input. std::ostream writer; /** Spawn the child process. \throws runtime_error if an error occurs. */ void run(); /** Terminite the child process. \throws runtime_error if an error occurs. \throws logic_error if the child process is not running. */ void terminate(); /** Check whether the child process has exited. \returns True if the child process has exited, false otherwise. \throws runtime_error if an error occurs. \throws logic_error if the child process is not running. */ bool isDone(); /** Get the exit value of the child process. \returns The exit value of the child process if the child process has exited. \throws runtime_error if an error occurs. \throws logic_error if the child process has not exited. \throws logic_error if the child process is not running. */ int32_t result(); private: /// Exit code to use when terminating the child process. static const uint32_t terminateExitCode = 0; /// True if the child process was successfully started. bool childStarted; /// True if the child process has exited. bool childExited; /// Initialize data members. void init(); /// Child executable path and command-line parameters. std::vector cmdArgs; /// Child executable path and command-line parameters. std::string cmdline; #ifdef WIN32 /// Child's process handle. HANDLE childProcess; /// Child's thread handle. HANDLE childThread; #else /// Child process ID. pid_t childPid; #endif /// Exit value of the process. int32_t exitCode; /// True if the exit code has been obtained. bool exitCodeObtainedFlag; /// Return text for the most recent error. // // \returns Human-readable description of the most recent error. // static std::string getErrorText(); }; } #endif // CHILD_HPP