Browse Source

Added Child::closeStdIn().


git-svn-id: https://svn.microneil.com/svn/CodeDweller/branches/adeniz_1@97 d34b734f-a00e-4b39-a726-e4eeb87269ab
adeniz_1
adeniz 9 years ago
parent
commit
5e81074c11
2 changed files with 170 additions and 52 deletions
  1. 137
    47
      child.cpp
  2. 33
    5
      child.hpp

+ 137
- 47
child.cpp View File

nWriteBytes = 0; nWriteBytes = 0;
nTransmitBytes = 0; nTransmitBytes = 0;
threadsAreRunning = false;
stopFlag = true;
readerThreadIsRunning = false;
writerThreadIsRunning = false;
stopReaderFlag = true;
stopWriterFlag = true;
errorText.clear(); errorText.clear();
} }
(0 == nTransmitBytes) ); (0 == nTransmitBytes) );
} }
bool Child::closeInput(std::string &errorString) {
#ifdef _WIN32
// Close if not already closed.
if ( (NULL != inputHandle) &&
(CloseHandle(inputHandle) == 0) ) {
errorString += (errorString.empty() ? "" : "\n");
errorString += "Error closing input to the child: " + getErrorText();
return false;
}
// Closed successfully.
inputHandle = NULL;
return true;
#else
// Close if not already closed.
if ( (-1 != inputFileDescriptor) &&
(0 != ::close(inputFileDescriptor)) ) {
errorString += (errorString.empty() ? "" : "\n");
errorString += "Error closing input to the child: " + getErrorText();
return false;
}
// Closed successfully.
inputFileDescriptor = -1;
return true;
#endif
}
bool Child::closeOutput(std::string &errorString) {
#ifdef _WIN32
// Close if not already closed.
if ( (NULL != outputHandle) &&
(CloseHandle(outputHandle) == 0) ) {
errorString += (errorString.empty() ? "" : "\n");
errorString += "Error closing output to the child: " + getErrorText();
return false;
}
// Closed successfully.
outputHandle = NULL;
return true;
#else
// Close if not already closed.
if ( (-1 != outputFileDescriptor) &&
(0 != ::close(outputFileDescriptor)) ) {
errorString += (errorString.empty() ? "" : "\n");
errorString += "Error closing output to the child: " + getErrorText();
return false;
}
// Closed successfully.
outputFileDescriptor = -1;
return true;
#endif
}
void Child::closeStdIn() {
if (!childStarted) {
throw std::logic_error("Child process was not started "
"when close() was called");
}
// Stop writer thread. Note: None of the error conditions that
// cause an exception to be thrown by join() can ever occur.
stopWriterFlag = true;
std::string errorString;
if (!closeOutput(errorString)) {
throw std::runtime_error(errorString);
}
if (writerThreadIsRunning) {
writerThread.join();
writerThreadIsRunning = false;
}
}
void Child::close() { void Child::close() {
if (!childStarted) { if (!childStarted) {
// Stop the reader and writer threads. Note: None of the error // Stop the reader and writer threads. Note: None of the error
// conditions that cause an exception to be thrown by join() // conditions that cause an exception to be thrown by join()
// can ever occur. // can ever occur.
stopFlag = true;
stopReaderFlag = true;
stopWriterFlag = true;
// Terminate the child if it's running. // Terminate the child if it's running.
if (isRunning()) { if (isRunning()) {
std::string errorString; std::string errorString;
bool errorOccurred = false;
bool noErrorOccurred = true;
#ifdef _WIN32 #ifdef _WIN32
// Ignore errors. Reason: Terminating a proces that doesn't // Ignore errors. Reason: Terminating a proces that doesn't
// exist (e.g. has exited) gives an error. // exist (e.g. has exited) gives an error.
(void) TerminateProcess(childProcess, terminateExitCode); (void) TerminateProcess(childProcess, terminateExitCode);
if (CloseHandle(inputHandle) == 0) {
errorString = "Error closing input from the child: " + getErrorText();
errorOccurred = true;
}
if (CloseHandle(outputHandle) == 0) {
errorString += (errorOccurred ? "\n" : "");
errorString += "Error closing output to the child: " + getErrorText();
errorOccurred = true;
}
noErrorOccurred = noErrorOccurred && closeInput(errorString);
noErrorOccurred = noErrorOccurred && closeOutput(errorString);
#else #else
if (0 != ::close(inputFileDescriptor)) {
errorString = "Error closing input from the child: " + getErrorText();
errorOccurred = true;
}
if (0 != ::close(outputFileDescriptor)) {
errorString += (errorOccurred ? "\n" : "");
errorString += "Error closing output to the child: " + getErrorText();
errorOccurred = true;
}
noErrorOccurred = noErrorOccurred && closeInput(errorString);
noErrorOccurred = noErrorOccurred && closeOutput(errorString);
if (kill(childPid, SIGKILL) != 0) { if (kill(childPid, SIGKILL) != 0) {
errorString += (errorOccurred ? "\n" : "");
errorString += (errorString.empty() ? "" : "\n");
errorString += "Error terminating the child process: " + errorString += "Error terminating the child process: " +
getErrorText(); getErrorText();
errorOccurred = true;
noErrorOccurred = false;
} else if (waitpid(childPid, NULL, 0) != childPid) { } else if (waitpid(childPid, NULL, 0) != childPid) {
errorString += (errorOccurred ? "\n" : "");
errorString += (errorString.empty() ? "" : "\n");
errorString += "Error waiting for the child process: " + errorString += "Error waiting for the child process: " +
getErrorText(); getErrorText();
errorOccurred = true;
noErrorOccurred = false;
} }
#endif #endif
if (errorOccurred) {
if (!noErrorOccurred) {
throw std::runtime_error(errorString); throw std::runtime_error(errorString);
} }
} }
if (threadsAreRunning) {
if (readerThreadIsRunning) {
readerThread.join(); readerThread.join();
readerThreadIsRunning = false;
}
if (writerThreadIsRunning) {
writerThread.join(); writerThread.join();
threadsAreRunning = false;
writerThreadIsRunning = false;
} }
// Reset. // Reset.
childStarted = true; childStarted = true;
// Start the reader and writer threads. // Start the reader and writer threads.
stopFlag = false;
stopReaderFlag = false;
stopWriterFlag = false;
try { try {
} catch (std::exception &e) { } catch (std::exception &e) {
stopFlag = true;
stopReaderFlag = true;
stopWriterFlag = true;
readerThread.join(); readerThread.join();
throw std::runtime_error("Error starting writer thread: " + throw std::runtime_error("Error starting writer thread: " +
} }
threadsAreRunning = true;
readerThreadIsRunning = true;
writerThreadIsRunning = true;
} }
childExited = true; childExited = true;
// Stop threads. // Stop threads.
stopFlag = true;
readerThread.join();
writerThread.join();
threadsAreRunning = false;
stopReaderFlag = true;
stopWriterFlag = true;
if (readerThreadIsRunning) {
readerThread.join();
readerThreadIsRunning = false;
}
if (writerThreadIsRunning) {
writerThread.join();
writerThreadIsRunning = false;
}
return true; return true;
CodeDweller::PollTimer pollTimer(nominalPollTime_ms, maximumPollTime_ms); CodeDweller::PollTimer pollTimer(nominalPollTime_ms, maximumPollTime_ms);
while (!stopFlag) {
while (!stopReaderFlag) {
char *bufferPtr; char *bufferPtr;
&nBytesRead, &nBytesRead,
NULL)) { NULL)) {
if (stopFlag) {
if (stopReaderFlag) {
break; break;
} }
bufferCapacity); bufferCapacity);
if (-1 == nBytesRead) { if (-1 == nBytesRead) {
if (stopFlag) {
if (stopReaderFlag) {
break; break;
} }
#endif #endif
// Copy to the shared read buffer. // Copy to the shared read buffer.
while ((nBytesRead > 0) && !stopFlag) {
while ((nBytesRead > 0) && !stopReaderFlag) {
int nBytesToPut, nBytesFree; int nBytesToPut, nBytesFree;
CodeDweller::PollTimer pollTimer(nominalPollTime_ms, maximumPollTime_ms); CodeDweller::PollTimer pollTimer(nominalPollTime_ms, maximumPollTime_ms);
while (!stopFlag) {
while (!stopWriterFlag) {
char *bufferPtr; char *bufferPtr;
// Poll for data in the shared write buffer. // Poll for data in the shared write buffer.
while ((0 == nWriteBytes) && !stopFlag) {
while ((0 == nWriteBytes) && !stopWriterFlag) {
pollTimer.pause(); pollTimer.pause();
} }
if (stopFlag) {
if (stopWriterFlag) {
goto exit; goto exit;
} }
nWriteBytes = 0; nWriteBytes = 0;
} }
if (stopFlag) {
if (stopWriterFlag) {
goto exit; goto exit;
} }
&nBytesWritten, &nBytesWritten,
NULL)) { NULL)) {
if (stopFlag) {
if (stopWriterFlag) {
goto exit; goto exit;
} }
} }
if (stopFlag) {
if (stopWriterFlag) {
goto exit; goto exit;
} }
#else #else
bufferPtr, bufferPtr,
nLocalWriteBytes); nLocalWriteBytes);
if (stopFlag) {
if (stopWriterFlag) {
goto exit; goto exit;
} }

