diff options
Diffstat (limited to 'win/tclWinConsole.c')
-rw-r--r-- | win/tclWinConsole.c | 153 |
1 files changed, 77 insertions, 76 deletions
diff --git a/win/tclWinConsole.c b/win/tclWinConsole.c index c59bc6f..615e87d 100644 --- a/win/tclWinConsole.c +++ b/win/tclWinConsole.c @@ -1,4 +1,4 @@ -/* +/* * tclWinConsole.c -- * * This file implements the Windows-specific console functions, and the @@ -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.16 2005/11/03 01:16:07 patthoyts Exp $ + * RCS: @(#) $Id: tclWinConsole.c,v 1.17 2005/11/04 00:06:50 dkf Exp $ */ #include "tclWinInt.h" @@ -54,7 +54,6 @@ TCL_DECLARE_MUTEX(consoleMutex) * This structure describes per-instance data for a console based channel. */ - typedef struct ConsoleInfo { HANDLE handle; int type; @@ -82,20 +81,17 @@ typedef struct ConsoleInfo { * 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. - */ + * 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. - */ + * 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 * writer thread so access must be - * synchronized with the writable object. - */ + * synchronized with the writable object. */ char *writeBuf; /* Current background output buffer. Access is * synchronized with the writable object. */ int writeBufLen; /* Size of write buffer. Access is @@ -116,7 +112,7 @@ typedef struct ThreadSpecificData { * The following pointer refers to the head of the list of consoles that * are being watched for file events. */ - + ConsoleInfo *firstConsolePtr; } ThreadSpecificData; @@ -140,7 +136,7 @@ typedef struct ConsoleEvent { * Declarations for functions used only in this file. */ -static int ConsoleBlockModeProc(ClientData instanceData, int mode); +static int ConsoleBlockModeProc(ClientData instanceData,int mode); static void ConsoleCheckProc(ClientData clientData, int flags); static int ConsoleCloseProc(ClientData instanceData, Tcl_Interp *interp); @@ -188,15 +184,17 @@ static Tcl_ChannelType consoleChannelType = { /* *---------------------------------------------------------------------- - * + * * readConsoleBytes, writeConsoleBytes -- * Wrapper for ReadConsole{A,W}, that takes and returns number of bytes * instead of number of TCHARS */ -static BOOL readConsoleBytes(HANDLE hConsole, - LPVOID lpBuffer, - DWORD nbytes, - LPDWORD nbytesread) +static BOOL +readConsoleBytes( + HANDLE hConsole, + LPVOID lpBuffer, + DWORD nbytes, + LPDWORD nbytesread) { DWORD ntchars; BOOL result; @@ -204,15 +202,17 @@ static BOOL readConsoleBytes(HANDLE hConsole, tcharsize = tclWinProcs->useWide? 2 : 1; result = tclWinProcs->readConsoleProc( hConsole, lpBuffer, nbytes / tcharsize, &ntchars, NULL); - if (nbytesread) + if (nbytesread) *nbytesread = (ntchars*tcharsize); return result; } -static BOOL writeConsoleBytes(HANDLE hConsole, - const VOID *lpBuffer, - DWORD nbytes, - LPDWORD nbyteswritten) +static BOOL +writeConsoleBytes( + HANDLE hConsole, + const VOID *lpBuffer, + DWORD nbytes, + LPDWORD nbyteswritten) { DWORD ntchars; BOOL result; @@ -220,7 +220,7 @@ static BOOL writeConsoleBytes(HANDLE hConsole, tcharsize = tclWinProcs->useWide? 2 : 1; result = tclWinProcs->writeConsoleProc( hConsole, lpBuffer, nbytes / tcharsize, &ntchars, NULL); - if (nbyteswritten) + if (nbyteswritten) *nbyteswritten = (ntchars*tcharsize); return result; } @@ -242,7 +242,7 @@ static BOOL writeConsoleBytes(HANDLE hConsole, */ static void -ConsoleInit() +ConsoleInit(void) { ThreadSpecificData *tsdPtr; @@ -349,12 +349,12 @@ ConsoleSetupProc( if (!(flags & TCL_FILE_EVENTS)) { return; } - + /* * Look to see if any events are already pending. If they are, poll. */ - for (infoPtr = tsdPtr->firstConsolePtr; infoPtr != NULL; + for (infoPtr = tsdPtr->firstConsolePtr; infoPtr != NULL; infoPtr = infoPtr->nextPtr) { if (infoPtr->watchMask & TCL_WRITABLE) { if (WaitForSingleObject(infoPtr->writable, 0) != WAIT_TIMEOUT) { @@ -402,18 +402,18 @@ ConsoleCheckProc( if (!(flags & TCL_FILE_EVENTS)) { return; } - + /* * Queue events for any ready consoles that don't already have events * queued. */ - for (infoPtr = tsdPtr->firstConsolePtr; infoPtr != NULL; + for (infoPtr = tsdPtr->firstConsolePtr; infoPtr != NULL; infoPtr = infoPtr->nextPtr) { if (infoPtr->flags & CONSOLE_PENDING) { continue; } - + /* * Queue an event if the console is signaled for reading or writing. */ @@ -424,7 +424,7 @@ ConsoleCheckProc( needEvent = 1; } } - + if (infoPtr->watchMask & TCL_READABLE) { if (WaitForRead(infoPtr, 0) >= 0) { needEvent = 1; @@ -465,7 +465,7 @@ ConsoleBlockModeProc( * TCL_MODE_NONBLOCKING. */ { ConsoleInfo *infoPtr = (ConsoleInfo *) instanceData; - + /* * Consoles on Windows can not be switched between blocking and * nonblocking, hence we have to emulate the behavior. This is done in the @@ -510,13 +510,13 @@ ConsoleCloseProc( DWORD exitCode; errorCode = 0; - + /* * Clean up the background thread if necessary. Note that this must be * done before we can close the file, since the thread may be blocking * trying to read from the console. */ - + if (consolePtr->readThread) { /* * The thread may already have closed on it's own. Check it's exit @@ -568,7 +568,7 @@ ConsoleCloseProc( * the thread and close the handles. If the channel is nonblocking, there * should be no pending write operations. */ - + if (consolePtr->writeThread) { if (consolePtr->toWrite) { /* @@ -631,7 +631,7 @@ ConsoleCloseProc( * another. */ - if (!TclInThreadExit() + if (!TclInThreadExit() || ((GetStdHandle(STD_INPUT_HANDLE) != consolePtr->handle) && (GetStdHandle(STD_OUTPUT_HANDLE) != consolePtr->handle) && (GetStdHandle(STD_ERROR_HANDLE) != consolePtr->handle))) { @@ -640,7 +640,7 @@ ConsoleCloseProc( errorCode = errno; } } - + consolePtr->watchMask &= consolePtr->validMask; /* @@ -699,13 +699,13 @@ ConsoleInputProc( /* * Synchronize with the reader thread. */ - + result = WaitForRead(infoPtr, (infoPtr->flags & CONSOLE_ASYNC) ? 0 : 1); - + /* * If an error occurred, return immediately. */ - + if (result == -1) { *errorCode = errno; return -1; @@ -727,21 +727,21 @@ ConsoleInputProc( /* * Reset the buffer */ - + infoPtr->readFlags &= ~CONSOLE_BUFFERED; infoPtr->offset = 0; } return bytesRead; } - + /* * Attempt to read bufSize bytes. The read will return immediately if * there is any data available. Otherwise it will block until at least one * byte is available or an EOF occurs. */ - if (readConsoleBytes(infoPtr->handle, (LPVOID) buf, (DWORD) bufSize, &count) + if (readConsoleBytes(infoPtr->handle, (LPVOID) buf, (DWORD) bufSize, &count) == TRUE) { buf[count] = '\0'; return count; @@ -770,10 +770,10 @@ ConsoleInputProc( static int ConsoleOutputProc( - ClientData instanceData, /* Console state. */ - CONST char *buf, /* The data buffer. */ - int toWrite, /* How many bytes to write? */ - int *errorCode) /* Where to store error code. */ + ClientData instanceData, /* Console state. */ + CONST char *buf, /* The data buffer. */ + int toWrite, /* How many bytes to write? */ + int *errorCode) /* Where to store error code. */ { ConsoleInfo *infoPtr = (ConsoleInfo *) instanceData; DWORD bytesWritten, timeout; @@ -920,7 +920,7 @@ ConsoleEventProc( } else { mask |= TCL_READABLE; } - } + } } /* @@ -1042,18 +1042,18 @@ ConsoleGetHandleProc( static int WaitForRead( ConsoleInfo *infoPtr, /* Console state. */ - int blocking) /* Indicates whether call should be - * blocking or not. */ + int blocking) /* Indicates whether call should be blocking + * or not. */ { DWORD timeout, count; HANDLE *handle = infoPtr->handle; INPUT_RECORD input; - + while (1) { /* * Synchronize with the reader thread. */ - + timeout = blocking ? INFINITE : 0; if (WaitForSingleObject(infoPtr->readable, timeout) == WAIT_TIMEOUT) { /* @@ -1064,27 +1064,27 @@ WaitForRead( errno = EAGAIN; return -1; } - + /* * At this point, the two threads are synchronized, so it is safe to * access shared state. */ - + /* * If the console has hit EOF, it is always readable. */ - + if (infoPtr->readFlags & CONSOLE_EOF) { return 1; } - + if (PeekConsoleInput(handle, &input, 1, &count) == FALSE) { /* * Check to see if the peek failed because of EOF. */ - + TclWinConvertError(GetLastError()); - + if (errno == EOF) { infoPtr->readFlags |= CONSOLE_EOF; return 1; @@ -1093,7 +1093,7 @@ WaitForRead( /* * Ignore errors if there is data in the buffer. */ - + if (infoPtr->readFlags & CONSOLE_BUFFERED) { return 0; } else { @@ -1113,7 +1113,7 @@ WaitForRead( /* * There wasn't any data available, so reset the thread and try again. */ - + ResetEvent(infoPtr->readable); SetEvent(infoPtr->startReader); } @@ -1139,7 +1139,8 @@ WaitForRead( */ static DWORD WINAPI -ConsoleReaderThread(LPVOID arg) +ConsoleReaderThread( + LPVOID arg) { ConsoleInfo *infoPtr = (ConsoleInfo *)arg; HANDLE *handle = infoPtr->handle; @@ -1168,7 +1169,7 @@ ConsoleReaderThread(LPVOID arg) count = 0; - /* + /* * Look for data on the console, but first ignore any events that are * not KEY_EVENTs. */ @@ -1178,12 +1179,12 @@ ConsoleReaderThread(LPVOID arg) /* * Data was stored in the buffer. */ - + infoPtr->readFlags |= CONSOLE_BUFFERED; } else { DWORD err; err = GetLastError(); - + if (err == EOF) { infoPtr->readFlags = CONSOLE_EOF; } @@ -1236,7 +1237,8 @@ ConsoleReaderThread(LPVOID arg) */ static DWORD WINAPI -ConsoleWriterThread(LPVOID arg) +ConsoleWriterThread( + LPVOID arg) { ConsoleInfo *infoPtr = (ConsoleInfo *)arg; @@ -1286,7 +1288,7 @@ ConsoleWriterThread(LPVOID arg) * Signal the main thread by signalling the writable event and then * waking up the notifier thread. */ - + SetEvent(infoPtr->writable); /* @@ -1301,6 +1303,7 @@ ConsoleWriterThread(LPVOID arg) * TIP #218. When in flight ignore the event, no one will receive * it anyway. */ + Tcl_ThreadAlert(infoPtr->threadId); } Tcl_MutexUnlock(&consoleMutex); @@ -1308,8 +1311,6 @@ ConsoleWriterThread(LPVOID arg) return 0; } - - /* *---------------------------------------------------------------------- @@ -1330,10 +1331,10 @@ ConsoleWriterThread(LPVOID arg) */ Tcl_Channel -TclWinOpenConsoleChannel(handle, channelName, permissions) - HANDLE handle; - char *channelName; - int permissions; +TclWinOpenConsoleChannel( + HANDLE handle, + char *channelName, + int permissions) { char encoding[4 + TCL_INTEGER_SPACE]; ConsoleInfo *infoPtr; @@ -1344,7 +1345,7 @@ TclWinOpenConsoleChannel(handle, channelName, permissions) /* * See if a channel with this handle already exists. */ - + infoPtr = (ConsoleInfo *) ckalloc((unsigned) sizeof(ConsoleInfo)); memset(infoPtr, 0, sizeof(ConsoleInfo)); @@ -1363,7 +1364,7 @@ TclWinOpenConsoleChannel(handle, channelName, permissions) */ wsprintfA(channelName, "file%lx", (int) infoPtr); - + infoPtr->channel = Tcl_CreateChannel(&consoleChannelType, channelName, (ClientData) infoPtr, permissions); @@ -1400,7 +1401,7 @@ TclWinOpenConsoleChannel(handle, channelName, permissions) * Files have default translation of AUTO and ^Z eof char, which means * that a ^Z will be accepted as EOF when reading. */ - + Tcl_SetChannelOption(NULL, infoPtr->channel, "-translation", "auto"); Tcl_SetChannelOption(NULL, infoPtr->channel, "-eofchar", "\032 {}"); if (tclWinProcs->useWide) @@ -1428,9 +1429,9 @@ TclWinOpenConsoleChannel(handle, channelName, permissions) */ static void -ConsoleThreadActionProc (instanceData, action) - ClientData instanceData; - int action; +ConsoleThreadActionProc( + ClientData instanceData, + int action) { ConsoleInfo *infoPtr = (ConsoleInfo *) instanceData; |