Attachment "patch.txt" to
ticket [597924ffff]
added by
davygrvy
2002-11-21 15:13:04.
*** win/tclWinConsole.c 7 Nov 2002 02:13:37 -0000 1.9
--- win/tclWinConsole.c 21 Nov 2002 07:47:42 -0000
***************
*** 79,87 ****
--- 79,93 ----
HANDLE startWriter; /* Auto-reset event used by the main thread to
* signal when the writer thread should attempt
* to write to the console. */
+ HANDLE stopWriter; /* Auto-reset event used by the main thread to
+ * signal when the writer thread should exit.
+ */
HANDLE startReader; /* Auto-reset event used by the main thread to
* signal when the reader thread should attempt
* to read from the console. */
+ HANDLE stopReader; /* Auto-reset event used by the main thread to
+ * signal when the reader thread should exit.
+ */
DWORD writeError; /* An error caused by the last background
* write. Set to 0 if no error has been
* detected. This word is shared with the
***************
*** 458,463 ****
--- 464,470 ----
int errorCode;
ConsoleInfo *infoPtr, **nextPtrPtr;
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
+ DWORD exitCode;
errorCode = 0;
***************
*** 468,497 ****
*/
if (consolePtr->readThread) {
/*
! * Forcibly terminate the background thread. We cannot rely on the
! * thread to cleanly terminate itself because we have no way of
! * closing the handle without blocking in the case where the
! * thread is in the middle of an I/O operation. Note that we need
! * to guard against terminating the thread while it is in the
! * middle of Tcl_ThreadAlert because it won't be able to release
! * the notifier lock.
*/
! Tcl_MutexLock(&consoleMutex);
! TerminateThread(consolePtr->readThread, 0);
! /*
! * Wait for the thread to terminate. This ensures that we are
! * completely cleaned up before we leave this function.
! */
! WaitForSingleObject(consolePtr->readThread, INFINITE);
! Tcl_MutexUnlock(&consoleMutex);
CloseHandle(consolePtr->readThread);
CloseHandle(consolePtr->readable);
CloseHandle(consolePtr->startReader);
consolePtr->readThread = NULL;
}
consolePtr->validMask &= ~TCL_READABLE;
--- 475,524 ----
*/
if (consolePtr->readThread) {
+
/*
! * The thread may already have closed on it's own. Check it's
! * exit code.
*/
! GetExitCodeThread(consolePtr->readThread, &exitCode);
! if (exitCode == STILL_ACTIVE) {
! /*
! * Set the stop event so that if the reader thread is blocked
! * in ConsoleReaderThread on WaitForMultipleEvents, it will exit
! * cleanly.
! */
!
! SetEvent(consolePtr->stopReader);
!
! /*
! * Wait at most 20 milliseconds for the reader thread to close.
! */
!
! if (WaitForSingleObject(consolePtr->readThread, 20)
! == WAIT_TIMEOUT) {
! /*
! * Forcibly terminate the background thread as a last
! * resort. Note that we need to guard against
! * terminating the thread while it is in the middle of
! * Tcl_ThreadAlert because it won't be able to release
! * the notifier lock.
! */
!
! Tcl_MutexLock(&consoleMutex);
!
! /* BUG: this leaks memory. */
! TerminateThread(consolePtr->readThread, 0);
! Tcl_MutexUnlock(&consoleMutex);
! }
! }
CloseHandle(consolePtr->readThread);
CloseHandle(consolePtr->readable);
CloseHandle(consolePtr->startReader);
+ CloseHandle(consolePtr->stopReader);
consolePtr->readThread = NULL;
}
consolePtr->validMask &= ~TCL_READABLE;
***************
*** 512,540 ****
}
/*
! * Forcibly terminate the background thread. We cannot rely on the
! * thread to cleanly terminate itself because we have no way of
! * closing the handle without blocking in the case where the
! * thread is in the middle of an I/O operation. Note that we need
! * to guard against terminating the thread while it is in the
! * middle of Tcl_ThreadAlert because it won't be able to release
! * the notifier lock.
*/
! Tcl_MutexLock(&consoleMutex);
! TerminateThread(consolePtr->writeThread, 0);
! /*
! * Wait for the thread to terminate. This ensures that we are
! * completely cleaned up before we leave this function.
! */
! WaitForSingleObject(consolePtr->writeThread, INFINITE);
! Tcl_MutexUnlock(&consoleMutex);
CloseHandle(consolePtr->writeThread);
CloseHandle(consolePtr->writable);
CloseHandle(consolePtr->startWriter);
consolePtr->writeThread = NULL;
}
consolePtr->validMask &= ~TCL_WRITABLE;
--- 539,583 ----
}
/*
! * The thread may already have closed on it's own. Check it's
! * exit code.
*/
! GetExitCodeThread(consolePtr->writeThread, &exitCode);
! if (exitCode == STILL_ACTIVE) {
! /*
! * Set the stop event so that if the reader thread is blocked
! * in ConsoleWriterThread on WaitForMultipleEvents, it will
! * exit cleanly.
! */
! SetEvent(consolePtr->stopWriter);
!
! /*
! * Wait at most 20 milliseconds for the writer thread to close.
! */
!
! if (WaitForSingleObject(consolePtr->writeThread, 20)
! == WAIT_TIMEOUT) {
! /*
! * Forcibly terminate the background thread as a last
! * resort. Note that we need to guard against
! * terminating the thread while it is in the middle of
! * Tcl_ThreadAlert because it won't be able to release
! * the notifier lock.
! */
!
! Tcl_MutexLock(&consoleMutex);
! TerminateThread(consolePtr->writeThread, 0);
! Tcl_MutexUnlock(&consoleMutex);
! }
! }
CloseHandle(consolePtr->writeThread);
CloseHandle(consolePtr->writable);
CloseHandle(consolePtr->startWriter);
+ CloseHandle(consolePtr->stopWriter);
consolePtr->writeThread = NULL;
}
consolePtr->validMask &= ~TCL_WRITABLE;
***************
*** 1066,1079 ****
{
ConsoleInfo *infoPtr = (ConsoleInfo *)arg;
HANDLE *handle = infoPtr->handle;
! DWORD count;
for (;;) {
/*
* Wait for the main thread to signal before attempting to wait.
*/
! WaitForSingleObject(infoPtr->startReader, INFINITE);
count = 0;
--- 1109,1136 ----
{
ConsoleInfo *infoPtr = (ConsoleInfo *)arg;
HANDLE *handle = infoPtr->handle;
! DWORD count, waitResult;
! HANDLE wEvents[2];
!
! /* The first event takes precedence. */
! wEvents[0] = infoPtr->stopReader;
! wEvents[1] = infoPtr->startReader;
for (;;) {
/*
* Wait for the main thread to signal before attempting to wait.
*/
! waitResult = WaitForMultipleObjects(2, wEvents, FALSE, INFINITE);
!
! if (waitResult != (WAIT_OBJECT_0 + 1)) {
! /*
! * The start event was not signaled. It must be the stop event
! * or an error, so exit this thread.
! */
!
! break;
! }
count = 0;
***************
*** 1081,1087 ****
* Look for data on the console, but first ignore any events
* that are not KEY_EVENTs
*/
! if (ReadConsole(handle, infoPtr->buffer, CONSOLE_BUFFER_SIZE,
(LPDWORD) &infoPtr->bytesRead, NULL) != FALSE) {
/*
* Data was stored in the buffer.
--- 1138,1144 ----
* Look for data on the console, but first ignore any events
* that are not KEY_EVENTs
*/
! if (ReadConsoleA(handle, infoPtr->buffer, CONSOLE_BUFFER_SIZE,
(LPDWORD) &infoPtr->bytesRead, NULL) != FALSE) {
/*
* Data was stored in the buffer.
***************
*** 1114,1120 ****
Tcl_ThreadAlert(infoPtr->threadId);
Tcl_MutexUnlock(&consoleMutex);
}
! return 0; /* NOT REACHED */
}
/*
--- 1171,1178 ----
Tcl_ThreadAlert(infoPtr->threadId);
Tcl_MutexUnlock(&consoleMutex);
}
!
! return 0;
}
/*
***************
*** 1141,1155 ****
ConsoleInfo *infoPtr = (ConsoleInfo *)arg;
HANDLE *handle = infoPtr->handle;
! DWORD count, toWrite;
char *buf;
for (;;) {
/*
* Wait for the main thread to signal before attempting to write.
*/
! WaitForSingleObject(infoPtr->startWriter, INFINITE);
buf = infoPtr->writeBuf;
toWrite = infoPtr->toWrite;
--- 1199,1227 ----
ConsoleInfo *infoPtr = (ConsoleInfo *)arg;
HANDLE *handle = infoPtr->handle;
! DWORD count, toWrite, waitResult;
char *buf;
+ HANDLE wEvents[2];
+
+ /* The first event takes precedence. */
+ wEvents[0] = infoPtr->stopWriter;
+ wEvents[1] = infoPtr->startWriter;
for (;;) {
/*
* Wait for the main thread to signal before attempting to write.
*/
! waitResult = WaitForMultipleObjects(2, wEvents, FALSE, INFINITE);
!
! if (waitResult != (WAIT_OBJECT_0 + 1)) {
! /*
! * The start event was not signaled. It must be the stop event
! * or an error, so exit this thread.
! */
!
! break;
! }
buf = infoPtr->writeBuf;
toWrite = infoPtr->toWrite;
***************
*** 1159,1165 ****
*/
while (toWrite > 0) {
! if (WriteFile(handle, buf, toWrite, &count, NULL) == FALSE) {
infoPtr->writeError = GetLastError();
break;
} else {
--- 1231,1237 ----
*/
while (toWrite > 0) {
! if (WriteConsoleA(handle, buf, toWrite, &count, NULL) == FALSE) {
infoPtr->writeError = GetLastError();
break;
} else {
***************
*** 1185,1191 ****
Tcl_ThreadAlert(infoPtr->threadId);
Tcl_MutexUnlock(&consoleMutex);
}
! return 0; /* NOT REACHED */
}
--- 1257,1264 ----
Tcl_ThreadAlert(infoPtr->threadId);
Tcl_MutexUnlock(&consoleMutex);
}
!
! return 0;
}
***************
*** 1217,1223 ****
char encoding[4 + TCL_INTEGER_SPACE];
ConsoleInfo *infoPtr;
ThreadSpecificData *tsdPtr;
! DWORD id;
tsdPtr = ConsoleInit();
--- 1290,1296 ----
char encoding[4 + TCL_INTEGER_SPACE];
ConsoleInfo *infoPtr;
ThreadSpecificData *tsdPtr;
! DWORD id, modes;
tsdPtr = ConsoleInit();
***************
*** 1232,1238 ****
infoPtr->handle = handle;
wsprintfA(encoding, "cp%d", GetConsoleCP());
!
/*
* Use the pointer for the name of the result channel.
* This keeps the channel names unique, since some may share
--- 1305,1311 ----
infoPtr->handle = handle;
wsprintfA(encoding, "cp%d", GetConsoleCP());
!
/*
* Use the pointer for the name of the result channel.
* This keeps the channel names unique, since some may share
***************
*** 1247,1264 ****
infoPtr->threadId = Tcl_GetCurrentThread();
if (permissions & TCL_READABLE) {
infoPtr->readable = CreateEvent(NULL, TRUE, TRUE, NULL);
infoPtr->startReader = CreateEvent(NULL, FALSE, FALSE, NULL);
! infoPtr->readThread = CreateThread(NULL, 8000, ConsoleReaderThread,
infoPtr, 0, &id);
! SetThreadPriority(infoPtr->readThread, THREAD_PRIORITY_HIGHEST);
}
if (permissions & TCL_WRITABLE) {
infoPtr->writable = CreateEvent(NULL, TRUE, TRUE, NULL);
infoPtr->startWriter = CreateEvent(NULL, FALSE, FALSE, NULL);
! infoPtr->writeThread = CreateThread(NULL, 8000, ConsoleWriterThread,
infoPtr, 0, &id);
}
/*
--- 1320,1351 ----
infoPtr->threadId = Tcl_GetCurrentThread();
if (permissions & TCL_READABLE) {
+ /*
+ * Make sure the console input buffer is ready for only character
+ * input notifications and the buffer is set for line buffering.
+ * IOW, we only want to catch when complete lines are ready for
+ * reading.
+ */
+ GetConsoleMode(infoPtr->handle, &modes);
+ modes &= ~(ENABLE_WINDOW_INPUT | ENABLE_MOUSE_INPUT);
+ modes |= ENABLE_LINE_INPUT;
+ SetConsoleMode(infoPtr->handle, modes);
+
infoPtr->readable = CreateEvent(NULL, TRUE, TRUE, NULL);
infoPtr->startReader = CreateEvent(NULL, FALSE, FALSE, NULL);
! infoPtr->stopReader = CreateEvent(NULL, FALSE, FALSE, NULL);
! infoPtr->readThread = CreateThread(NULL, 256, ConsoleReaderThread,
infoPtr, 0, &id);
! SetThreadPriority(infoPtr->readThread, THREAD_PRIORITY_HIGHEST);
}
if (permissions & TCL_WRITABLE) {
infoPtr->writable = CreateEvent(NULL, TRUE, TRUE, NULL);
infoPtr->startWriter = CreateEvent(NULL, FALSE, FALSE, NULL);
! infoPtr->stopWriter = CreateEvent(NULL, FALSE, FALSE, NULL);
! infoPtr->writeThread = CreateThread(NULL, 256, ConsoleWriterThread,
infoPtr, 0, &id);
+ SetThreadPriority(infoPtr->writeThread, THREAD_PRIORITY_HIGHEST);
}
/*
*** win/tclWinPipe.c 7 Nov 2002 02:13:37 -0000 1.26
--- win/tclWinPipe.c 21 Nov 2002 07:47:56 -0000
***************
*** 120,125 ****
--- 120,127 ----
HANDLE startWriter; /* Auto-reset event used by the main thread to
* signal when the writer thread should attempt
* to write to the pipe. */
+ HANDLE stopWriter; /* Manual-reset event used to alert the reader
+ * thread to fall-out and exit */
HANDLE startReader; /* Auto-reset event used by the main thread to
* signal when the reader thread should attempt
* to read from the pipe. */
***************
*** 1685,1691 ****
infoPtr->readable = CreateEvent(NULL, TRUE, TRUE, NULL);
infoPtr->startReader = CreateEvent(NULL, FALSE, FALSE, NULL);
infoPtr->stopReader = CreateEvent(NULL, TRUE, FALSE, NULL);
! infoPtr->readThread = CreateThread(NULL, 512, PipeReaderThread,
infoPtr, 0, &id);
SetThreadPriority(infoPtr->readThread, THREAD_PRIORITY_HIGHEST);
infoPtr->validMask |= TCL_READABLE;
--- 1687,1693 ----
infoPtr->readable = CreateEvent(NULL, TRUE, TRUE, NULL);
infoPtr->startReader = CreateEvent(NULL, FALSE, FALSE, NULL);
infoPtr->stopReader = CreateEvent(NULL, TRUE, FALSE, NULL);
! infoPtr->readThread = CreateThread(NULL, 256, PipeReaderThread,
infoPtr, 0, &id);
SetThreadPriority(infoPtr->readThread, THREAD_PRIORITY_HIGHEST);
infoPtr->validMask |= TCL_READABLE;
***************
*** 1699,1705 ****
infoPtr->writable = CreateEvent(NULL, TRUE, TRUE, NULL);
infoPtr->startWriter = CreateEvent(NULL, FALSE, FALSE, NULL);
! infoPtr->writeThread = CreateThread(NULL, 512, PipeWriterThread,
infoPtr, 0, &id);
SetThreadPriority(infoPtr->readThread, THREAD_PRIORITY_HIGHEST);
infoPtr->validMask |= TCL_WRITABLE;
--- 1701,1708 ----
infoPtr->writable = CreateEvent(NULL, TRUE, TRUE, NULL);
infoPtr->startWriter = CreateEvent(NULL, FALSE, FALSE, NULL);
! infoPtr->stopWriter = CreateEvent(NULL, TRUE, FALSE, NULL);
! infoPtr->writeThread = CreateThread(NULL, 256, PipeWriterThread,
infoPtr, 0, &id);
SetThreadPriority(infoPtr->readThread, THREAD_PRIORITY_HIGHEST);
infoPtr->validMask |= TCL_WRITABLE;
***************
*** 1873,1885 ****
SetEvent(pipePtr->stopReader);
/*
! * Wait at most 10 milliseconds for the reader thread to close.
*/
! WaitForSingleObject(pipePtr->readThread, 10);
! GetExitCodeThread(pipePtr->readThread, &exitCode);
!
! if (exitCode == STILL_ACTIVE) {
/*
* The thread must be blocked waiting for the pipe to
* become readable in ReadFile(). There isn't a clean way
--- 1876,1886 ----
SetEvent(pipePtr->stopReader);
/*
! * Wait at most 20 milliseconds for the reader thread to close.
*/
! if (WaitForSingleObject(pipePtr->readThread, 20)
! == WAIT_TIMEOUT) {
/*
* The thread must be blocked waiting for the pipe to
* become readable in ReadFile(). There isn't a clean way
***************
*** 1898,1907 ****
/* BUG: this leaks memory */
TerminateThread(pipePtr->readThread, 0);
-
- /* Wait for the thread to terminate. */
- WaitForSingleObject(pipePtr->readThread, INFINITE);
-
Tcl_MutexUnlock(&pipeMutex);
}
}
--- 1899,1904 ----
***************
*** 1920,1959 ****
}
if ((!flags || (flags & TCL_CLOSE_WRITE))
&& (pipePtr->writeFile != NULL)) {
- /*
- * Wait for the writer thread to finish the current buffer, then
- * terminate the thread and close the handles. If the channel is
- * nonblocking, there should be no pending write operations.
- */
if (pipePtr->writeThread) {
- WaitForSingleObject(pipePtr->writable, INFINITE);
-
/*
! * Forcibly terminate the background thread. We cannot rely on the
! * thread to cleanly terminate itself because we have no way of
! * closing the pipe handle without blocking in the case where the
! * thread is in the middle of an I/O operation. Note that we need
! * to guard against terminating the thread while it is in the
! * middle of Tcl_ThreadAlert because it won't be able to release
! * the notifier lock.
*/
! Tcl_MutexLock(&pipeMutex);
! TerminateThread(pipePtr->writeThread, 0);
/*
! * Wait for the thread to terminate. This ensures that we are
! * completely cleaned up before we leave this function.
*/
! WaitForSingleObject(pipePtr->writeThread, INFINITE);
! Tcl_MutexUnlock(&pipeMutex);
CloseHandle(pipePtr->writeThread);
CloseHandle(pipePtr->writable);
CloseHandle(pipePtr->startWriter);
pipePtr->writeThread = NULL;
}
if (TclpCloseFile(pipePtr->writeFile) != 0) {
--- 1917,1981 ----
}
if ((!flags || (flags & TCL_CLOSE_WRITE))
&& (pipePtr->writeFile != NULL)) {
if (pipePtr->writeThread) {
/*
! * Wait for the writer thread to finish the current buffer,
! * then terminate the thread and close the handles. If the
! * channel is nonblocking, there should be no pending write
! * operations.
*/
! WaitForSingleObject(pipePtr->writable, INFINITE);
/*
! * The thread may already have closed on it's own. Check it's
! * exit code.
*/
! GetExitCodeThread(pipePtr->writeThread, &exitCode);
!
! if (exitCode == STILL_ACTIVE) {
! /*
! * Set the stop event so that if the reader thread is blocked
! * in PipeReaderThread on WaitForMultipleEvents, it will exit
! * cleanly.
! */
!
! SetEvent(pipePtr->stopWriter);
!
! /*
! * Wait at most 20 milliseconds for the reader thread to close.
! */
!
! if (WaitForSingleObject(pipePtr->writeThread, 20)
! == WAIT_TIMEOUT) {
! /*
! * The thread must be blocked waiting for the pipe to
! * consume input in WriteFile(). There isn't a clean way
! * to exit the thread from this condition. We should
! * terminate the child process instead to get the writer
! * thread to fall out of WriteFile with a FALSE. (below) is
! * not the correct way to do this, but will stay here until
! * a better solution is found.
! *
! * Note that we need to guard against terminating the
! * thread while it is in the middle of Tcl_ThreadAlert
! * because it won't be able to release the notifier lock.
! */
+ Tcl_MutexLock(&pipeMutex);
+
+ /* BUG: this leaks memory */
+ TerminateThread(pipePtr->writeThread, 0);
+ Tcl_MutexUnlock(&pipeMutex);
+ }
+ }
CloseHandle(pipePtr->writeThread);
CloseHandle(pipePtr->writable);
CloseHandle(pipePtr->startWriter);
+ CloseHandle(pipePtr->stopWriter);
pipePtr->writeThread = NULL;
}
if (TclpCloseFile(pipePtr->writeFile) != 0) {
***************
*** 2745,2751 ****
DWORD count, err;
int done = 0;
HANDLE wEvents[2];
! DWORD dwWait;
wEvents[0] = infoPtr->stopReader;
wEvents[1] = infoPtr->startReader;
--- 2767,2773 ----
DWORD count, err;
int done = 0;
HANDLE wEvents[2];
! DWORD waitResult;
wEvents[0] = infoPtr->stopReader;
wEvents[1] = infoPtr->startReader;
***************
*** 2756,2770 ****
* on the pipe becoming readable.
*/
! dwWait = WaitForMultipleObjects(2, wEvents, FALSE, INFINITE);
! if (dwWait != (WAIT_OBJECT_0 + 1)) {
/*
* The start event was not signaled. It might be the stop event
* or an error, so exit.
*/
! return 0;
}
/*
--- 2778,2792 ----
* on the pipe becoming readable.
*/
! waitResult = WaitForMultipleObjects(2, wEvents, FALSE, INFINITE);
! if (waitResult != (WAIT_OBJECT_0 + 1)) {
/*
* The start event was not signaled. It might be the stop event
* or an error, so exit.
*/
! break;
}
/*
***************
*** 2832,2837 ****
--- 2854,2860 ----
Tcl_ThreadAlert(infoPtr->threadId);
Tcl_MutexUnlock(&pipeMutex);
}
+
return 0;
}
***************
*** 2862,2874 ****
DWORD count, toWrite;
char *buf;
int done = 0;
while (!done) {
/*
* Wait for the main thread to signal before attempting to write.
*/
! WaitForSingleObject(infoPtr->startWriter, INFINITE);
buf = infoPtr->writeBuf;
toWrite = infoPtr->toWrite;
--- 2885,2911 ----
DWORD count, toWrite;
char *buf;
int done = 0;
+ HANDLE wEvents[2];
+ DWORD waitResult;
+
+ wEvents[0] = infoPtr->stopWriter;
+ wEvents[1] = infoPtr->startWriter;
while (!done) {
/*
* Wait for the main thread to signal before attempting to write.
*/
! waitResult = WaitForMultipleObjects(2, wEvents, FALSE, INFINITE);
!
! if (waitResult != (WAIT_OBJECT_0 + 1)) {
! /*
! * The start event was not signaled. It might be the stop event
! * or an error, so exit.
! */
!
! break;
! }
buf = infoPtr->writeBuf;
toWrite = infoPtr->toWrite;
***************
*** 2905,2910 ****
--- 2942,2948 ----
Tcl_ThreadAlert(infoPtr->threadId);
Tcl_MutexUnlock(&pipeMutex);
}
+
return 0;
}
*** win/tclWinSerial.c 7 Nov 2002 02:13:37 -0000 1.22
--- win/tclWinSerial.c 21 Nov 2002 07:48:04 -0000
***************
*** 103,108 ****
--- 103,111 ----
HANDLE evStartWriter; /* Auto-reset event used by the main thread to
* signal when the writer thread should attempt
* to write to the serial. */
+ HANDLE evStopWriter; /* Auto-reset event used by the main thread to
+ * signal when the writer thread should close.
+ */
DWORD writeError; /* An error caused by the last background
* write. Set to 0 if no error has been
* detected. This word is shared with the
***************
*** 585,590 ****
--- 588,594 ----
int errorCode, result = 0;
SerialInfo *infoPtr, **nextPtrPtr;
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
+ DWORD exitCode;
errorCode = 0;
***************
*** 600,629 ****
* Generally we cannot wait for a pending write operation
* because it may hang due to handshake
* WaitForSingleObject(serialPtr->evWritable, INFINITE);
- */
- /*
- * Forcibly terminate the background thread. We cannot rely on the
- * thread to cleanly terminate itself because we have no way of
- * closing the handle without blocking in the case where the
- * thread is in the middle of an I/O operation. Note that we need
- * to guard against terminating the thread while it is in the
- * middle of Tcl_ThreadAlert because it won't be able to release
- * the notifier lock.
*/
! Tcl_MutexLock(&serialMutex);
! TerminateThread(serialPtr->writeThread, 0);
! Tcl_MutexUnlock(&serialMutex);
!
! /*
! * Wait for the thread to terminate. This ensures that we are
! * completely cleaned up before we leave this function.
! */
- WaitForSingleObject(serialPtr->writeThread, INFINITE);
CloseHandle(serialPtr->writeThread);
CloseHandle(serialPtr->evWritable);
CloseHandle(serialPtr->evStartWriter);
serialPtr->writeThread = NULL;
PurgeComm(serialPtr->handle, PURGE_TXABORT | PURGE_TXCLEAR);
--- 604,655 ----
* Generally we cannot wait for a pending write operation
* because it may hang due to handshake
* WaitForSingleObject(serialPtr->evWritable, INFINITE);
*/
! /*
! * The thread may have already closed on it's own. Check it's
! * exit code.
! */
!
! GetExitCodeThread(serialPtr->writeThread, &exitCode);
!
! if (exitCode == STILL_ACTIVE) {
! /*
! * Set the stop event so that if the writer thread is
! * blocked in SerialWriterThread on WaitForMultipleEvents, it
! * will exit cleanly.
! */
!
! SetEvent(serialPtr->evStopWriter);
!
! /*
! * Wait at most 20 milliseconds for the writer thread to
! * close.
! */
!
! if (WaitForSingleObject(serialPtr->writeThread, 20)
! == WAIT_TIMEOUT) {
! /*
! * Forcibly terminate the background thread as a last
! * resort. Note that we need to guard against
! * terminating the thread while it is in the middle of
! * Tcl_ThreadAlert because it won't be able to release
! * the notifier lock.
! */
!
! Tcl_MutexLock(&serialMutex);
!
! /* BUG: this leaks memory */
! TerminateThread(serialPtr->writeThread, 0);
!
! Tcl_MutexUnlock(&serialMutex);
! }
! }
CloseHandle(serialPtr->writeThread);
CloseHandle(serialPtr->evWritable);
CloseHandle(serialPtr->evStartWriter);
+ CloseHandle(serialPtr->evStopWriter);
serialPtr->writeThread = NULL;
PurgeComm(serialPtr->handle, PURGE_TXABORT | PURGE_TXCLEAR);
***************
*** 637,649 ****
*/
if (!TclInThreadExit()
! || ((GetStdHandle(STD_INPUT_HANDLE) != serialPtr->handle)
! && (GetStdHandle(STD_OUTPUT_HANDLE) != serialPtr->handle)
! && (GetStdHandle(STD_ERROR_HANDLE) != serialPtr->handle))) {
! if (CloseHandle(serialPtr->handle) == FALSE) {
! TclWinConvertError(GetLastError());
! errorCode = errno;
! }
}
serialPtr->watchMask &= serialPtr->validMask;
--- 663,675 ----
*/
if (!TclInThreadExit()
! || ((GetStdHandle(STD_INPUT_HANDLE) != serialPtr->handle)
! && (GetStdHandle(STD_OUTPUT_HANDLE) != serialPtr->handle)
! && (GetStdHandle(STD_ERROR_HANDLE) != serialPtr->handle))) {
! if (CloseHandle(serialPtr->handle) == FALSE) {
! TclWinConvertError(GetLastError());
! errorCode = errno;
! }
}
serialPtr->watchMask &= serialPtr->validMask;
***************
*** 653,660 ****
*/
for (nextPtrPtr = &(tsdPtr->firstSerialPtr), infoPtr = *nextPtrPtr;
! infoPtr != NULL;
! nextPtrPtr = &infoPtr->nextPtr, infoPtr = *nextPtrPtr) {
if (infoPtr == (SerialInfo *)serialPtr) {
*nextPtrPtr = infoPtr->nextPtr;
break;
--- 679,686 ----
*/
for (nextPtrPtr = &(tsdPtr->firstSerialPtr), infoPtr = *nextPtrPtr;
! infoPtr != NULL;
! nextPtrPtr = &infoPtr->nextPtr, infoPtr = *nextPtrPtr) {
if (infoPtr == (SerialInfo *)serialPtr) {
*nextPtrPtr = infoPtr->nextPtr;
break;
***************
*** 703,722 ****
LPOVERLAPPED osPtr ) /* OVERLAPPED structure */
{
/*
! * Perform overlapped blocking read.
! * 1. Reset the overlapped event
! * 2. Start overlapped read operation
! * 3. Wait for completion
! */
! /*
! * Set Offset to ZERO, otherwise NT4.0 may report an error
! */
! osPtr->Offset = osPtr->OffsetHigh = 0;
ResetEvent(osPtr->hEvent);
if (! ReadFile(infoPtr->handle, buf, bufSize, lpRead, osPtr) ) {
if (GetLastError() != ERROR_IO_PENDING) {
! /* ReadFile failed, but it isn't delayed. Report error */
return FALSE;
} else {
/* Read is pending, wait for completion, timeout ? */
--- 729,748 ----
LPOVERLAPPED osPtr ) /* OVERLAPPED structure */
{
/*
! * Perform overlapped blocking read.
! * 1. Reset the overlapped event
! * 2. Start overlapped read operation
! * 3. Wait for completion
! */
! /*
! * Set Offset to ZERO, otherwise NT4.0 may report an error.
! */
! osPtr->Offset = osPtr->OffsetHigh = 0;
ResetEvent(osPtr->hEvent);
if (! ReadFile(infoPtr->handle, buf, bufSize, lpRead, osPtr) ) {
if (GetLastError() != ERROR_IO_PENDING) {
! /* ReadFile failed, but it isn't delayed. Report error. */
return FALSE;
} else {
/* Read is pending, wait for completion, timeout ? */
***************
*** 1247,1262 ****
SerialInfo *infoPtr = (SerialInfo *)arg;
HANDLE *handle = infoPtr->handle;
! DWORD bytesWritten, toWrite;
char *buf;
OVERLAPPED myWrite; /* have an own OVERLAPPED in this thread */
for (;;) {
/*
* Wait for the main thread to signal before attempting to write.
*/
! WaitForSingleObject(infoPtr->evStartWriter, INFINITE);
buf = infoPtr->writeBuf;
toWrite = infoPtr->toWrite;
--- 1273,1304 ----
SerialInfo *infoPtr = (SerialInfo *)arg;
HANDLE *handle = infoPtr->handle;
! DWORD bytesWritten, toWrite, waitResult;
char *buf;
OVERLAPPED myWrite; /* have an own OVERLAPPED in this thread */
+ HANDLE wEvents[2];
+
+ /*
+ * The stop event takes precedence by being first in the list.
+ */
+ wEvents[0] = infoPtr->evStopWriter;
+ wEvents[1] = infoPtr->evStartWriter;
for (;;) {
/*
* Wait for the main thread to signal before attempting to write.
*/
! waitResult = WaitForMultipleObjects(2, wEvents, FALSE, INFINITE);
!
! if (waitResult != (WAIT_OBJECT_0 + 1)) {
! /*
! * The start event was not signaled. It might be the stop event
! * or an error, so exit.
! */
!
! break;
! }
buf = infoPtr->writeBuf;
toWrite = infoPtr->toWrite;
***************
*** 1306,1312 ****
Tcl_ThreadAlert(infoPtr->threadId);
Tcl_MutexUnlock(&serialMutex);
}
! return 0; /* NOT REACHED */
}
--- 1348,1355 ----
Tcl_ThreadAlert(infoPtr->threadId);
Tcl_MutexUnlock(&serialMutex);
}
!
! return 0;
}
***************
*** 1426,1433 ****
infoPtr->osWrite.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
infoPtr->evWritable = CreateEvent(NULL, TRUE, TRUE, NULL);
infoPtr->evStartWriter = CreateEvent(NULL, FALSE, FALSE, NULL);
InitializeCriticalSection(&infoPtr->csWrite);
! infoPtr->writeThread = CreateThread(NULL, 8000, SerialWriterThread,
infoPtr, 0, &id);
}
--- 1469,1477 ----
infoPtr->osWrite.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
infoPtr->evWritable = CreateEvent(NULL, TRUE, TRUE, NULL);
infoPtr->evStartWriter = CreateEvent(NULL, FALSE, FALSE, NULL);
+ infoPtr->evStopWriter = CreateEvent(NULL, FALSE, FALSE, NULL);
InitializeCriticalSection(&infoPtr->csWrite);
! infoPtr->writeThread = CreateThread(NULL, 256, SerialWriterThread,
infoPtr, 0, &id);
}
*** win/tclWinSock.c 24 May 2002 18:57:09 -0000 1.26
--- win/tclWinSock.c 21 Nov 2002 07:48:11 -0000
***************
*** 435,441 ****
tsdPtr->readyEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
tsdPtr->socketListLock = CreateEvent(NULL, FALSE, TRUE, NULL);
! tsdPtr->socketThread = CreateThread(NULL, 8000, SocketThread,
tsdPtr, 0, &id);
SetThreadPriority(tsdPtr->socketThread, THREAD_PRIORITY_HIGHEST);
--- 438,444 ----
tsdPtr->readyEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
tsdPtr->socketListLock = CreateEvent(NULL, FALSE, TRUE, NULL);
! tsdPtr->socketThread = CreateThread(NULL, 256, SocketThread,
tsdPtr, 0, &id);
SetThreadPriority(tsdPtr->socketThread, THREAD_PRIORITY_HIGHEST);
*** win/tclWinThrd.c 19 Nov 2002 01:29:27 -0000 1.21
--- win/tclWinThrd.c 21 Nov 2002 07:48:20 -0000
***************
*** 825,831 ****
/*
* Be careful on timeouts because the signal might arrive right around
! * time time limit and someone else could have taken us off the queue.
*/
if (timeout) {
--- 825,831 ----
/*
* Be careful on timeouts because the signal might arrive right around
! * the time limit and someone else could have taken us off the queue.
*/
if (timeout) {
*** win/tclWinTime.c 9 Oct 2002 23:57:25 -0000 1.11
--- win/tclWinTime.c 21 Nov 2002 07:48:24 -0000
***************
*** 304,310 ****
timeInfo.readyEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
timeInfo.exitEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
timeInfo.calibrationThread = CreateThread( NULL,
! 8192,
CalibrationThread,
(LPVOID) NULL,
0,
--- 304,310 ----
timeInfo.readyEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
timeInfo.exitEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
timeInfo.calibrationThread = CreateThread( NULL,
! 256,
CalibrationThread,
(LPVOID) NULL,
0,