+ 33
- 5
child.hpp View File

*/ */
bool errorOccurred(std::string &errorDescription) const; bool errorOccurred(std::string &errorDescription) const;


/** Close the child process' standard input connection. */
void closeStdIn();

/** Close the connection. /** Close the connection.


This method terminate the child process if it is running, and This method terminate the child process if it is running, and
*/ */
void run(); void run();


/** Close the output connection to the child.

\param[in, out] errMesg is updated with a description of any
error that occurs.

\returns true if the connection was closed successfully.

*/
bool closeOutput(std::string &errMesg);

/** Close the input connection to the child.

\param[in, out] errMesg is updated with a description of any
error that occurs.

\returns true if the connection was closed successfully.

*/
bool closeInput(std::string &errMesg);

/// Reader thread object. /// Reader thread object.
std::thread readerThread; std::thread readerThread;


/// Thread start function to send data to the child. /// Thread start function to send data to the child.
void writeToChild(); void writeToChild();


/// True if readerThread and writerThread are to stop.
bool stopFlag;
/// True if readerThread is to stop.
bool stopReaderFlag;

/// True if writerThread is to stop.
bool stopWriterFlag;

/// True if the reader thread is running, false otherwise.
bool readerThreadIsRunning;


/// True if both the reader and writer the writer threads are
/// running, false otherwise.
bool threadsAreRunning;
/// True if the writer thread is running, false otherwise.
bool writerThreadIsRunning;


/// Description of any error. /// Description of any error.
std::string errorText; std::string errorText;

Loading…
Cancel
Save