diff options
Diffstat (limited to 'win/tclWinSerial.c')
-rw-r--r-- | win/tclWinSerial.c | 93 |
1 files changed, 16 insertions, 77 deletions
diff --git a/win/tclWinSerial.c b/win/tclWinSerial.c index 0ce5f4d..ed1a8e5 100644 --- a/win/tclWinSerial.c +++ b/win/tclWinSerial.c @@ -93,17 +93,12 @@ typedef struct SerialInfo { * threads. */ OVERLAPPED osRead; /* OVERLAPPED structure for read operations. */ OVERLAPPED osWrite; /* OVERLAPPED structure for write operations */ + TclPipeThreadInfo *writeTI; /* Thread info structure of writer worker. */ HANDLE writeThread; /* Handle to writer thread. */ CRITICAL_SECTION csWrite; /* Writer thread synchronisation. */ HANDLE evWritable; /* Manual-reset event to signal when the * writer thread has finished waiting for the * current buffer to be written. */ - 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 @@ -599,7 +594,6 @@ SerialCloseProc( int errorCode, result = 0; SerialInfo *infoPtr, **nextPtrPtr; ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); - DWORD exitCode; errorCode = 0; @@ -609,56 +603,13 @@ SerialCloseProc( } serialPtr->validMask &= ~TCL_READABLE; - if (serialPtr->validMask & TCL_WRITABLE) { - /* - * 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. - */ + if (serialPtr->writeThread) { - Tcl_MutexLock(&serialMutex); + TclPipeThreadStop(&serialPtr->writeTI, serialPtr->writeThread); - /* BUG: this leaks memory */ - TerminateThread(serialPtr->writeThread, 0); - - Tcl_MutexUnlock(&serialMutex); - } - } - - CloseHandle(serialPtr->writeThread); CloseHandle(serialPtr->osWrite.hEvent); CloseHandle(serialPtr->evWritable); - CloseHandle(serialPtr->evStartWriter); - CloseHandle(serialPtr->evStopWriter); + CloseHandle(serialPtr->writeThread); serialPtr->writeThread = NULL; PurgeComm(serialPtr->handle, PURGE_TXABORT | PURGE_TXCLEAR); @@ -1076,7 +1027,7 @@ SerialOutputProc( memcpy(infoPtr->writeBuf, buf, (size_t) toWrite); infoPtr->toWrite = toWrite; ResetEvent(infoPtr->evWritable); - SetEvent(infoPtr->evStartWriter); + TclPipeThreadSignal(&infoPtr->writeTI); bytesWritten = (DWORD) toWrite; } else { @@ -1313,34 +1264,21 @@ static DWORD WINAPI SerialWriterThread( LPVOID arg) { - SerialInfo *infoPtr = (SerialInfo *)arg; - DWORD bytesWritten, toWrite, waitResult; + TclPipeThreadInfo *pipeTI = (TclPipeThreadInfo *)arg; + SerialInfo *infoPtr = NULL; /* access info only after success init/wait */ + DWORD bytesWritten, toWrite; 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. - */ - + if (!TclPipeThreadWaitForSignal(&pipeTI)) { + /* exit */ break; } + infoPtr = (SerialInfo *)pipeTI->clientData; buf = infoPtr->writeBuf; toWrite = infoPtr->toWrite; @@ -1404,6 +1342,9 @@ SerialWriterThread( Tcl_MutexUnlock(&serialMutex); } + /* Worker exit, so inform the main thread or free TI-structure (if owned) */ + TclPipeThreadExit(&pipeTI); + return 0; } @@ -1477,7 +1418,6 @@ TclWinOpenSerialChannel( int permissions) { SerialInfo *infoPtr; - DWORD id; SerialInit(); @@ -1529,10 +1469,9 @@ TclWinOpenSerialChannel( 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); infoPtr->writeThread = CreateThread(NULL, 256, SerialWriterThread, - infoPtr, 0, &id); + TclPipeThreadCreateTI(&infoPtr->writeTI, infoPtr, + infoPtr->evWritable), 0, NULL); } /* |