Browse Source

Implemented new constructors and isRunning(). Renamed terminate() to close().

Call close() in ~ChildStream.


git-svn-id: https://svn.microneil.com/svn/CodeDweller/branches/adeniz_1@78 d34b734f-a00e-4b39-a726-e4eeb87269ab
adeniz_1
adeniz 9 years ago
parent
commit
20af91c0a2
2 changed files with 120 additions and 66 deletions
  1. 64
    53
      child.cpp
  2. 56
    13
      child.hpp

+ 64
- 53
child.cpp View File

namespace CodeDweller { namespace CodeDweller {
ChildStream::ChildStream(std::vector<std::string> args, size_t bufSize) :
ChildStream::ChildStream(std::vector<std::string> const &args,
size_t bufSize) :
childStreambuf(bufSize), childStreambuf(bufSize),
std::iostream(&childStreambuf), std::iostream(&childStreambuf),
cmdArgs(args) { cmdArgs(args) {
init(); init();
run();
} }
ChildStream::ChildStream(std::string childpath, size_t bufSize) :
ChildStream::ChildStream(std::string const &childpath, size_t bufSize) :
childStreambuf(bufSize), childStreambuf(bufSize),
std::iostream(&childStreambuf),
cmdline(childpath) {
std::iostream(&childStreambuf) {
cmdArgs.push_back(childpath); cmdArgs.push_back(childpath);
init(); init();
run();
} }
ChildStream::~ChildStream() {
// Close handles.
}
ChildStream::ChildStream(size_t bufSize) :
childStreambuf(bufSize),
std::iostream(&childStreambuf) {
void
ChildStream::init() {
init();
}
if (cmdArgs.empty()) {
throw std::invalid_argument("A child executable must be specified.");
ChildStream::~ChildStream() {
if (isRunning()) {
close();
} }
}
void ChildStream::init() {
childStarted = false; childStarted = false;
childExited = false; childExited = false;
exitCode = 0; exitCode = 0;
} }
size_t
ChildStream::numBytesAvailable() const {
void ChildStream::open(std::vector<std::string> const &args) {
cmdArgs = args;
init();
run();
}
void ChildStream::open(std::string const &childpath) {
cmdArgs.clear();
cmdArgs.push_back(childpath);
init();
run();
}
size_t ChildStream::numBytesAvailable() const {
return childStreambuf.numBytesAvailable(); return childStreambuf.numBytesAvailable();
} }
void
ChildStream::run() {
bool ChildStream::isRunning() const {
return childStarted && !childExited;
}
void ChildStream::run() {
if (childStarted) { if (childStarted) {
throw std::logic_error("Child process was active when " throw std::logic_error("Child process was active when "
"run() was called"); "run() was called");
} }
if (cmdArgs.empty()) {
throw std::invalid_argument("A child executable must be specified.");
}
#ifdef _WIN32 #ifdef _WIN32
// Set the bInheritHandle flag so pipe handles are inherited. // Set the bInheritHandle flag so pipe handles are inherited.
SECURITY_ATTRIBUTES securityAttributes; SECURITY_ATTRIBUTES securityAttributes;
getErrorText()); getErrorText());
} }
if (pipe(childStdOutPipe) != 0) { if (pipe(childStdOutPipe) != 0) {
close(childStdInPipe[0]);
close(childStdInPipe[1]);
::close(childStdInPipe[0]);
::close(childStdInPipe[1]);
throw std::runtime_error("Error creating pipe for stdout: " + throw std::runtime_error("Error creating pipe for stdout: " +
getErrorText()); getErrorText());
} }
childPid = fork(); childPid = fork();
if (-1 == childPid) { if (-1 == childPid) {
for (int i = 0; i < 2; i++) { for (int i = 0; i < 2; i++) {
close(childStdInPipe[i]);
close(childStdOutPipe[i]);
::close(childStdInPipe[i]);
::close(childStdOutPipe[i]);
} }
throw std::runtime_error("Error creating child process: " + throw std::runtime_error("Error creating child process: " +
getErrorText()); getErrorText());
} }
// Close pipes. // Close pipes.
if ( (close(childStdInPipe[0]) != 0) ||
(close(childStdInPipe[1]) != 0) ||
(close(childStdOutPipe[0]) != 0) ||
(close(childStdOutPipe[1]) != 0) ) {
if ( (::close(childStdInPipe[0]) != 0) ||
(::close(childStdInPipe[1]) != 0) ||
(::close(childStdOutPipe[0]) != 0) ||
(::close(childStdOutPipe[1]) != 0) ) {
std::string errMsg; std::string errMsg;
// Send message to parent. // Send message to parent.
} }
// std::cout << "Child pid: " << childPid << std::endl; // DEBUG.
// Provide the stream buffers with the file descriptors for // Provide the stream buffers with the file descriptors for
// communicating with the child process. // communicating with the child process.
childStreambuf.setInputFileDescriptor(childStdOutPipe[0]); childStreambuf.setInputFileDescriptor(childStdOutPipe[0]);
childStreambuf.setOutputFileDescriptor(childStdInPipe[1]); childStreambuf.setOutputFileDescriptor(childStdInPipe[1]);
// Close the child's end of the pipes. // Close the child's end of the pipes.
if ( (close(childStdInPipe[0]) != 0) ||
(close(childStdOutPipe[1]) != 0) ) {
if ( (::close(childStdInPipe[0]) != 0) ||
(::close(childStdOutPipe[1]) != 0) ) {
std::string errMsg; std::string errMsg;
throw std::runtime_error("Error closing child's end of pipes in " throw std::runtime_error("Error closing child's end of pipes in "
} }
void
ChildStream::terminate() {
void ChildStream::close() {
if (isDone()) { if (isDone()) {
} }
bool
ChildStream::isDone() {
bool ChildStream::isDone() {
if (childExited) { if (childExited) {
} }
int32_t
ChildStream::result() {
int32_t ChildStream::result() {
if (exitCodeObtainedFlag) { if (exitCodeObtainedFlag) {
} }
std::string
ChildStream::getErrorText() {
std::string ChildStream::getErrorText() {
#ifdef _WIN32 #ifdef _WIN32
LPVOID winMsgBuf; LPVOID winMsgBuf;
} }
#ifdef _WIN32 #ifdef _WIN32
void
ChildStream::ChildStreambuf::setInputHandle(HANDLE inHandle) {
void ChildStream::ChildStreambuf::setInputHandle(HANDLE inHandle) {
inputHandle = inHandle; inputHandle = inHandle;
} }
#else #else
void
ChildStream::ChildStreambuf::setInputFileDescriptor(int inFd) {
void ChildStream::ChildStreambuf::setInputFileDescriptor(int inFd) {
inputFileDescriptor = inFd; inputFileDescriptor = inFd;
} }
#endif #endif
size_t
ChildStream::ChildStreambuf::numBytesAvailable() const {
size_t ChildStream::ChildStreambuf::numBytesAvailable() const {
size_t nBytesAvailable = egptr() - gptr(); size_t nBytesAvailable = egptr() - gptr();
} }
std::streambuf::int_type
ChildStream::ChildStreambuf::underflow() {
std::streambuf::int_type ChildStream::ChildStreambuf::underflow() {
// Check for empty buffer. // Check for empty buffer.
if (gptr() < egptr()) { if (gptr() < egptr()) {
} }
#ifdef _WIN32 #ifdef _WIN32
void
ChildStream::ChildStreambuf::setOutputHandle(HANDLE outHandle) {
void ChildStream::ChildStreambuf::setOutputHandle(HANDLE outHandle) {
outputHandle = outHandle; outputHandle = outHandle;
} }
#else #else
void
ChildStream::ChildStreambuf::setOutputFileDescriptor(int outFd) {
void ChildStream::ChildStreambuf::setOutputFileDescriptor(int outFd) {
outputFileDescriptor = outFd; outputFileDescriptor = outFd;
} }
#endif #endif
void
ChildStream::ChildStreambuf::flushBuffer() {
void ChildStream::ChildStreambuf::flushBuffer() {
// Write. // Write.
std::ptrdiff_t nBytes = pptr() - pbase(); std::ptrdiff_t nBytes = pptr() - pbase();
} }
std::streambuf::int_type
ChildStream::ChildStreambuf::overflow(int_type ch) {
std::streambuf::int_type ChildStream::ChildStreambuf::overflow(int_type ch) {
// Check whether we're writing EOF. // Check whether we're writing EOF.
if (traits_type::eof() != ch) { if (traits_type::eof() != ch) {
} }
int
ChildStream::ChildStreambuf::sync() {
int ChildStream::ChildStreambuf::sync() {
flushBuffer(); // Throws exception on failure. flushBuffer(); // Throws exception on failure.

+ 56
- 13
child.hpp View File



/** Constructor for spawning with command-line parameters. /** Constructor for spawning with command-line parameters.


The constructor configures the object, but doesn't spawn the
child process.
The constructor configures the object, and spawns the child
process.


\param[in] args contains the child executable file name and \param[in] args contains the child executable file name and
command-line parameters. args[0] contains the full path of the command-line parameters. args[0] contains the full path of the
\param[in] bufSize is the input and output buffer size of the \param[in] bufSize is the input and output buffer size of the
stream used to communicate with the child process. stream used to communicate with the child process.


\throws runtime_error if an error occurs.

*/ */
ChildStream(std::vector<std::string> args, size_t bufSize = 4096);
ChildStream(std::vector<std::string> const &args, size_t bufSize = 4096);


/** Constructor for spawning without command-line parameters. /** Constructor for spawning without command-line parameters.


The constructor configures the object, but doesn't spawn the
child process.
The constructor configures the object, and spawns the child
process.


\param[in] childpath contains the child executable file name. \param[in] childpath contains the child executable file name.


\param[in] bufSize is the input and output buffer size of the \param[in] bufSize is the input and output buffer size of the
stream used to communicate with the child process. stream used to communicate with the child process.


\throws runtime_error if an error occurs.

*/
ChildStream(std::string const &childpath, size_t bufSize = 4096);

/** Constructor.

The constructor configures the I/O buffers, but doesn't spawn
any child process.

\param[in] bufSize is the input and output buffer size of the
stream used to communicate with the child process.

*/ */
ChildStream(std::string childpath, size_t bufSize = 4096);
ChildStream(size_t bufSize = 4096);


/** Destructor terminates the child process. */ /** Destructor terminates the child process. */
~ChildStream(); ~ChildStream();


/** 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.

\throws runtime_error if an error occurs.

\throws runtime_error if an error occurs.

*/
void open(std::vector<std::string> const &args);

/** Spawn the child process.

\param[in] childpath contains the child executable file name.

\throws runtime_error if an error occurs.

*/
void open(std::string const &childpath);

/** Get the number of bytes available for input. /** Get the number of bytes available for input.


@returns number of bytes that can be read without blocking. @returns number of bytes that can be read without blocking.
*/ */
size_t numBytesAvailable() const; size_t numBytesAvailable() const;


/** Spawn the child process.
/** Check whether the child process is running.


\throws runtime_error if an error occurs.
\returns True if the child process is running, false
otherwise.


*/ */
void run();
bool isRunning() const;


/** Terminite the child process. /** Terminite the child process.


\throws logic_error if the child process is not running. \throws logic_error if the child process is not running.


*/ */
void terminate();
void close();


/** Check whether the child process has exited. /** Check whether the child process has exited.




private: private:


/** Spawn the child process.

\throws runtime_error if an error occurs.

*/
void run();

/// Exit code to use when terminating the child process. /// Exit code to use when terminating the child process.
static const uint32_t terminateExitCode = 0; static const uint32_t terminateExitCode = 0;


/// Child executable path and command-line parameters. /// Child executable path and command-line parameters.
std::vector<std::string> cmdArgs; std::vector<std::string> cmdArgs;


/// Child executable path and command-line parameters.
std::string cmdline;

#ifdef _WIN32 #ifdef _WIN32
/// Child's process handle. /// Child's process handle.
HANDLE childProcess; HANDLE childProcess;

Loading…
Cancel
Save