diff options
Diffstat (limited to 'unix/tclUnixNotfy.c')
-rw-r--r-- | unix/tclUnixNotfy.c | 964 |
1 files changed, 462 insertions, 502 deletions
diff --git a/unix/tclUnixNotfy.c b/unix/tclUnixNotfy.c index 2ad1932..88e290e 100644 --- a/unix/tclUnixNotfy.c +++ b/unix/tclUnixNotfy.c @@ -7,8 +7,8 @@ * * Copyright (c) 1995-1997 Sun Microsystems, Inc. * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * See the file "license.terms" for information on usage and redistribution of + * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" @@ -17,6 +17,14 @@ #include <signal.h> /* + * This code does deep stub magic to allow replacement of the notifier at + * runtime. + */ + +extern TclStubs tclStubs; +extern Tcl_NotifierProcs tclOriginalNotifier; + +/* * This structure is used to keep track of the notifier info for a registered * file. */ @@ -51,13 +59,13 @@ typedef struct FileHandlerEvent { /* * The following structure contains a set of select() masks to track readable, - * writable, and exception conditions. + * writable, and exceptional conditions. */ typedef struct SelectMasks { fd_set readable; fd_set writable; - fd_set exception; + fd_set exceptional; } SelectMasks; /* @@ -196,12 +204,25 @@ static Tcl_ThreadId notifierThread; static void NotifierThreadProc(ClientData clientData); #endif static int FileHandlerEventProc(Tcl_Event *evPtr, int flags); - + /* - * Import of Windows API when building threaded with Cygwin. + *---------------------------------------------------------------------- + * + * Tcl_InitNotifier -- + * + * Initializes the platform specific notifier state. + * + * Results: + * Returns a handle to the notifier state for this thread. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- */ #if defined(TCL_THREADS) && defined(__CYGWIN__) + typedef struct { void *hwnd; unsigned int *message; @@ -213,109 +234,79 @@ typedef struct { } MSG; typedef struct { - unsigned int style; - void *lpfnWndProc; - int cbClsExtra; - int cbWndExtra; - void *hInstance; - void *hIcon; - void *hCursor; - void *hbrBackground; - void *lpszMenuName; - const void *lpszClassName; + unsigned int style; + void *lpfnWndProc; + int cbClsExtra; + int cbWndExtra; + void *hInstance; + void *hIcon; + void *hCursor; + void *hbrBackground; + void *lpszMenuName; + void *lpszClassName; } WNDCLASS; -extern void __stdcall CloseHandle(void *); -extern void *__stdcall CreateEventW(void *, unsigned char, unsigned char, - void *); -extern void * __stdcall CreateWindowExW(void *, const void *, const void *, - DWORD, int, int, int, int, void *, void *, void *, void *); -extern DWORD __stdcall DefWindowProcW(void *, int, void *, void *); -extern unsigned char __stdcall DestroyWindow(void *); -extern int __stdcall DispatchMessageW(const MSG *); -extern unsigned char __stdcall GetMessageW(MSG *, void *, int, int); -extern void __stdcall MsgWaitForMultipleObjects(DWORD, void *, - unsigned char, DWORD, DWORD); -extern unsigned char __stdcall PeekMessageW(MSG *, void *, int, int, int); -extern unsigned char __stdcall PostMessageW(void *, unsigned int, void *, - void *); -extern void __stdcall PostQuitMessage(int); -extern void *__stdcall RegisterClassW(const WNDCLASS *); -extern unsigned char __stdcall ResetEvent(void *); -extern unsigned char __stdcall TranslateMessage(const MSG *); +extern unsigned char __stdcall PeekMessageW(MSG *, void *, int, int, int); +extern unsigned char __stdcall GetMessageW(MSG *, void *, int, int); +extern unsigned char __stdcall TranslateMessage(const MSG *); +extern int __stdcall DispatchMessageW(const MSG *); +extern void __stdcall PostQuitMessage(int); +extern void * __stdcall CreateWindowExW(void *, void *, void *, DWORD, int, int, int, int, void *, void *, void *, void *); +extern unsigned char __stdcall DestroyWindow(void *); +extern unsigned char __stdcall PostMessageW(void *, unsigned int, void *, void *); +extern void *__stdcall RegisterClassW(const WNDCLASS *); +extern DWORD __stdcall DefWindowProcW(void *, int, void *, void *); +extern void *__stdcall CreateEventW(void *, unsigned char, unsigned char, void *); +extern void __stdcall CloseHandle(void *); +extern void __stdcall MsgWaitForMultipleObjects(DWORD, void *, unsigned char, DWORD, DWORD); +extern unsigned char __stdcall ResetEvent(void *); -/* - * Threaded-cygwin specific functions in this file: - */ - -static DWORD __stdcall NotifierProc(void *hwnd, unsigned int message, - void *wParam, void *lParam); -#endif /* TCL_THREADS && __CYGWIN__ */ - -/* - *---------------------------------------------------------------------- - * - * Tcl_InitNotifier -- - * - * Initializes the platform specific notifier state. - * - * Results: - * Returns a handle to the notifier state for this thread. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ +#endif ClientData Tcl_InitNotifier(void) { - if (tclNotifierHooks.initNotifierProc) { - return tclNotifierHooks.initNotifierProc(); - } else { - ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); + ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); #ifdef TCL_THREADS - tsdPtr->eventReady = 0; + tsdPtr->eventReady = 0; - /* - * Start the Notifier thread if necessary. - */ + /* + * Start the Notifier thread if necessary. + */ - Tcl_MutexLock(¬ifierMutex); - /* - * Check if my process id changed, e.g. I was forked - * In this case, restart the notifier thread and close the - * pipe to the original notifier thread - */ - if (notifierCount > 0 && processIDInitialized != getpid()) { - notifierCount = 0; - processIDInitialized = 0; - close(triggerPipe); - triggerPipe = -1; - } - if (notifierCount == 0) { - if (TclpThreadCreate(¬ifierThread, NotifierThreadProc, NULL, - TCL_THREAD_STACK_DEFAULT, TCL_THREAD_JOINABLE) != TCL_OK) { - Tcl_Panic("Tcl_InitNotifier: unable to start notifier thread"); - } + Tcl_MutexLock(¬ifierMutex); + /* + * Check if my process id changed, e.g. I was forked + * In this case, restart the notifier thread and close the + * pipe to the original notifier thread + */ + if (notifierCount > 0 && processIDInitialized != getpid()) { + notifierCount = 0; + processIDInitialized = 0; + close(triggerPipe); + triggerPipe = -1; + } + if (notifierCount == 0) { + if (TclpThreadCreate(¬ifierThread, NotifierThreadProc, NULL, + TCL_THREAD_STACK_DEFAULT, TCL_THREAD_JOINABLE) != TCL_OK) { + Tcl_Panic("Tcl_InitNotifier: unable to start notifier thread"); processIDInitialized = getpid(); } - notifierCount++; + } + notifierCount++; - /* - * Wait for the notifier pipe to be created. - */ + /* + * Wait for the notifier pipe to be created. + */ - while (triggerPipe < 0) { - Tcl_ConditionWait(¬ifierCV, ¬ifierMutex, NULL); - } + while (triggerPipe < 0) { + Tcl_ConditionWait(¬ifierCV, ¬ifierMutex, NULL); + } - Tcl_MutexUnlock(¬ifierMutex); + Tcl_MutexUnlock(¬ifierMutex); #endif /* TCL_THREADS */ - return tsdPtr; - } + return (ClientData) tsdPtr; } /* @@ -340,69 +331,61 @@ void Tcl_FinalizeNotifier( ClientData clientData) /* Not used. */ { - if (tclNotifierHooks.finalizeNotifierProc) { - tclNotifierHooks.finalizeNotifierProc(clientData); - return; - } else { #ifdef TCL_THREADS - ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); + ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); - Tcl_MutexLock(¬ifierMutex); - notifierCount--; + Tcl_MutexLock(¬ifierMutex); + notifierCount--; - /* - * If this is the last thread to use the notifier, close the notifier - * pipe and wait for the background thread to terminate. - */ + /* + * If this is the last thread to use the notifier, close the notifier pipe + * and wait for the background thread to terminate. + */ - if (notifierCount == 0) { - int result; + if (notifierCount == 0) { + int result; - if (triggerPipe < 0) { - Tcl_Panic("Tcl_FinalizeNotifier: %s", - "notifier pipe not initialized"); - } + if (triggerPipe < 0) { + Tcl_Panic("Tcl_FinalizeNotifier: notifier pipe not initialized"); + } - /* - * Send "q" message to the notifier thread so that it will - * terminate. The notifier will return from its call to select() - * and notice that a "q" message has arrived, it will then close - * its side of the pipe and terminate its thread. Note the we can - * not just close the pipe and check for EOF in the notifier thread - * because if a background child process was created with exec, - * select() would not register the EOF on the pipe until the child - * processes had terminated. [Bug: 4139] [Bug: 1222872] - */ + /* + * Send "q" message to the notifier thread so that it will terminate. + * The notifier will return from its call to select() and notice that + * a "q" message has arrived, it will then close its side of the pipe + * and terminate its thread. Note the we can not just close the pipe + * and check for EOF in the notifier thread because if a background + * child process was created with exec, select() would not register + * the EOF on the pipe until the child processes had terminated. [Bug: + * 4139] [Bug: 1222872] + */ - if (write(triggerPipe, "q", 1) != 1) { - Tcl_Panic("Tcl_FinalizeNotifier: %s", - "unable to write q to triggerPipe"); - } - close(triggerPipe); - while(triggerPipe >= 0) { - Tcl_ConditionWait(¬ifierCV, ¬ifierMutex, NULL); - } + if (write(triggerPipe, "q", 1) != 1) { + Tcl_Panic("Tcl_FinalizeNotifier: unable to write q to triggerPipe"); + } + close(triggerPipe); + while(triggerPipe >= 0) { + Tcl_ConditionWait(¬ifierCV, ¬ifierMutex, NULL); + } - result = Tcl_JoinThread(notifierThread, NULL); - if (result) { - Tcl_Panic("Tcl_FinalizeNotifier: %s", - "unable to join notifier thread"); - } + result = Tcl_JoinThread(notifierThread, NULL); + if (result) { + Tcl_Panic("Tcl_FinalizeNotifier: unable to join notifier thread"); } + } - /* - * Clean up any synchronization objects in the thread local storage. - */ + /* + * Clean up any synchronization objects in the thread local storage. + */ #ifdef __CYGWIN__ - CloseHandle(tsdPtr->event); + CloseHandle(tsdPtr->event); #else /* __CYGWIN__ */ - Tcl_ConditionFinalize(&(tsdPtr->waitCV)); + Tcl_ConditionFinalize(&(tsdPtr->waitCV)); #endif /* __CYGWIN__ */ - Tcl_MutexUnlock(¬ifierMutex); -#endif /* TCL_THREADS */ - } + Tcl_MutexUnlock(¬ifierMutex); +#endif } /* @@ -428,23 +411,17 @@ void Tcl_AlertNotifier( ClientData clientData) { - if (tclNotifierHooks.alertNotifierProc) { - tclNotifierHooks.alertNotifierProc(clientData); - return; - } else { #ifdef TCL_THREADS - ThreadSpecificData *tsdPtr = clientData; - - Tcl_MutexLock(¬ifierMutex); - tsdPtr->eventReady = 1; -# ifdef __CYGWIN__ - PostMessageW(tsdPtr->hwnd, 1024, 0, 0); -# else - Tcl_ConditionNotify(&tsdPtr->waitCV); -# endif /* __CYGWIN__ */ - Tcl_MutexUnlock(¬ifierMutex); -#endif /* TCL_THREADS */ - } + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) clientData; + Tcl_MutexLock(¬ifierMutex); + tsdPtr->eventReady = 1; +#ifdef __CYGWIN__ + PostMessageW(tsdPtr->hwnd, 1024, 0, 0); +#else + Tcl_ConditionNotify(&tsdPtr->waitCV); +#endif + Tcl_MutexUnlock(¬ifierMutex); +#endif } /* @@ -467,17 +444,16 @@ Tcl_AlertNotifier( void Tcl_SetTimer( - const Tcl_Time *timePtr) /* Timeout value, may be NULL. */ + Tcl_Time *timePtr) /* Timeout value, may be NULL. */ { - if (tclNotifierHooks.setTimerProc) { - tclNotifierHooks.setTimerProc(timePtr); - return; - } else { - /* - * The interval timer doesn't do anything in this implementation, - * because the only event loop is via Tcl_DoOneEvent, which passes - * timeout values to Tcl_WaitForEvent. - */ + /* + * The interval timer doesn't do anything in this implementation, because + * the only event loop is via Tcl_DoOneEvent, which passes timeout values + * to Tcl_WaitForEvent. + */ + + if (tclStubs.tcl_SetTimer != tclOriginalNotifier.setTimerProc) { + tclStubs.tcl_SetTimer(timePtr); } } @@ -502,12 +478,6 @@ Tcl_ServiceModeHook( int mode) /* Either TCL_SERVICE_ALL, or * TCL_SERVICE_NONE. */ { - if (tclNotifierHooks.serviceModeHookProc) { - tclNotifierHooks.serviceModeHookProc(mode); - return; - } else { - /* Does nothing in this implementation. */ - } } /* @@ -537,52 +507,53 @@ Tcl_CreateFileHandler( * event. */ ClientData clientData) /* Arbitrary data to pass to proc. */ { - if (tclNotifierHooks.createFileHandlerProc) { - tclNotifierHooks.createFileHandlerProc(fd, mask, proc, clientData); + ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); + FileHandler *filePtr; + + if (tclStubs.tcl_CreateFileHandler != + tclOriginalNotifier.createFileHandlerProc) { + tclStubs.tcl_CreateFileHandler(fd, mask, proc, clientData); return; - } else { - ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); - FileHandler *filePtr; + } - for (filePtr = tsdPtr->firstFileHandlerPtr; filePtr != NULL; - filePtr = filePtr->nextPtr) { - if (filePtr->fd == fd) { - break; - } - } - if (filePtr == NULL) { - filePtr = ckalloc(sizeof(FileHandler)); - filePtr->fd = fd; - filePtr->readyMask = 0; - filePtr->nextPtr = tsdPtr->firstFileHandlerPtr; - tsdPtr->firstFileHandlerPtr = filePtr; + for (filePtr = tsdPtr->firstFileHandlerPtr; filePtr != NULL; + filePtr = filePtr->nextPtr) { + if (filePtr->fd == fd) { + break; } - filePtr->proc = proc; - filePtr->clientData = clientData; - filePtr->mask = mask; + } + if (filePtr == NULL) { + filePtr = (FileHandler*) ckalloc(sizeof(FileHandler)); + filePtr->fd = fd; + filePtr->readyMask = 0; + filePtr->nextPtr = tsdPtr->firstFileHandlerPtr; + tsdPtr->firstFileHandlerPtr = filePtr; + } + filePtr->proc = proc; + filePtr->clientData = clientData; + filePtr->mask = mask; - /* - * Update the check masks for this file. - */ + /* + * Update the check masks for this file. + */ - if (mask & TCL_READABLE) { - FD_SET(fd, &tsdPtr->checkMasks.readable); - } else { - FD_CLR(fd, &tsdPtr->checkMasks.readable); - } - if (mask & TCL_WRITABLE) { - FD_SET(fd, &tsdPtr->checkMasks.writable); - } else { - FD_CLR(fd, &tsdPtr->checkMasks.writable); - } - if (mask & TCL_EXCEPTION) { - FD_SET(fd, &tsdPtr->checkMasks.exception); - } else { - FD_CLR(fd, &tsdPtr->checkMasks.exception); - } - if (tsdPtr->numFdBits <= fd) { - tsdPtr->numFdBits = fd+1; - } + if (mask & TCL_READABLE) { + FD_SET(fd, &(tsdPtr->checkMasks.readable)); + } else { + FD_CLR(fd, &(tsdPtr->checkMasks.readable)); + } + if (mask & TCL_WRITABLE) { + FD_SET(fd, &(tsdPtr->checkMasks.writable)); + } else { + FD_CLR(fd, &(tsdPtr->checkMasks.writable)); + } + if (mask & TCL_EXCEPTION) { + FD_SET(fd, &(tsdPtr->checkMasks.exceptional)); + } else { + FD_CLR(fd, &(tsdPtr->checkMasks.exceptional)); + } + if (tsdPtr->numFdBits <= fd) { + tsdPtr->numFdBits = fd+1; } } @@ -607,71 +578,72 @@ Tcl_DeleteFileHandler( int fd) /* Stream id for which to remove callback * function. */ { - if (tclNotifierHooks.deleteFileHandlerProc) { - tclNotifierHooks.deleteFileHandlerProc(fd); + FileHandler *filePtr, *prevPtr; + int i; + ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); + + if (tclStubs.tcl_DeleteFileHandler != + tclOriginalNotifier.deleteFileHandlerProc) { + tclStubs.tcl_DeleteFileHandler(fd); return; - } else { - FileHandler *filePtr, *prevPtr; - int i; - ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); + } - /* - * Find the entry for the given file (and return if there isn't one). - */ + /* + * Find the entry for the given file (and return if there isn't one). + */ - for (prevPtr = NULL, filePtr = tsdPtr->firstFileHandlerPtr; ; - prevPtr = filePtr, filePtr = filePtr->nextPtr) { - if (filePtr == NULL) { - return; - } - if (filePtr->fd == fd) { - break; - } + for (prevPtr = NULL, filePtr = tsdPtr->firstFileHandlerPtr; ; + prevPtr = filePtr, filePtr = filePtr->nextPtr) { + if (filePtr == NULL) { + return; } + if (filePtr->fd == fd) { + break; + } + } - /* - * Update the check masks for this file. - */ + /* + * Update the check masks for this file. + */ - if (filePtr->mask & TCL_READABLE) { - FD_CLR(fd, &tsdPtr->checkMasks.readable); - } - if (filePtr->mask & TCL_WRITABLE) { - FD_CLR(fd, &tsdPtr->checkMasks.writable); - } - if (filePtr->mask & TCL_EXCEPTION) { - FD_CLR(fd, &tsdPtr->checkMasks.exception); - } + if (filePtr->mask & TCL_READABLE) { + FD_CLR(fd, &(tsdPtr->checkMasks.readable)); + } + if (filePtr->mask & TCL_WRITABLE) { + FD_CLR(fd, &(tsdPtr->checkMasks.writable)); + } + if (filePtr->mask & TCL_EXCEPTION) { + FD_CLR(fd, &(tsdPtr->checkMasks.exceptional)); + } - /* - * Find current max fd. - */ + /* + * Find current max fd. + */ - if (fd+1 == tsdPtr->numFdBits) { - int numFdBits = 0; + if (fd+1 == tsdPtr->numFdBits) { + int numFdBits = 0; - for (i = fd-1; i >= 0; i--) { - if (FD_ISSET(i, &tsdPtr->checkMasks.readable) - || FD_ISSET(i, &tsdPtr->checkMasks.writable) - || FD_ISSET(i, &tsdPtr->checkMasks.exception)) { - numFdBits = i+1; - break; - } + for (i = fd-1; i >= 0; i--) { + if (FD_ISSET(i, &(tsdPtr->checkMasks.readable)) + || FD_ISSET(i, &(tsdPtr->checkMasks.writable)) + || FD_ISSET(i, &(tsdPtr->checkMasks.exceptional))) { + numFdBits = i+1; + break; } - tsdPtr->numFdBits = numFdBits; } + tsdPtr->numFdBits = numFdBits; + } - /* - * Clean up information in the callback record. - */ + /* + * Clean up information in the callback record. + */ - if (prevPtr == NULL) { - tsdPtr->firstFileHandlerPtr = filePtr->nextPtr; - } else { - prevPtr->nextPtr = filePtr->nextPtr; - } - ckfree(filePtr); + if (prevPtr == NULL) { + tsdPtr->firstFileHandlerPtr = filePtr->nextPtr; + } else { + prevPtr->nextPtr = filePtr->nextPtr; } + ckfree((char *) filePtr); } /* @@ -740,7 +712,7 @@ FileHandlerEventProc( mask = filePtr->readyMask & filePtr->mask; filePtr->readyMask = 0; if (mask != 0) { - filePtr->proc(filePtr->clientData, mask); + (*filePtr->proc)(filePtr->clientData, mask); } break; } @@ -766,12 +738,12 @@ NotifierProc( * Process all of the runnable events. */ - tsdPtr->eventReady = 1; + tsdPtr->eventReady = 1; Tcl_ServiceAll(); return 0; } -#endif /* TCL_THREADS && __CYGWIN__ */ - +#endif /* __CYGWIN__ */ + /* *---------------------------------------------------------------------- * @@ -792,77 +764,107 @@ NotifierProc( int Tcl_WaitForEvent( - const Tcl_Time *timePtr) /* Maximum block time, or NULL. */ + Tcl_Time *timePtr) /* Maximum block time, or NULL. */ { - if (tclNotifierHooks.waitForEventProc) { - return tclNotifierHooks.waitForEventProc(timePtr); - } else { - FileHandler *filePtr; - int mask; - Tcl_Time vTime; + FileHandler *filePtr; + FileHandlerEvent *fileEvPtr; + int mask; + Tcl_Time vTime; #ifdef TCL_THREADS - int waitForFiles; -# ifdef __CYGWIN__ - MSG msg; -# endif /* __CYGWIN__ */ + int waitForFiles; +# ifdef __CYGWIN__ + MSG msg; +# endif #else - /* - * Impl. notes: timeout & timeoutPtr are used if, and only if threads - * are not enabled. They are the arguments for the regular select() - * used when the core is not thread-enabled. - */ + /* + * Impl. notes: timeout & timeoutPtr are used if, and only if threads are + * not enabled. They are the arguments for the regular select() used when + * the core is not thread-enabled. + */ - struct timeval timeout, *timeoutPtr; - int numFound; + struct timeval timeout, *timeoutPtr; + int numFound; #endif /* TCL_THREADS */ - ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); + ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); + + if (tclStubs.tcl_WaitForEvent != tclOriginalNotifier.waitForEventProc) { + return tclStubs.tcl_WaitForEvent(timePtr); + } + /* + * Set up the timeout structure. Note that if there are no events to check + * for, we return with a negative result rather than blocking forever. + */ + + if (timePtr != NULL) { /* - * Set up the timeout structure. Note that if there are no events to - * check for, we return with a negative result rather than blocking - * forever. + * TIP #233 (Virtualized Time). Is virtual time in effect? And do we + * actually have something to scale? If yes to both then we call the + * handler to do this scaling. */ - if (timePtr != NULL) { - /* - * TIP #233 (Virtualized Time). Is virtual time in effect? And do - * we actually have something to scale? If yes to both then we - * call the handler to do this scaling. - */ - - if (timePtr->sec != 0 || timePtr->usec != 0) { - vTime = *timePtr; - tclScaleTimeProcPtr(&vTime, tclTimeClientData); - timePtr = &vTime; - } + if (timePtr->sec != 0 || timePtr->usec != 0) { + vTime = *timePtr; + (*tclScaleTimeProcPtr) (&vTime, tclTimeClientData); + timePtr = &vTime; + } #ifndef TCL_THREADS - timeout.tv_sec = timePtr->sec; - timeout.tv_usec = timePtr->usec; - timeoutPtr = &timeout; - } else if (tsdPtr->numFdBits == 0) { - /* - * If there are no threads, no timeout, and no fds registered, - * then there are no events possible and we must avoid deadlock. - * Note that this is not entirely correct because there might be a - * signal that could interrupt the select call, but we don't - * handle that case if we aren't using threads. - */ + timeout.tv_sec = timePtr->sec; + timeout.tv_usec = timePtr->usec; + timeoutPtr = &timeout; + } else if (tsdPtr->numFdBits == 0) { + /* + * If there are no threads, no timeout, and no fds registered, then + * there are no events possible and we must avoid deadlock. Note that + * this is not entirely correct because there might be a signal that + * could interrupt the select call, but we don't handle that case if + * we aren't using threads. + */ - return -1; - } else { - timeoutPtr = NULL; -#endif /* !TCL_THREADS */ - } + return -1; + } else { + timeoutPtr = NULL; +#endif /* TCL_THREADS */ + } #ifdef TCL_THREADS + /* + * Place this thread on the list of interested threads, signal the + * notifier thread, and wait for a response or a timeout. + */ + + Tcl_MutexLock(¬ifierMutex); + + if (timePtr != NULL && timePtr->sec == 0 && (timePtr->usec == 0 +#if defined(__APPLE__) && defined(__LP64__) + /* + * On 64-bit Darwin, pthread_cond_timedwait() appears to have a bug + * that causes it to wait forever when passed an absolute time which + * has already been exceeded by the system time; as a workaround, + * when given a very brief timeout, just do a poll. [Bug 1457797] + */ + || timePtr->usec < 10 +#endif + )) { /* - * Place this thread on the list of interested threads, signal the - * notifier thread, and wait for a response or a timeout. + * Cannot emulate a polling select with a polling condition variable. + * Instead, pretend to wait for files and tell the notifier thread + * what we are doing. The notifier thread makes sure it goes through + * select with its select mask in the same state as ours currently is. + * We block until that happens. */ + waitForFiles = 1; + tsdPtr->pollState = POLL_WANT; + timePtr = NULL; + } else { + waitForFiles = (tsdPtr->numFdBits > 0); + tsdPtr->pollState = 0; + } + #ifdef __CYGWIN__ if (!tsdPtr->hwnd) { - WNDCLASS class; + WNDCLASS class; class.style = 0; class.cbClsExtra = 0; @@ -876,191 +878,153 @@ Tcl_WaitForEvent( class.hCursor = NULL; RegisterClassW(&class); - tsdPtr->hwnd = CreateWindowExW(NULL, class.lpszClassName, - class.lpszClassName, 0, 0, 0, 0, 0, NULL, NULL, - TclWinGetTclInstance(), NULL); + tsdPtr->hwnd = CreateWindowExW(NULL, class.lpszClassName, class.lpszClassName, + 0, 0, 0, 0, 0, NULL, NULL, TclWinGetTclInstance(), NULL); tsdPtr->event = CreateEventW(NULL, 1 /* manual */, 0 /* !signaled */, NULL); - } -#endif /* __CYGWIN */ - - Tcl_MutexLock(¬ifierMutex); + } - if (timePtr != NULL && timePtr->sec == 0 && (timePtr->usec == 0 -#if defined(__APPLE__) && defined(__LP64__) - /* - * On 64-bit Darwin, pthread_cond_timedwait() appears to have - * a bug that causes it to wait forever when passed an - * absolute time which has already been exceeded by the system - * time; as a workaround, when given a very brief timeout, - * just do a poll. [Bug 1457797] - */ - || timePtr->usec < 10 -#endif /* __APPLE__ && __LP64__ */ - )) { - /* - * Cannot emulate a polling select with a polling condition - * variable. Instead, pretend to wait for files and tell the - * notifier thread what we are doing. The notifier thread makes - * sure it goes through select with its select mask in the same - * state as ours currently is. We block until that happens. - */ +#endif + if (waitForFiles) { + /* + * Add the ThreadSpecificData structure of this thread to the list of + * ThreadSpecificData structures of all threads that are waiting on + * file events. + */ - waitForFiles = 1; - tsdPtr->pollState = POLL_WANT; - timePtr = NULL; - } else { - waitForFiles = (tsdPtr->numFdBits > 0); - tsdPtr->pollState = 0; + tsdPtr->nextPtr = waitingListPtr; + if (waitingListPtr) { + waitingListPtr->prevPtr = tsdPtr; } + tsdPtr->prevPtr = 0; + waitingListPtr = tsdPtr; + tsdPtr->onList = 1; - if (waitForFiles) { - /* - * Add the ThreadSpecificData structure of this thread to the list - * of ThreadSpecificData structures of all threads that are - * waiting on file events. - */ - - tsdPtr->nextPtr = waitingListPtr; - if (waitingListPtr) { - waitingListPtr->prevPtr = tsdPtr; - } - tsdPtr->prevPtr = 0; - waitingListPtr = tsdPtr; - tsdPtr->onList = 1; - - if ((write(triggerPipe, "", 1) == -1) && (errno != EAGAIN)) { - Tcl_Panic("Tcl_WaitForEvent: %s", - "unable to write to triggerPipe"); - } + if ((write(triggerPipe, "", 1) == -1) && (errno != EAGAIN)) { + Tcl_Panic("Tcl_WaitForEvent: unable to write to triggerPipe"); } + } - FD_ZERO(&tsdPtr->readyMasks.readable); - FD_ZERO(&tsdPtr->readyMasks.writable); - FD_ZERO(&tsdPtr->readyMasks.exception); + FD_ZERO(&(tsdPtr->readyMasks.readable)); + FD_ZERO(&(tsdPtr->readyMasks.writable)); + FD_ZERO(&(tsdPtr->readyMasks.exceptional)); - if (!tsdPtr->eventReady) { + if (!tsdPtr->eventReady) { #ifdef __CYGWIN__ - if (!PeekMessageW(&msg, NULL, 0, 0, 0)) { - DWORD timeout; - - if (timePtr) { - timeout = timePtr->sec * 1000 + timePtr->usec / 1000; - } else { - timeout = 0xFFFFFFFF; - } - Tcl_MutexUnlock(¬ifierMutex); - MsgWaitForMultipleObjects(1, &tsdPtr->event, 0, timeout, 1279); - Tcl_MutexLock(¬ifierMutex); + if (!PeekMessageW(&msg, NULL, 0, 0, 0)) { + DWORD timeout; + if (timePtr) { + timeout = timePtr->sec * 1000 + timePtr->usec / 1000; + } else { + timeout = 0xFFFFFFFF; } -#else - Tcl_ConditionWait(&tsdPtr->waitCV, ¬ifierMutex, timePtr); -#endif /* __CYGWIN__ */ + Tcl_MutexUnlock(¬ifierMutex); + MsgWaitForMultipleObjects(1, &tsdPtr->event, 0, timeout, 1279); + Tcl_MutexLock(¬ifierMutex); } - tsdPtr->eventReady = 0; +#else + Tcl_ConditionWait(&tsdPtr->waitCV, ¬ifierMutex, timePtr); +#endif + } + tsdPtr->eventReady = 0; #ifdef __CYGWIN__ - while (PeekMessageW(&msg, NULL, 0, 0, 0)) { - /* - * Retrieve and dispatch the message. - */ - - DWORD result = GetMessageW(&msg, NULL, 0, 0); - - if (result == 0) { - PostQuitMessage(msg.wParam); - /* What to do here? */ - } else if (result != (DWORD) -1) { - TranslateMessage(&msg); - DispatchMessageW(&msg); - } + while (PeekMessageW(&msg, NULL, 0, 0, 0)) { + /* + * Retrieve and dispatch the message. + */ + DWORD result = GetMessageW(&msg, NULL, 0, 0); + if (result == 0) { + PostQuitMessage(msg.wParam); + /* What to do here? */ + } else if (result != (DWORD)-1) { + TranslateMessage(&msg); + DispatchMessageW(&msg); } - ResetEvent(tsdPtr->event); -#endif /* __CYGWIN__ */ + } + ResetEvent(tsdPtr->event); +#endif - if (waitForFiles && tsdPtr->onList) { - /* - * Remove the ThreadSpecificData structure of this thread from the - * waiting list. Alert the notifier thread to recompute its select - * masks - skipping this caused a hang when trying to close a pipe - * which the notifier thread was still doing a select on. - */ + if (waitForFiles && tsdPtr->onList) { + /* + * Remove the ThreadSpecificData structure of this thread from the + * waiting list. Alert the notifier thread to recompute its select + * masks - skipping this caused a hang when trying to close a pipe + * which the notifier thread was still doing a select on. + */ - if (tsdPtr->prevPtr) { - tsdPtr->prevPtr->nextPtr = tsdPtr->nextPtr; - } else { - waitingListPtr = tsdPtr->nextPtr; - } - if (tsdPtr->nextPtr) { - tsdPtr->nextPtr->prevPtr = tsdPtr->prevPtr; - } - tsdPtr->nextPtr = tsdPtr->prevPtr = NULL; - tsdPtr->onList = 0; - if ((write(triggerPipe, "", 1) == -1) && (errno != EAGAIN)) { - Tcl_Panic("Tcl_WaitForEvent: %s", - "unable to write to triggerPipe"); - } + if (tsdPtr->prevPtr) { + tsdPtr->prevPtr->nextPtr = tsdPtr->nextPtr; + } else { + waitingListPtr = tsdPtr->nextPtr; + } + if (tsdPtr->nextPtr) { + tsdPtr->nextPtr->prevPtr = tsdPtr->prevPtr; + } + tsdPtr->nextPtr = tsdPtr->prevPtr = NULL; + tsdPtr->onList = 0; + if ((write(triggerPipe, "", 1) == -1) && (errno != EAGAIN)) { + Tcl_Panic("Tcl_WaitForEvent: unable to write to triggerPipe"); } + } #else - tsdPtr->readyMasks = tsdPtr->checkMasks; - numFound = select(tsdPtr->numFdBits, &tsdPtr->readyMasks.readable, - &tsdPtr->readyMasks.writable, &tsdPtr->readyMasks.exception, - timeoutPtr); + tsdPtr->readyMasks = tsdPtr->checkMasks; + numFound = select(tsdPtr->numFdBits, &(tsdPtr->readyMasks.readable), + &(tsdPtr->readyMasks.writable), &(tsdPtr->readyMasks.exceptional), + timeoutPtr); - /* - * Some systems don't clear the masks after an error, so we have to do - * it here. - */ + /* + * Some systems don't clear the masks after an error, so we have to do it + * here. + */ - if (numFound == -1) { - FD_ZERO(&tsdPtr->readyMasks.readable); - FD_ZERO(&tsdPtr->readyMasks.writable); - FD_ZERO(&tsdPtr->readyMasks.exception); - } + if (numFound == -1) { + FD_ZERO(&(tsdPtr->readyMasks.readable)); + FD_ZERO(&(tsdPtr->readyMasks.writable)); + FD_ZERO(&(tsdPtr->readyMasks.exceptional)); + } #endif /* TCL_THREADS */ - /* - * Queue all detected file events before returning. - */ + /* + * Queue all detected file events before returning. + */ - for (filePtr = tsdPtr->firstFileHandlerPtr; (filePtr != NULL); - filePtr = filePtr->nextPtr) { - mask = 0; - if (FD_ISSET(filePtr->fd, &tsdPtr->readyMasks.readable)) { - mask |= TCL_READABLE; - } - if (FD_ISSET(filePtr->fd, &tsdPtr->readyMasks.writable)) { - mask |= TCL_WRITABLE; - } - if (FD_ISSET(filePtr->fd, &tsdPtr->readyMasks.exception)) { - mask |= TCL_EXCEPTION; - } + for (filePtr = tsdPtr->firstFileHandlerPtr; (filePtr != NULL); + filePtr = filePtr->nextPtr) { - if (!mask) { - continue; - } + mask = 0; + if (FD_ISSET(filePtr->fd, &(tsdPtr->readyMasks.readable))) { + mask |= TCL_READABLE; + } + if (FD_ISSET(filePtr->fd, &(tsdPtr->readyMasks.writable))) { + mask |= TCL_WRITABLE; + } + if (FD_ISSET(filePtr->fd, &(tsdPtr->readyMasks.exceptional))) { + mask |= TCL_EXCEPTION; + } - /* - * Don't bother to queue an event if the mask was previously - * non-zero since an event must still be on the queue. - */ + if (!mask) { + continue; + } - if (filePtr->readyMask == 0) { - FileHandlerEvent *fileEvPtr = - ckalloc(sizeof(FileHandlerEvent)); + /* + * Don't bother to queue an event if the mask was previously non-zero + * since an event must still be on the queue. + */ - fileEvPtr->header.proc = FileHandlerEventProc; - fileEvPtr->fd = filePtr->fd; - Tcl_QueueEvent((Tcl_Event *) fileEvPtr, TCL_QUEUE_TAIL); - } - filePtr->readyMask = mask; + if (filePtr->readyMask == 0) { + fileEvPtr = (FileHandlerEvent *) ckalloc(sizeof(FileHandlerEvent)); + fileEvPtr->header.proc = FileHandlerEventProc; + fileEvPtr->fd = filePtr->fd; + Tcl_QueueEvent((Tcl_Event *) fileEvPtr, TCL_QUEUE_TAIL); } + filePtr->readyMask = mask; + } #ifdef TCL_THREADS - Tcl_MutexUnlock(¬ifierMutex); + Tcl_MutexUnlock(¬ifierMutex); #endif /* TCL_THREADS */ - return 0; - } + return 0; } #ifdef TCL_THREADS @@ -1095,7 +1059,7 @@ NotifierThreadProc( ThreadSpecificData *tsdPtr; fd_set readableMask; fd_set writableMask; - fd_set exceptionMask; + fd_set exceptionalMask; int fds[2]; int i, numFdBits = 0, receivePipe; long found; @@ -1103,26 +1067,22 @@ NotifierThreadProc( char buf[2]; if (pipe(fds) != 0) { - Tcl_Panic("NotifierThreadProc: %s", "could not create trigger pipe"); + Tcl_Panic("NotifierThreadProc: could not create trigger pipe"); } receivePipe = fds[0]; if (TclUnixSetBlockingMode(receivePipe, TCL_MODE_NONBLOCKING) < 0) { - Tcl_Panic("NotifierThreadProc: %s", - "could not make receive pipe non blocking"); + Tcl_Panic("NotifierThreadProc: could not make receive pipe non blocking"); } if (TclUnixSetBlockingMode(fds[1], TCL_MODE_NONBLOCKING) < 0) { - Tcl_Panic("NotifierThreadProc: %s", - "could not make trigger pipe non blocking"); + Tcl_Panic("NotifierThreadProc: could not make trigger pipe non blocking"); } if (fcntl(receivePipe, F_SETFD, FD_CLOEXEC) < 0) { - Tcl_Panic("NotifierThreadProc: %s", - "could not make receive pipe close-on-exec"); + Tcl_Panic("NotifierThreadProc: could not make receive pipe close-on-exec"); } if (fcntl(fds[1], F_SETFD, FD_CLOEXEC) < 0) { - Tcl_Panic("NotifierThreadProc: %s", - "could not make trigger pipe close-on-exec"); + Tcl_Panic("NotifierThreadProc: could not make trigger pipe close-on-exec"); } /* @@ -1146,7 +1106,7 @@ NotifierThreadProc( while (1) { FD_ZERO(&readableMask); FD_ZERO(&writableMask); - FD_ZERO(&exceptionMask); + FD_ZERO(&exceptionalMask); /* * Compute the logical OR of the select masks from all the waiting @@ -1157,14 +1117,14 @@ NotifierThreadProc( timePtr = NULL; for (tsdPtr = waitingListPtr; tsdPtr; tsdPtr = tsdPtr->nextPtr) { for (i = tsdPtr->numFdBits-1; i >= 0; --i) { - if (FD_ISSET(i, &tsdPtr->checkMasks.readable)) { + if (FD_ISSET(i, &(tsdPtr->checkMasks.readable))) { FD_SET(i, &readableMask); } - if (FD_ISSET(i, &tsdPtr->checkMasks.writable)) { + if (FD_ISSET(i, &(tsdPtr->checkMasks.writable))) { FD_SET(i, &writableMask); } - if (FD_ISSET(i, &tsdPtr->checkMasks.exception)) { - FD_SET(i, &exceptionMask); + if (FD_ISSET(i, &(tsdPtr->checkMasks.exceptional))) { + FD_SET(i, &exceptionalMask); } } if (tsdPtr->numFdBits > numFdBits) { @@ -1191,7 +1151,7 @@ NotifierThreadProc( } FD_SET(receivePipe, &readableMask); - if (select(numFdBits, &readableMask, &writableMask, &exceptionMask, + if (select(numFdBits, &readableMask, &writableMask, &exceptionalMask, timePtr) == -1) { /* * Try again immediately on an error. @@ -1209,19 +1169,19 @@ NotifierThreadProc( found = 0; for (i = tsdPtr->numFdBits-1; i >= 0; --i) { - if (FD_ISSET(i, &tsdPtr->checkMasks.readable) + if (FD_ISSET(i, &(tsdPtr->checkMasks.readable)) && FD_ISSET(i, &readableMask)) { - FD_SET(i, &tsdPtr->readyMasks.readable); + FD_SET(i, &(tsdPtr->readyMasks.readable)); found = 1; } - if (FD_ISSET(i, &tsdPtr->checkMasks.writable) + if (FD_ISSET(i, &(tsdPtr->checkMasks.writable)) && FD_ISSET(i, &writableMask)) { - FD_SET(i, &tsdPtr->readyMasks.writable); + FD_SET(i, &(tsdPtr->readyMasks.writable)); found = 1; } - if (FD_ISSET(i, &tsdPtr->checkMasks.exception) - && FD_ISSET(i, &exceptionMask)) { - FD_SET(i, &tsdPtr->readyMasks.exception); + if (FD_ISSET(i, &(tsdPtr->checkMasks.exceptional)) + && FD_ISSET(i, &exceptionalMask)) { + FD_SET(i, &(tsdPtr->readyMasks.exceptional)); found = 1; } } @@ -1249,9 +1209,9 @@ NotifierThreadProc( tsdPtr->pollState = 0; } #ifdef __CYGWIN__ - PostMessageW(tsdPtr->hwnd, 1024, 0, 0); -#else - Tcl_ConditionNotify(&tsdPtr->waitCV); + PostMessageW(tsdPtr->hwnd, 1024, 0, 0); +#else /* __CYGWIN__ */ + Tcl_ConditionNotify(&tsdPtr->waitCV); #endif /* __CYGWIN__ */ } } @@ -1289,11 +1249,11 @@ NotifierThreadProc( Tcl_ConditionNotify(¬ifierCV); Tcl_MutexUnlock(¬ifierMutex); - TclpThreadExit(0); + TclpThreadExit (0); } #endif /* TCL_THREADS */ -#endif /* !HAVE_COREFOUNDATION */ +#endif /* HAVE_COREFOUNDATION */ /* * Local Variables: |