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

@@ -851,8 +851,10 @@ namespace CodeDweller {
nWriteBytes = 0;
nTransmitBytes = 0;
threadsAreRunning = false;
stopFlag = true;
readerThreadIsRunning = false;
writerThreadIsRunning = false;
stopReaderFlag = true;
stopWriterFlag = true;
errorText.clear();
}
@@ -862,6 +864,90 @@ namespace CodeDweller {
(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() {
if (!childStarted) {
@@ -872,62 +958,57 @@ namespace CodeDweller {
// Stop the reader and writer threads. Note: None of the error
// conditions that cause an exception to be thrown by join()
// can ever occur.
stopFlag = true;
stopReaderFlag = true;
stopWriterFlag = true;
// Terminate the child if it's running.
if (isRunning()) {
std::string errorString;
bool errorOccurred = false;
bool noErrorOccurred = true;
#ifdef _WIN32
// Ignore errors. Reason: Terminating a proces that doesn't
// exist (e.g. has exited) gives an error.
(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
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) {
errorString += (errorOccurred ? "\n" : "");
errorString += (errorString.empty() ? "" : "\n");
errorString += "Error terminating the child process: " +
getErrorText();
errorOccurred = true;
noErrorOccurred = false;
} else if (waitpid(childPid, NULL, 0) != childPid) {
errorString += (errorOccurred ? "\n" : "");
errorString += (errorString.empty() ? "" : "\n");
errorString += "Error waiting for the child process: " +
getErrorText();
errorOccurred = true;
noErrorOccurred = false;
}
#endif
if (errorOccurred) {
if (!noErrorOccurred) {
throw std::runtime_error(errorString);
}
}
if (threadsAreRunning) {
if (readerThreadIsRunning) {
readerThread.join();
readerThreadIsRunning = false;
}
if (writerThreadIsRunning) {
writerThread.join();
threadsAreRunning = false;
writerThreadIsRunning = false;
}
// Reset.
@@ -1183,7 +1264,8 @@ namespace CodeDweller {
childStarted = true;
// Start the reader and writer threads.
stopFlag = false;
stopReaderFlag = false;
stopWriterFlag = false;
try {
@@ -1204,7 +1286,8 @@ namespace CodeDweller {
} catch (std::exception &e) {
stopFlag = true;
stopReaderFlag = true;
stopWriterFlag = true;
readerThread.join();
throw std::runtime_error("Error starting writer thread: " +
@@ -1212,7 +1295,8 @@ namespace CodeDweller {
}
threadsAreRunning = true;
readerThreadIsRunning = true;
writerThreadIsRunning = true;
}
@@ -1274,10 +1358,16 @@ namespace CodeDweller {
childExited = true;
// 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;
@@ -1341,7 +1431,7 @@ namespace CodeDweller {
CodeDweller::PollTimer pollTimer(nominalPollTime_ms, maximumPollTime_ms);
while (!stopFlag) {
while (!stopReaderFlag) {
char *bufferPtr;
@@ -1357,7 +1447,7 @@ namespace CodeDweller {
&nBytesRead,
NULL)) {
if (stopFlag) {
if (stopReaderFlag) {
break;
}
@@ -1381,7 +1471,7 @@ namespace CodeDweller {
bufferCapacity);
if (-1 == nBytesRead) {
if (stopFlag) {
if (stopReaderFlag) {
break;
}
@@ -1398,7 +1488,7 @@ namespace CodeDweller {
#endif
// Copy to the shared read buffer.
while ((nBytesRead > 0) && !stopFlag) {
while ((nBytesRead > 0) && !stopReaderFlag) {
int nBytesToPut, nBytesFree;
@@ -1438,16 +1528,16 @@ namespace CodeDweller {
CodeDweller::PollTimer pollTimer(nominalPollTime_ms, maximumPollTime_ms);
while (!stopFlag) {
while (!stopWriterFlag) {
char *bufferPtr;
// Poll for data in the shared write buffer.
while ((0 == nWriteBytes) && !stopFlag) {
while ((0 == nWriteBytes) && !stopWriterFlag) {
pollTimer.pause();
}
if (stopFlag) {
if (stopWriterFlag) {
goto exit;
}
@@ -1460,7 +1550,7 @@ namespace CodeDweller {
nWriteBytes = 0;
}
if (stopFlag) {
if (stopWriterFlag) {
goto exit;
}
@@ -1480,7 +1570,7 @@ namespace CodeDweller {
&nBytesWritten,
NULL)) {
if (stopFlag) {
if (stopWriterFlag) {
goto exit;
}
@@ -1490,7 +1580,7 @@ namespace CodeDweller {
}
if (stopFlag) {
if (stopWriterFlag) {
goto exit;
}
#else
@@ -1500,7 +1590,7 @@ namespace CodeDweller {
bufferPtr,
nLocalWriteBytes);
if (stopFlag) {
if (stopWriterFlag) {
goto exit;
}

+ 33
- 5
child.hpp View File

@@ -1159,6 +1159,9 @@ namespace CodeDweller {
*/
bool errorOccurred(std::string &errorDescription) const;

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

/** Close the connection.

This method terminate the child process if it is running, and
@@ -1211,6 +1214,26 @@ namespace CodeDweller {
*/
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.
std::thread readerThread;

@@ -1223,12 +1246,17 @@ namespace CodeDweller {
/// Thread start function to send data to the child.
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.
std::string errorText;

Loading…
Cancel
Save