diff options
-rw-r--r-- | ChangeLog | 17 | ||||
-rw-r--r-- | win/tclWinConsole.c | 175 | ||||
-rw-r--r-- | win/tclWinPipe.c | 112 | ||||
-rw-r--r-- | win/tclWinSerial.c | 126 | ||||
-rw-r--r-- | win/tclWinSock.c | 4 | ||||
-rw-r--r-- | win/tclWinThrd.c | 4 | ||||
-rw-r--r-- | win/tclWinTime.c | 4 |
7 files changed, 314 insertions, 128 deletions
@@ -1,3 +1,20 @@ +2002-11-26 David Gravereaux <davygrvy@pobox.com> + + * win/tclWinConsole.c: + * win/tclWinPipe.c: + * win/tclWinSerial.c: + * win/tclWinSock.c: + * win/tclWinThrd.c: + * win/tclWinTime.c: General cleanup of all worker threads used + by the channel drivers. Eliminates the normal case where the + worker thread is terminated ('cept the winsock one). Instead, + use kernel events to signal a clean exit. Only when the worker + thread is blocked on an I/O call is the thread terminated. + Essentially, this makes all other channel worker threads behave + like the PipeReaderThread() function for it's cleaner exit + behavior. This appears to fix [Bug 597924] but needs 3rd party + confirmation to close the issue. + 2002-11-26 Mo DeJong <mdejong@users.sourceforge.net> * win/README: Update msys build env URL. This diff --git a/win/tclWinConsole.c b/win/tclWinConsole.c index 230a20e..7bb406b 100644 --- a/win/tclWinConsole.c +++ b/win/tclWinConsole.c @@ -9,7 +9,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclWinConsole.c,v 1.9 2002/11/07 02:13:37 mdejong Exp $ + * RCS: @(#) $Id: tclWinConsole.c,v 1.10 2002/11/26 22:35:20 davygrvy Exp $ */ #include "tclWinInt.h" @@ -79,9 +79,15 @@ typedef struct ConsoleInfo { 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,6 +464,7 @@ ConsoleCloseProc( int errorCode; ConsoleInfo *infoPtr, **nextPtrPtr; ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); + DWORD exitCode; errorCode = 0; @@ -468,30 +475,50 @@ ConsoleCloseProc( */ 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. + * The thread may already have closed on it's own. Check it's + * exit code. */ - Tcl_MutexLock(&consoleMutex); - TerminateThread(consolePtr->readThread, 0); + GetExitCodeThread(consolePtr->readThread, &exitCode); - /* - * Wait for the thread to terminate. This ensures that we are - * completely cleaned up before we leave this function. - */ + if (exitCode == STILL_ACTIVE) { - WaitForSingleObject(consolePtr->readThread, INFINITE); - Tcl_MutexUnlock(&consoleMutex); + /* + * 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,29 +539,45 @@ ConsoleCloseProc( } /* - * 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. + * The thread may already have closed on it's own. Check it's + * exit code. */ - Tcl_MutexLock(&consoleMutex); - TerminateThread(consolePtr->writeThread, 0); + GetExitCodeThread(consolePtr->writeThread, &exitCode); - /* - * Wait for the thread to terminate. This ensures that we are - * completely cleaned up before we leave this function. - */ + if (exitCode == STILL_ACTIVE) { + /* + * Set the stop event so that if the reader thread is blocked + * in ConsoleWriterThread on WaitForMultipleEvents, it will + * exit cleanly. + */ - WaitForSingleObject(consolePtr->writeThread, INFINITE); - Tcl_MutexUnlock(&consoleMutex); + 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,14 +1109,28 @@ ConsoleReaderThread(LPVOID arg) { ConsoleInfo *infoPtr = (ConsoleInfo *)arg; HANDLE *handle = infoPtr->handle; - DWORD count; + 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. */ - WaitForSingleObject(infoPtr->startReader, INFINITE); + 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,7 +1138,7 @@ ConsoleReaderThread(LPVOID arg) * Look for data on the console, but first ignore any events * that are not KEY_EVENTs */ - if (ReadConsole(handle, infoPtr->buffer, CONSOLE_BUFFER_SIZE, + if (ReadConsoleA(handle, infoPtr->buffer, CONSOLE_BUFFER_SIZE, (LPDWORD) &infoPtr->bytesRead, NULL) != FALSE) { /* * Data was stored in the buffer. @@ -1114,7 +1171,8 @@ ConsoleReaderThread(LPVOID arg) Tcl_ThreadAlert(infoPtr->threadId); Tcl_MutexUnlock(&consoleMutex); } - return 0; /* NOT REACHED */ + + return 0; } /* @@ -1141,15 +1199,29 @@ ConsoleWriterThread(LPVOID arg) ConsoleInfo *infoPtr = (ConsoleInfo *)arg; HANDLE *handle = infoPtr->handle; - DWORD count, toWrite; + 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. */ - WaitForSingleObject(infoPtr->startWriter, INFINITE); + 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,7 +1231,7 @@ ConsoleWriterThread(LPVOID arg) */ while (toWrite > 0) { - if (WriteFile(handle, buf, toWrite, &count, NULL) == FALSE) { + if (WriteConsoleA(handle, buf, toWrite, &count, NULL) == FALSE) { infoPtr->writeError = GetLastError(); break; } else { @@ -1185,7 +1257,8 @@ ConsoleWriterThread(LPVOID arg) Tcl_ThreadAlert(infoPtr->threadId); Tcl_MutexUnlock(&consoleMutex); } - return 0; /* NOT REACHED */ + + return 0; } @@ -1217,7 +1290,7 @@ TclWinOpenConsoleChannel(handle, channelName, permissions) char encoding[4 + TCL_INTEGER_SPACE]; ConsoleInfo *infoPtr; ThreadSpecificData *tsdPtr; - DWORD id; + DWORD id, modes; tsdPtr = ConsoleInit(); @@ -1232,7 +1305,7 @@ TclWinOpenConsoleChannel(handle, channelName, permissions) 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,18 +1320,32 @@ TclWinOpenConsoleChannel(handle, channelName, permissions) 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->readThread = CreateThread(NULL, 8000, ConsoleReaderThread, + infoPtr->stopReader = CreateEvent(NULL, FALSE, FALSE, NULL); + infoPtr->readThread = CreateThread(NULL, 256, ConsoleReaderThread, infoPtr, 0, &id); - SetThreadPriority(infoPtr->readThread, THREAD_PRIORITY_HIGHEST); + 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->stopWriter = CreateEvent(NULL, FALSE, FALSE, NULL); + infoPtr->writeThread = CreateThread(NULL, 256, ConsoleWriterThread, infoPtr, 0, &id); + SetThreadPriority(infoPtr->writeThread, THREAD_PRIORITY_HIGHEST); } /* diff --git a/win/tclWinPipe.c b/win/tclWinPipe.c index 2134d8d..8a6fc59 100644 --- a/win/tclWinPipe.c +++ b/win/tclWinPipe.c @@ -9,7 +9,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclWinPipe.c,v 1.26 2002/11/07 02:13:37 mdejong Exp $ + * RCS: @(#) $Id: tclWinPipe.c,v 1.27 2002/11/26 22:35:20 davygrvy Exp $ */ #include "tclWinInt.h" @@ -120,6 +120,8 @@ typedef struct PipeInfo { 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,7 +1687,7 @@ TclpCreateCommandChannel( 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->readThread = CreateThread(NULL, 256, PipeReaderThread, infoPtr, 0, &id); SetThreadPriority(infoPtr->readThread, THREAD_PRIORITY_HIGHEST); infoPtr->validMask |= TCL_READABLE; @@ -1699,7 +1701,8 @@ TclpCreateCommandChannel( infoPtr->writable = CreateEvent(NULL, TRUE, TRUE, NULL); infoPtr->startWriter = CreateEvent(NULL, FALSE, FALSE, NULL); - infoPtr->writeThread = CreateThread(NULL, 512, PipeWriterThread, + 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,13 +1876,11 @@ PipeClose2Proc( SetEvent(pipePtr->stopReader); /* - * Wait at most 10 milliseconds for the reader thread to close. + * Wait at most 20 milliseconds for the reader thread to close. */ - WaitForSingleObject(pipePtr->readThread, 10); - GetExitCodeThread(pipePtr->readThread, &exitCode); - - if (exitCode == STILL_ACTIVE) { + 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,10 +1899,6 @@ PipeClose2Proc( /* BUG: this leaks memory */ TerminateThread(pipePtr->readThread, 0); - - /* Wait for the thread to terminate. */ - WaitForSingleObject(pipePtr->readThread, INFINITE); - Tcl_MutexUnlock(&pipeMutex); } } @@ -1920,40 +1917,65 @@ PipeClose2Proc( } 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. + * 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. */ - Tcl_MutexLock(&pipeMutex); - TerminateThread(pipePtr->writeThread, 0); + WaitForSingleObject(pipePtr->writable, INFINITE); /* - * Wait for the thread to terminate. This ensures that we are - * completely cleaned up before we leave this function. + * The thread may already have closed on it's own. Check it's + * exit code. */ - WaitForSingleObject(pipePtr->writeThread, INFINITE); - Tcl_MutexUnlock(&pipeMutex); + 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,7 +2767,7 @@ PipeReaderThread(LPVOID arg) DWORD count, err; int done = 0; HANDLE wEvents[2]; - DWORD dwWait; + DWORD waitResult; wEvents[0] = infoPtr->stopReader; wEvents[1] = infoPtr->startReader; @@ -2756,15 +2778,15 @@ PipeReaderThread(LPVOID arg) * on the pipe becoming readable. */ - dwWait = WaitForMultipleObjects(2, wEvents, FALSE, INFINITE); + waitResult = WaitForMultipleObjects(2, wEvents, FALSE, INFINITE); - if (dwWait != (WAIT_OBJECT_0 + 1)) { + if (waitResult != (WAIT_OBJECT_0 + 1)) { /* * The start event was not signaled. It might be the stop event * or an error, so exit. */ - return 0; + break; } /* @@ -2832,6 +2854,7 @@ PipeReaderThread(LPVOID arg) Tcl_ThreadAlert(infoPtr->threadId); Tcl_MutexUnlock(&pipeMutex); } + return 0; } @@ -2862,13 +2885,27 @@ PipeWriterThread(LPVOID arg) 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. */ - WaitForSingleObject(infoPtr->startWriter, INFINITE); + 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,6 +2942,7 @@ PipeWriterThread(LPVOID arg) Tcl_ThreadAlert(infoPtr->threadId); Tcl_MutexUnlock(&pipeMutex); } + return 0; } diff --git a/win/tclWinSerial.c b/win/tclWinSerial.c index a1cdcfd..e6781ae 100644 --- a/win/tclWinSerial.c +++ b/win/tclWinSerial.c @@ -11,7 +11,7 @@ * * Serial functionality implemented by Rolf.Schroedter@dlr.de * - * RCS: @(#) $Id: tclWinSerial.c,v 1.22 2002/11/07 02:13:37 mdejong Exp $ + * RCS: @(#) $Id: tclWinSerial.c,v 1.23 2002/11/26 22:35:20 davygrvy Exp $ */ #include "tclWinInt.h" @@ -103,6 +103,9 @@ typedef struct SerialInfo { 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,6 +588,7 @@ SerialCloseProc( int errorCode, result = 0; SerialInfo *infoPtr, **nextPtrPtr; ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); + DWORD exitCode; errorCode = 0; @@ -600,30 +604,52 @@ SerialCloseProc( * 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); + /* + * The thread may have already closed on it's own. Check it's + * exit code. + */ - /* - * Wait for the thread to terminate. This ensures that we are - * completely cleaned up before we leave this function. - */ + 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); + } + } - WaitForSingleObject(serialPtr->writeThread, INFINITE); CloseHandle(serialPtr->writeThread); CloseHandle(serialPtr->evWritable); CloseHandle(serialPtr->evStartWriter); + CloseHandle(serialPtr->evStopWriter); serialPtr->writeThread = NULL; PurgeComm(serialPtr->handle, PURGE_TXABORT | PURGE_TXCLEAR); @@ -637,13 +663,13 @@ SerialCloseProc( */ 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; - } + || ((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,8 +679,8 @@ SerialCloseProc( */ for (nextPtrPtr = &(tsdPtr->firstSerialPtr), infoPtr = *nextPtrPtr; - infoPtr != NULL; - nextPtrPtr = &infoPtr->nextPtr, infoPtr = *nextPtrPtr) { + infoPtr != NULL; + nextPtrPtr = &infoPtr->nextPtr, infoPtr = *nextPtrPtr) { if (infoPtr == (SerialInfo *)serialPtr) { *nextPtrPtr = infoPtr->nextPtr; break; @@ -703,20 +729,20 @@ blockingRead( LPOVERLAPPED osPtr ) /* OVERLAPPED structure */ { /* - * Perform overlapped blocking read. - * 1. Reset the overlapped event - * 2. Start overlapped read operation - * 3. Wait for completion - */ + * 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; + /* + * 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 */ + /* ReadFile failed, but it isn't delayed. Report error. */ return FALSE; } else { /* Read is pending, wait for completion, timeout ? */ @@ -1247,16 +1273,32 @@ SerialWriterThread(LPVOID arg) SerialInfo *infoPtr = (SerialInfo *)arg; HANDLE *handle = infoPtr->handle; - DWORD bytesWritten, toWrite; + 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. */ - WaitForSingleObject(infoPtr->evStartWriter, INFINITE); + 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,7 +1348,8 @@ SerialWriterThread(LPVOID arg) Tcl_ThreadAlert(infoPtr->threadId); Tcl_MutexUnlock(&serialMutex); } - return 0; /* NOT REACHED */ + + return 0; } @@ -1426,8 +1469,9 @@ TclWinOpenSerialChannel(handle, channelName, permissions) 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, 8000, SerialWriterThread, + infoPtr->writeThread = CreateThread(NULL, 256, SerialWriterThread, infoPtr, 0, &id); } diff --git a/win/tclWinSock.c b/win/tclWinSock.c index a5ffdfb..a520380 100644 --- a/win/tclWinSock.c +++ b/win/tclWinSock.c @@ -8,7 +8,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclWinSock.c,v 1.26 2002/05/24 18:57:09 andreas_kupries Exp $ + * RCS: @(#) $Id: tclWinSock.c,v 1.27 2002/11/26 22:35:20 davygrvy Exp $ */ #include "tclWinInt.h" @@ -435,7 +435,7 @@ InitSockets() tsdPtr->readyEvent = CreateEvent(NULL, FALSE, FALSE, NULL); tsdPtr->socketListLock = CreateEvent(NULL, FALSE, TRUE, NULL); - tsdPtr->socketThread = CreateThread(NULL, 8000, SocketThread, + tsdPtr->socketThread = CreateThread(NULL, 256, SocketThread, tsdPtr, 0, &id); SetThreadPriority(tsdPtr->socketThread, THREAD_PRIORITY_HIGHEST); diff --git a/win/tclWinThrd.c b/win/tclWinThrd.c index cbef305..2f1d60e 100644 --- a/win/tclWinThrd.c +++ b/win/tclWinThrd.c @@ -9,7 +9,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclWinThrd.c,v 1.21 2002/11/19 01:29:27 davygrvy Exp $ + * RCS: @(#) $Id: tclWinThrd.c,v 1.22 2002/11/26 22:35:21 davygrvy Exp $ */ #include "tclWinInt.h" @@ -825,7 +825,7 @@ Tcl_ConditionWait(condPtr, mutexPtr, timePtr) /* * Be careful on timeouts because the signal might arrive right around - * time time limit and someone else could have taken us off the queue. + * the time limit and someone else could have taken us off the queue. */ if (timeout) { diff --git a/win/tclWinTime.c b/win/tclWinTime.c index 87d3c4e..13d1a4e 100644 --- a/win/tclWinTime.c +++ b/win/tclWinTime.c @@ -9,7 +9,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclWinTime.c,v 1.11 2002/10/09 23:57:25 kennykb Exp $ + * RCS: @(#) $Id: tclWinTime.c,v 1.12 2002/11/26 22:35:21 davygrvy Exp $ */ #include "tclWinInt.h" @@ -304,7 +304,7 @@ Tcl_GetTime(timePtr) timeInfo.readyEvent = CreateEvent( NULL, FALSE, FALSE, NULL ); timeInfo.exitEvent = CreateEvent( NULL, FALSE, FALSE, NULL ); timeInfo.calibrationThread = CreateThread( NULL, - 8192, + 256, CalibrationThread, (LPVOID) NULL, 0, |