Parcourir la 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 il y a 9 ans
Parent
révision
20af91c0a2
2 fichiers modifiés avec 120 ajouts et 66 suppressions
  1. 64
    53
      child.cpp
  2. 56
    13
      child.hpp

+ 64
- 53
child.cpp Voir le fichier

@@ -37,33 +37,40 @@
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),
std::iostream(&childStreambuf),
cmdArgs(args) {
init();
run();
}
ChildStream::ChildStream(std::string childpath, size_t bufSize) :
ChildStream::ChildStream(std::string const &childpath, size_t bufSize) :
childStreambuf(bufSize),
std::iostream(&childStreambuf),
cmdline(childpath) {
std::iostream(&childStreambuf) {
cmdArgs.push_back(childpath);
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;
childExited = false;
@@ -71,21 +78,40 @@ namespace CodeDweller {
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();
}
void
ChildStream::run() {
bool ChildStream::isRunning() const {
return childStarted && !childExited;
}
void ChildStream::run() {
if (childStarted) {
throw std::logic_error("Child process was active when "
"run() was called");
}
if (cmdArgs.empty()) {
throw std::invalid_argument("A child executable must be specified.");
}
#ifdef _WIN32
// Set the bInheritHandle flag so pipe handles are inherited.
SECURITY_ATTRIBUTES securityAttributes;
@@ -221,8 +247,8 @@ namespace CodeDweller {
getErrorText());
}
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: " +
getErrorText());
}
@@ -231,8 +257,8 @@ namespace CodeDweller {
childPid = fork();
if (-1 == childPid) {
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: " +
getErrorText());
@@ -261,10 +287,10 @@ namespace CodeDweller {
}
// 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;
// Send message to parent.
@@ -295,16 +321,14 @@ namespace CodeDweller {
}
// std::cout << "Child pid: " << childPid << std::endl; // DEBUG.
// Provide the stream buffers with the file descriptors for
// communicating with the child process.
childStreambuf.setInputFileDescriptor(childStdOutPipe[0]);
childStreambuf.setOutputFileDescriptor(childStdInPipe[1]);
// 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;
throw std::runtime_error("Error closing child's end of pipes in "
@@ -317,8 +341,7 @@ namespace CodeDweller {
}
void
ChildStream::terminate() {
void ChildStream::close() {
if (isDone()) {
@@ -337,8 +360,7 @@ namespace CodeDweller {
}
bool
ChildStream::isDone() {
bool ChildStream::isDone() {
if (childExited) {
@@ -399,8 +421,7 @@ namespace CodeDweller {
}
int32_t
ChildStream::result() {
int32_t ChildStream::result() {
if (exitCodeObtainedFlag) {
@@ -427,8 +448,7 @@ namespace CodeDweller {
}
std::string
ChildStream::getErrorText() {
std::string ChildStream::getErrorText() {
#ifdef _WIN32
LPVOID winMsgBuf;
@@ -479,23 +499,20 @@ namespace CodeDweller {
}
#ifdef _WIN32
void
ChildStream::ChildStreambuf::setInputHandle(HANDLE inHandle) {
void ChildStream::ChildStreambuf::setInputHandle(HANDLE inHandle) {
inputHandle = inHandle;
}
#else
void
ChildStream::ChildStreambuf::setInputFileDescriptor(int inFd) {
void ChildStream::ChildStreambuf::setInputFileDescriptor(int inFd) {
inputFileDescriptor = inFd;
}
#endif
size_t
ChildStream::ChildStreambuf::numBytesAvailable() const {
size_t ChildStream::ChildStreambuf::numBytesAvailable() const {
size_t nBytesAvailable = egptr() - gptr();
@@ -537,8 +554,7 @@ namespace CodeDweller {
}
std::streambuf::int_type
ChildStream::ChildStreambuf::underflow() {
std::streambuf::int_type ChildStream::ChildStreambuf::underflow() {
// Check for empty buffer.
if (gptr() < egptr()) {
@@ -595,23 +611,20 @@ namespace CodeDweller {
}
#ifdef _WIN32
void
ChildStream::ChildStreambuf::setOutputHandle(HANDLE outHandle) {
void ChildStream::ChildStreambuf::setOutputHandle(HANDLE outHandle) {
outputHandle = outHandle;
}
#else
void
ChildStream::ChildStreambuf::setOutputFileDescriptor(int outFd) {
void ChildStream::ChildStreambuf::setOutputFileDescriptor(int outFd) {
outputFileDescriptor = outFd;
}
#endif
void
ChildStream::ChildStreambuf::flushBuffer() {
void ChildStream::ChildStreambuf::flushBuffer() {
// Write.
std::ptrdiff_t nBytes = pptr() - pbase();
@@ -648,8 +661,7 @@ namespace CodeDweller {
}
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.
if (traits_type::eof() != ch) {
@@ -670,8 +682,7 @@ namespace CodeDweller {
}
int
ChildStream::ChildStreambuf::sync() {
int ChildStream::ChildStreambuf::sync() {
flushBuffer(); // Throws exception on failure.

+ 56
- 13
child.hpp Voir le fichier

@@ -172,8 +172,8 @@ namespace CodeDweller {

/** 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
command-line parameters. args[0] contains the full path of the
@@ -183,25 +183,63 @@ namespace CodeDweller {
\param[in] bufSize is the input and output buffer size of the
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.

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] bufSize is the input and output buffer size of the
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. */
~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.

@returns number of bytes that can be read without blocking.
@@ -209,12 +247,13 @@ namespace CodeDweller {
*/
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.

@@ -223,7 +262,7 @@ namespace CodeDweller {
\throws logic_error if the child process is not running.

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

/** Check whether the child process has exited.

@@ -253,6 +292,13 @@ namespace CodeDweller {

private:

/** Spawn the child process.

\throws runtime_error if an error occurs.

*/
void run();

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

@@ -268,9 +314,6 @@ namespace CodeDweller {
/// Child executable path and command-line parameters.
std::vector<std::string> cmdArgs;

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

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

Chargement…
Annuler
Enregistrer