diff options
Diffstat (limited to 'unix/tclUnixNotfy.c')
| -rw-r--r-- | unix/tclUnixNotfy.c | 682 |
1 files changed, 333 insertions, 349 deletions
diff --git a/unix/tclUnixNotfy.c b/unix/tclUnixNotfy.c index 51f0b1f..128b080 100644 --- a/unix/tclUnixNotfy.c +++ b/unix/tclUnixNotfy.c @@ -1,65 +1,63 @@ /* * tclUnixNotify.c -- * - * This file contains the implementation of the select()-based - * Unix-specific notifier, which is the lowest-level part of the Tcl - * event loop. This file works together with generic/tclNotify.c. + * This file contains the implementation of the select-based + * Unix-specific notifier, which is the lowest-level part of the + * Tcl event loop. This file works together with + * ../generic/tclNotify.c. * * 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" -#ifndef HAVE_COREFOUNDATION /* Darwin/Mac OS X CoreFoundation notifier is - * in tclMacOSXNotify.c */ -#include <signal.h> - -/* - * This code does deep stub magic to allow replacement of the notifier at - * runtime. - */ +#include "tclPort.h" +#ifndef HAVE_COREFOUNDATION /* Darwin/Mac OS X CoreFoundation notifier + * is in tclMacOSXNotify.c */ +#include <signal.h> extern TclStubs tclStubs; extern Tcl_NotifierProcs tclOriginalNotifier; /* - * This structure is used to keep track of the notifier info for a registered - * file. + * This structure is used to keep track of the notifier info for a + * a registered file. */ typedef struct FileHandler { int fd; int mask; /* Mask of desired events: TCL_READABLE, * etc. */ - int readyMask; /* Mask of events that have been seen since - * the last time file handlers were invoked - * for this file. */ - Tcl_FileProc *proc; /* Function to call, in the style of + int readyMask; /* Mask of events that have been seen since the + * last time file handlers were invoked for + * this file. */ + Tcl_FileProc *proc; /* Procedure to call, in the style of * Tcl_CreateFileHandler. */ ClientData clientData; /* Argument to pass to proc. */ struct FileHandler *nextPtr;/* Next in list of all files we care about. */ } FileHandler; /* - * The following structure is what is added to the Tcl event queue when file - * handlers are ready to fire. + * The following structure is what is added to the Tcl event queue when + * file handlers are ready to fire. */ typedef struct FileHandlerEvent { - Tcl_Event header; /* Information that is standard for all - * events. */ - int fd; /* File descriptor that is ready. Used to find - * the FileHandler structure for the file - * (can't point directly to the FileHandler - * structure because it could go away while - * the event is queued). */ + Tcl_Event header; /* Information that is standard for + * all events. */ + int fd; /* File descriptor that is ready. Used + * to find the FileHandler structure for + * the file (can't point directly to the + * FileHandler structure because it could + * go away while the event is queued). */ } FileHandlerEvent; /* - * The following structure contains a set of select() masks to track readable, - * writable, and exceptional conditions. + * + * The following structure contains a set of select() masks to track + * readable, writable, and exceptional conditions. */ typedef struct SelectMasks { @@ -70,48 +68,49 @@ typedef struct SelectMasks { /* * The following static structure contains the state information for the - * select based implementation of the Tcl notifier. One of these structures is - * created for each thread that is using the notifier. + * select based implementation of the Tcl notifier. One of these structures + * is created for each thread that is using the notifier. */ typedef struct ThreadSpecificData { FileHandler *firstFileHandlerPtr; /* Pointer to head of file handler list. */ - SelectMasks checkMasks; /* This structure is used to build up the - * masks to be used in the next call to - * select. Bits are set in response to calls - * to Tcl_CreateFileHandler. */ + + SelectMasks checkMasks; /* This structure is used to build up the masks + * to be used in the next call to select. + * Bits are set in response to calls to + * Tcl_CreateFileHandler. */ SelectMasks readyMasks; /* This array reflects the readable/writable * conditions that were found to exist by the * last call to select. */ - int numFdBits; /* Number of valid bits in checkMasks (one - * more than highest fd for which + int numFdBits; /* Number of valid bits in checkMasks + * (one more than highest fd for which * Tcl_WatchFile has been called). */ #ifdef TCL_THREADS int onList; /* True if it is in this list */ - unsigned int pollState; /* pollState is used to implement a polling + unsigned int pollState; /* pollState is used to implement a polling * handshake between each thread and the * notifier thread. Bits defined below. */ struct ThreadSpecificData *nextPtr, *prevPtr; - /* All threads that are currently waiting on - * an event have their ThreadSpecificData - * structure on a doubly-linked listed formed - * from these pointers. You must hold the - * notifierMutex lock before accessing these - * fields. */ + /* All threads that are currently waiting on + * an event have their ThreadSpecificData + * structure on a doubly-linked listed formed + * from these pointers. You must hold the + * notifierMutex lock before accessing these + * fields. */ #ifdef __CYGWIN__ void *event; /* Any other thread alerts a notifier * that an event is ready to be processed * by sending this event. */ void *hwnd; /* Messaging window. */ #else /* !__CYGWIN__ */ - Tcl_Condition waitCV; /* Any other thread alerts a notifier that an - * event is ready to be processed by signaling - * this condition variable. */ + Tcl_Condition waitCV; /* Any other thread alerts a notifier + * that an event is ready to be processed + * by signaling this condition variable. */ #endif /* __CYGWIN__ */ - int eventReady; /* True if an event is ready to be processed. - * Used as condition flag together with waitCV - * above. */ + int eventReady; /* True if an event is ready to be processed. + * Used as condition flag together with + * waitCV above. */ #endif } ThreadSpecificData; @@ -119,8 +118,8 @@ static Tcl_ThreadDataKey dataKey; #ifdef TCL_THREADS /* - * The following static indicates the number of threads that have initialized - * notifiers. + * The following static indicates the number of threads that have + * initialized notifiers. * * You must hold the notifierMutex lock before accessing this variable. */ @@ -128,9 +127,9 @@ static Tcl_ThreadDataKey dataKey; static int notifierCount = 0; /* - * The following variable points to the head of a doubly-linked list of - * ThreadSpecificData structures for all threads that are currently waiting on - * an event. + * The following variable points to the head of a doubly-linked list of + * of ThreadSpecificData structures for all threads that are currently + * waiting on an event. * * You must hold the notifierMutex lock before accessing this list. */ @@ -138,31 +137,32 @@ static int notifierCount = 0; static ThreadSpecificData *waitingListPtr = NULL; /* - * The notifier thread spends all its time in select() waiting for a file - * descriptor associated with one of the threads on the waitingListPtr list to - * do something interesting. But if the contents of the waitingListPtr list - * ever changes, we need to wake up and restart the select() system call. You - * can wake up the notifier thread by writing a single byte to the file - * descriptor defined below. This file descriptor is the input-end of a pipe - * and the notifier thread is listening for data on the output-end of the same - * pipe. Hence writing to this file descriptor will cause the select() system - * call to return and wake up the notifier thread. + * The notifier thread spends all its time in select() waiting for a + * file descriptor associated with one of the threads on the waitingListPtr + * list to do something interesting. But if the contents of the + * waitingListPtr list ever changes, we need to wake up and restart + * the select() system call. You can wake up the notifier thread by + * writing a single byte to the file descriptor defined below. This + * file descriptor is the input-end of a pipe and the notifier thread is + * listening for data on the output-end of the same pipe. Hence writing + * to this file descriptor will cause the select() system call to return + * and wake up the notifier thread. * - * You must hold the notifierMutex lock before writing to the pipe. + * You must hold the notifierMutex lock before accessing this list. */ static int triggerPipe = -1; /* - * The notifierMutex locks access to all of the global notifier state. + * The notifierMutex locks access to all of the global notifier state. */ TCL_DECLARE_MUTEX(notifierMutex) /* * The notifier thread signals the notifierCV when it has finished - * initializing the triggerPipe and right before the notifier thread - * terminates. + * initializing the triggerPipe and right before the notifier + * thread terminates. */ static Tcl_Condition notifierCV; @@ -170,19 +170,18 @@ static Tcl_Condition notifierCV; /* * The pollState bits * POLL_WANT is set by each thread before it waits on its condition - * variable. It is checked by the notifier before it does select. - * POLL_DONE is set by the notifier if it goes into select after seeing - * POLL_WANT. The idea is to ensure it tries a select with the - * same bits the initial thread had set. + * variable. It is checked by the notifier before it does + * select. + * POLL_DONE is set by the notifier if it goes into select after + * seeing POLL_WANT. The idea is to ensure it tries a select + * with the same bits the initial thread had set. */ - #define POLL_WANT 0x1 #define POLL_DONE 0x2 /* * This is the thread ID of the notifier thread that does select. */ - static Tcl_ThreadId notifierThread; #endif @@ -192,9 +191,10 @@ static Tcl_ThreadId notifierThread; */ #ifdef TCL_THREADS -static void NotifierThreadProc(ClientData clientData); +static void NotifierThreadProc _ANSI_ARGS_((ClientData clientData)); #endif -static int FileHandlerEventProc(Tcl_Event *evPtr, int flags); +static int FileHandlerEventProc _ANSI_ARGS_((Tcl_Event *evPtr, + int flags)); /* *---------------------------------------------------------------------- @@ -204,7 +204,7 @@ static int FileHandlerEventProc(Tcl_Event *evPtr, int flags); * Initializes the platform specific notifier state. * * Results: - * Returns a handle to the notifier state for this thread. + * Returns a handle to the notifier state for this thread.. * * Side effects: * None. @@ -255,7 +255,7 @@ extern unsigned char __stdcall ResetEvent(void *); #endif ClientData -Tcl_InitNotifier(void) +Tcl_InitNotifier() { ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); @@ -269,8 +269,8 @@ Tcl_InitNotifier(void) Tcl_MutexLock(¬ifierMutex); 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_THREAD_STACK_DEFAULT, TCL_THREAD_JOINABLE) != TCL_OK) { + panic("Tcl_InitNotifier: unable to start notifier thread"); } } notifierCount++; @@ -293,22 +293,22 @@ Tcl_InitNotifier(void) * * Tcl_FinalizeNotifier -- * - * This function is called to cleanup the notifier state before a thread - * is terminated. + * This function is called to cleanup the notifier state before + * a thread is terminated. * * Results: * None. * * Side effects: - * May terminate the background notifier thread if this is the last - * notifier instance. + * May terminate the background notifier thread if this is the + * last notifier instance. * *---------------------------------------------------------------------- */ void -Tcl_FinalizeNotifier( - ClientData clientData) /* Not used. */ +Tcl_FinalizeNotifier(clientData) + ClientData clientData; /* Not used. */ { #ifdef TCL_THREADS ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); @@ -317,36 +317,32 @@ Tcl_FinalizeNotifier( 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 (triggerPipe < 0) { - Tcl_Panic("Tcl_FinalizeNotifier: notifier pipe not initialized"); + 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: unable to write q to triggerPipe"); - } + write(triggerPipe, "q", 1); close(triggerPipe); while(triggerPipe >= 0) { Tcl_ConditionWait(¬ifierCV, ¬ifierMutex, NULL); } - result = Tcl_JoinThread(notifierThread, NULL); if (result) { Tcl_Panic("Tcl_FinalizeNotifier: unable to join notifier thread"); @@ -372,23 +368,25 @@ Tcl_FinalizeNotifier( * * Tcl_AlertNotifier -- * - * Wake up the specified notifier from any thread. This routine is called - * by the platform independent notifier code whenever the Tcl_ThreadAlert - * routine is called. This routine is guaranteed not to be called on a - * given notifier after Tcl_FinalizeNotifier is called for that notifier. + * Wake up the specified notifier from any thread. This routine + * is called by the platform independent notifier code whenever + * the Tcl_ThreadAlert routine is called. This routine is + * guaranteed not to be called on a given notifier after + * Tcl_FinalizeNotifier is called for that notifier. * * Results: * None. * * Side effects: - * Signals the notifier condition variable for the specified notifier. + * Signals the notifier condition variable for the specified + * notifier. * *---------------------------------------------------------------------- */ void -Tcl_AlertNotifier( - ClientData clientData) +Tcl_AlertNotifier(clientData) + ClientData clientData; { #ifdef TCL_THREADS ThreadSpecificData *tsdPtr = (ThreadSpecificData *) clientData; @@ -408,9 +406,9 @@ Tcl_AlertNotifier( * * Tcl_SetTimer -- * - * This function sets the current notifier timer value. This interface is - * not implemented in this notifier because we are always running inside - * of Tcl_DoOneEvent. + * This procedure sets the current notifier timer value. This + * interface is not implemented in this notifier because we are + * always running inside of Tcl_DoOneEvent. * * Results: * None. @@ -422,13 +420,13 @@ Tcl_AlertNotifier( */ void -Tcl_SetTimer( - Tcl_Time *timePtr) /* Timeout value, may be NULL. */ +Tcl_SetTimer(timePtr) + Tcl_Time *timePtr; /* Timeout value, may be NULL. */ { /* - * 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) { @@ -453,8 +451,8 @@ Tcl_SetTimer( */ void -Tcl_ServiceModeHook( - int mode) /* Either TCL_SERVICE_ALL, or +Tcl_ServiceModeHook(mode) + int mode; /* Either TCL_SERVICE_ALL, or * TCL_SERVICE_NONE. */ { } @@ -464,7 +462,7 @@ Tcl_ServiceModeHook( * * Tcl_CreateFileHandler -- * - * This function registers a file handler with the select notifier. + * This procedure registers a file handler with the select notifier. * * Results: * None. @@ -476,27 +474,26 @@ Tcl_ServiceModeHook( */ void -Tcl_CreateFileHandler( - int fd, /* Handle of stream to watch. */ - int mask, /* OR'ed combination of TCL_READABLE, - * TCL_WRITABLE, and TCL_EXCEPTION: indicates - * conditions under which proc should be - * called. */ - Tcl_FileProc *proc, /* Function to call for each selected - * event. */ - ClientData clientData) /* Arbitrary data to pass to proc. */ +Tcl_CreateFileHandler(fd, mask, proc, clientData) + int fd; /* Handle of stream to watch. */ + int mask; /* OR'ed combination of TCL_READABLE, + * TCL_WRITABLE, and TCL_EXCEPTION: + * indicates conditions under which + * proc should be called. */ + Tcl_FileProc *proc; /* Procedure to call for each + * selected event. */ + ClientData clientData; /* Arbitrary data to pass to proc. */ { ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); FileHandler *filePtr; - if (tclStubs.tcl_CreateFileHandler != - tclOriginalNotifier.createFileHandlerProc) { + if (tclStubs.tcl_CreateFileHandler != tclOriginalNotifier.createFileHandlerProc) { tclStubs.tcl_CreateFileHandler(fd, mask, proc, clientData); return; } for (filePtr = tsdPtr->firstFileHandlerPtr; filePtr != NULL; - filePtr = filePtr->nextPtr) { + filePtr = filePtr->nextPtr) { if (filePtr->fd == fd) { break; } @@ -516,20 +513,20 @@ Tcl_CreateFileHandler( * Update the check masks for this file. */ - if (mask & TCL_READABLE) { - FD_SET(fd, &(tsdPtr->checkMasks.readable)); + if ( mask & TCL_READABLE ) { + FD_SET( fd, &(tsdPtr->checkMasks.readable) ); } else { - FD_CLR(fd, &(tsdPtr->checkMasks.readable)); + FD_CLR( fd, &(tsdPtr->checkMasks.readable) ); } - if (mask & TCL_WRITABLE) { - FD_SET(fd, &(tsdPtr->checkMasks.writable)); + if ( mask & TCL_WRITABLE ) { + FD_SET( fd, &(tsdPtr->checkMasks.writable) ); } else { - FD_CLR(fd, &(tsdPtr->checkMasks.writable)); + FD_CLR( fd, &(tsdPtr->checkMasks.writable) ); } - if (mask & TCL_EXCEPTION) { - FD_SET(fd, &(tsdPtr->checkMasks.exceptional)); + if ( mask & TCL_EXCEPTION ) { + FD_SET( fd, &(tsdPtr->checkMasks.exceptional) ); } else { - FD_CLR(fd, &(tsdPtr->checkMasks.exceptional)); + FD_CLR( fd, &(tsdPtr->checkMasks.exceptional) ); } if (tsdPtr->numFdBits <= fd) { tsdPtr->numFdBits = fd+1; @@ -541,7 +538,8 @@ Tcl_CreateFileHandler( * * Tcl_DeleteFileHandler -- * - * Cancel a previously-arranged callback arrangement for a file. + * Cancel a previously-arranged callback arrangement for + * a file. * * Results: * None. @@ -553,16 +551,14 @@ Tcl_CreateFileHandler( */ void -Tcl_DeleteFileHandler( - int fd) /* Stream id for which to remove callback - * function. */ +Tcl_DeleteFileHandler(fd) + int fd; /* Stream id for which to remove callback procedure. */ { FileHandler *filePtr, *prevPtr; int i; ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); - if (tclStubs.tcl_DeleteFileHandler != - tclOriginalNotifier.deleteFileHandlerProc) { + if (tclStubs.tcl_DeleteFileHandler != tclOriginalNotifier.deleteFileHandlerProc) { tclStubs.tcl_DeleteFileHandler(fd); return; } @@ -586,13 +582,13 @@ Tcl_DeleteFileHandler( */ if (filePtr->mask & TCL_READABLE) { - FD_CLR(fd, &(tsdPtr->checkMasks.readable)); + FD_CLR( fd, &(tsdPtr->checkMasks.readable) ); } if (filePtr->mask & TCL_WRITABLE) { - FD_CLR(fd, &(tsdPtr->checkMasks.writable)); + FD_CLR( fd, &(tsdPtr->checkMasks.writable) ); } if (filePtr->mask & TCL_EXCEPTION) { - FD_CLR(fd, &(tsdPtr->checkMasks.exceptional)); + FD_CLR( fd, &(tsdPtr->checkMasks.exceptional) ); } /* @@ -600,17 +596,15 @@ Tcl_DeleteFileHandler( */ if (fd+1 == tsdPtr->numFdBits) { - int numFdBits = 0; - + tsdPtr->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.exceptional))) { - numFdBits = i+1; + if ( FD_ISSET( i, &(tsdPtr->checkMasks.readable) ) + || FD_ISSET( i, &(tsdPtr->checkMasks.writable) ) + || FD_ISSET( i, &(tsdPtr->checkMasks.exceptional ) ) ) { + tsdPtr->numFdBits = i+1; break; } } - tsdPtr->numFdBits = numFdBits; } /* @@ -630,28 +624,28 @@ Tcl_DeleteFileHandler( * * FileHandlerEventProc -- * - * This function is called by Tcl_ServiceEvent when a file event reaches - * the front of the event queue. This function is responsible for - * actually handling the event by invoking the callback for the file - * handler. + * This procedure is called by Tcl_ServiceEvent when a file event + * reaches the front of the event queue. This procedure is + * responsible for actually handling the event by invoking the + * callback for the file handler. * * Results: - * Returns 1 if the event was handled, meaning it should be removed from - * the queue. Returns 0 if the event was not handled, meaning it should - * stay on the queue. The only time the event isn't handled is if the - * TCL_FILE_EVENTS flag bit isn't set. + * Returns 1 if the event was handled, meaning it should be removed + * from the queue. Returns 0 if the event was not handled, meaning + * it should stay on the queue. The only time the event isn't + * handled is if the TCL_FILE_EVENTS flag bit isn't set. * * Side effects: - * Whatever the file handler's callback function does. + * Whatever the file handler's callback procedure does. * *---------------------------------------------------------------------- */ static int -FileHandlerEventProc( - Tcl_Event *evPtr, /* Event to service. */ - int flags) /* Flags that indicate what events to handle, - * such as TCL_FILE_EVENTS. */ +FileHandlerEventProc(evPtr, flags) + Tcl_Event *evPtr; /* Event to service. */ + int flags; /* Flags that indicate what events to + * handle, such as TCL_FILE_EVENTS. */ { int mask; FileHandler *filePtr; @@ -664,28 +658,28 @@ FileHandlerEventProc( /* * Search through the file handlers to find the one whose handle matches - * the event. We do this rather than keeping a pointer to the file handler - * directly in the event, so that the handler can be deleted while the - * event is queued without leaving a dangling pointer. + * the event. We do this rather than keeping a pointer to the file + * handler directly in the event, so that the handler can be deleted + * while the event is queued without leaving a dangling pointer. */ tsdPtr = TCL_TSD_INIT(&dataKey); for (filePtr = tsdPtr->firstFileHandlerPtr; filePtr != NULL; - filePtr = filePtr->nextPtr) { + filePtr = filePtr->nextPtr) { if (filePtr->fd != fileEvPtr->fd) { continue; } /* * The code is tricky for two reasons: - * 1. The file handler's desired events could have changed since the - * time when the event was queued, so AND the ready mask with the - * desired mask. - * 2. The file could have been closed and re-opened since the time - * when the event was queued. This is why the ready mask is stored - * in the file handler rather than the queued event: it will be - * zeroed when a new file handler is created for the newly opened - * file. + * 1. The file handler's desired events could have changed + * since the time when the event was queued, so AND the + * ready mask with the desired mask. + * 2. The file could have been closed and re-opened since + * the time when the event was queued. This is why the + * ready mask is stored in the file handler rather than + * the queued event: it will be zeroed when a new + * file handler is created for the newly opened file. */ mask = filePtr->readyMask & filePtr->mask; @@ -728,12 +722,13 @@ NotifierProc( * * Tcl_WaitForEvent -- * - * This function is called by Tcl_DoOneEvent to wait for new events on - * the message queue. If the block time is 0, then Tcl_WaitForEvent just - * polls without blocking. + * This function is called by Tcl_DoOneEvent to wait for new + * events on the message queue. If the block time is 0, then + * Tcl_WaitForEvent just polls without blocking. * * Results: - * Returns -1 if the select would block forever, otherwise returns 0. + * Returns -1 if the select would block forever, otherwise + * returns 0. * * Side effects: * Queues file events that are detected by the select. @@ -742,69 +737,56 @@ NotifierProc( */ int -Tcl_WaitForEvent( - Tcl_Time *timePtr) /* Maximum block time, or NULL. */ +Tcl_WaitForEvent(timePtr) + Tcl_Time *timePtr; /* Maximum block time, or NULL. */ { FileHandler *filePtr; FileHandlerEvent *fileEvPtr; int mask; - Tcl_Time vTime; #ifdef TCL_THREADS 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; -#endif /* TCL_THREADS */ +#endif ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); if (tclStubs.tcl_WaitForEvent != tclOriginalNotifier.waitForEventProc) { return tclStubs.tcl_WaitForEvent(timePtr); } +#ifndef TCL_THREADS /* - * 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. + * 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) { - /* - * 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; - } -#ifndef TCL_THREADS + if (timePtr) { 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. + * 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 */ } +#endif #ifdef TCL_THREADS /* @@ -814,6 +796,7 @@ Tcl_WaitForEvent( Tcl_MutexLock(¬ifierMutex); + waitForFiles = (tsdPtr->numFdBits > 0); if (timePtr != NULL && timePtr->sec == 0 && (timePtr->usec == 0 #if defined(__APPLE__) && defined(__LP64__) /* @@ -827,17 +810,16 @@ Tcl_WaitForEvent( )) { /* * 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. + * 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; } @@ -865,28 +847,27 @@ Tcl_WaitForEvent( #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. - */ - - tsdPtr->nextPtr = waitingListPtr; - if (waitingListPtr) { - waitingListPtr->prevPtr = tsdPtr; - } - tsdPtr->prevPtr = 0; - waitingListPtr = tsdPtr; + /* + * 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: unable to write to triggerPipe"); - } + + write(triggerPipe, "", 1); } - FD_ZERO(&(tsdPtr->readyMasks.readable)); - FD_ZERO(&(tsdPtr->readyMasks.writable)); - FD_ZERO(&(tsdPtr->readyMasks.exceptional)); + FD_ZERO( &(tsdPtr->readyMasks.readable) ); + FD_ZERO( &(tsdPtr->readyMasks.writable) ); + FD_ZERO( &(tsdPtr->readyMasks.exceptional) ); if (!tsdPtr->eventReady) { #ifdef __CYGWIN__ @@ -927,59 +908,60 @@ Tcl_WaitForEvent( if (waitForFiles && tsdPtr->onList) { /* * Remove the ThreadSpecificData structure of this thread from the - * waiting list. Alert the notifier thread to recompute its select + * 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; + 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"); - } + write(triggerPipe, "", 1); } + #else tsdPtr->readyMasks = tsdPtr->checkMasks; - numFound = select(tsdPtr->numFdBits, &(tsdPtr->readyMasks.readable), - &(tsdPtr->readyMasks.writable), &(tsdPtr->readyMasks.exceptional), - timeoutPtr); + 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.exceptional)); + FD_ZERO( &(tsdPtr->readyMasks.readable ) ); + FD_ZERO( &(tsdPtr->readyMasks.writable ) ); + FD_ZERO( &(tsdPtr->readyMasks.exceptional ) ); } -#endif /* TCL_THREADS */ +#endif /* * Queue all detected file events before returning. */ for (filePtr = tsdPtr->firstFileHandlerPtr; (filePtr != NULL); - filePtr = filePtr->nextPtr) { + filePtr = filePtr->nextPtr) { mask = 0; - if (FD_ISSET(filePtr->fd, &(tsdPtr->readyMasks.readable))) { + if ( FD_ISSET( filePtr->fd, &(tsdPtr->readyMasks.readable) ) ) { mask |= TCL_READABLE; } - if (FD_ISSET(filePtr->fd, &(tsdPtr->readyMasks.writable))) { + if ( FD_ISSET( filePtr->fd, &(tsdPtr->readyMasks.writable) ) ) { mask |= TCL_WRITABLE; } - if (FD_ISSET(filePtr->fd, &(tsdPtr->readyMasks.exceptional))) { + if ( FD_ISSET( filePtr->fd, &(tsdPtr->readyMasks.exceptional) ) ) { mask |= TCL_EXCEPTION; } @@ -988,12 +970,13 @@ Tcl_WaitForEvent( } /* - * Don't bother to queue an event if the mask was previously non-zero - * since an event must still be on the queue. + * Don't bother to queue an event if the mask was previously + * non-zero since an event must still be on the queue. */ if (filePtr->readyMask == 0) { - fileEvPtr = (FileHandlerEvent *) ckalloc(sizeof(FileHandlerEvent)); + fileEvPtr = (FileHandlerEvent *) ckalloc( + sizeof(FileHandlerEvent)); fileEvPtr->header.proc = FileHandlerEventProc; fileEvPtr->fd = filePtr->fd; Tcl_QueueEvent((Tcl_Event *) fileEvPtr, TCL_QUEUE_TAIL); @@ -1002,7 +985,7 @@ Tcl_WaitForEvent( } #ifdef TCL_THREADS Tcl_MutexUnlock(¬ifierMutex); -#endif /* TCL_THREADS */ +#endif return 0; } @@ -1013,56 +996,64 @@ Tcl_WaitForEvent( * NotifierThreadProc -- * * This routine is the initial (and only) function executed by the - * special notifier thread. Its job is to wait for file descriptors to - * become readable or writable or to have an exception condition and then - * to notify other threads who are interested in this information by - * signalling a condition variable. Other threads can signal this - * notifier thread of a change in their interests by writing a single - * byte to a special pipe that the notifier thread is monitoring. + * special notifier thread. Its job is to wait for file descriptors + * to become readable or writable or to have an exception condition + * and then to notify other threads who are interested in this + * information by signalling a condition variable. Other threads + * can signal this notifier thread of a change in their interests + * by writing a single byte to a special pipe that the notifier + * thread is monitoring. * * Result: - * None. Once started, this routine never exits. It dies with the overall - * process. + * None. Once started, this routine never exits. It dies with + * the overall process. * * Side effects: - * The trigger pipe used to signal the notifier thread is created when - * the notifier thread first starts. + * The trigger pipe used to signal the notifier thread is created + * when the notifier thread first starts. * *---------------------------------------------------------------------- */ static void -NotifierThreadProc( - ClientData clientData) /* Not used. */ +NotifierThreadProc(clientData) + ClientData clientData; /* Not used. */ { ThreadSpecificData *tsdPtr; fd_set readableMask; fd_set writableMask; fd_set exceptionalMask; int fds[2]; - int i, numFdBits = 0, receivePipe; + int i, status, numFdBits = 0, receivePipe; long found; struct timeval poll = {0., 0.}, *timePtr; char buf[2]; if (pipe(fds) != 0) { - Tcl_Panic("NotifierThreadProc: could not create trigger pipe"); + panic("NotifierThreadProc: could not create trigger pipe."); } receivePipe = fds[0]; - if (TclUnixSetBlockingMode(receivePipe, TCL_MODE_NONBLOCKING) < 0) { - Tcl_Panic("NotifierThreadProc: could not make receive pipe non blocking"); +#ifndef USE_FIONBIO + status = fcntl(receivePipe, F_GETFL); + status |= O_NONBLOCK; + if (fcntl(receivePipe, F_SETFL, status) < 0) { + panic("NotifierThreadProc: could not make receive pipe non blocking."); } - if (TclUnixSetBlockingMode(fds[1], TCL_MODE_NONBLOCKING) < 0) { - Tcl_Panic("NotifierThreadProc: could not make trigger pipe non blocking"); + status = fcntl(fds[1], F_GETFL); + status |= O_NONBLOCK; + if (fcntl(fds[1], F_SETFL, status) < 0) { + panic("NotifierThreadProc: could not make trigger pipe non blocking."); } - if (fcntl(receivePipe, F_SETFD, FD_CLOEXEC) < 0) { - Tcl_Panic("NotifierThreadProc: could not make receive pipe close-on-exec"); +#else + if (ioctl(receivePipe, (int) FIONBIO, &status) < 0) { + panic("NotifierThreadProc: could not make receive pipe non blocking."); } - if (fcntl(fds[1], F_SETFD, FD_CLOEXEC) < 0) { - Tcl_Panic("NotifierThreadProc: could not make trigger pipe close-on-exec"); + if (ioctl(fds[1], (int) FIONBIO, &status) < 0) { + panic("NotifierThreadProc: could not make trigger pipe non blocking."); } +#endif /* * Install the write end of the pipe into the global variable. @@ -1083,36 +1074,37 @@ NotifierThreadProc( */ while (1) { - FD_ZERO(&readableMask); - FD_ZERO(&writableMask); - FD_ZERO(&exceptionalMask); + + FD_ZERO( &readableMask ); + FD_ZERO( &writableMask ); + FD_ZERO( &exceptionalMask ); /* - * Compute the logical OR of the select masks from all the waiting - * notifiers. + * Compute the logical OR of the select masks from all the + * waiting notifiers. */ Tcl_MutexLock(¬ifierMutex); timePtr = NULL; - for (tsdPtr = waitingListPtr; tsdPtr; tsdPtr = tsdPtr->nextPtr) { - for (i = tsdPtr->numFdBits-1; i >= 0; --i) { - if (FD_ISSET(i, &(tsdPtr->checkMasks.readable))) { - FD_SET(i, &readableMask); + for (tsdPtr = waitingListPtr; tsdPtr; tsdPtr = tsdPtr->nextPtr) { + for ( i = tsdPtr->numFdBits-1; i >= 0; --i ) { + if ( FD_ISSET( i, &(tsdPtr->checkMasks.readable) ) ) { + FD_SET( i, &readableMask ); } - if (FD_ISSET(i, &(tsdPtr->checkMasks.writable))) { - FD_SET(i, &writableMask); + if ( FD_ISSET( i, &(tsdPtr->checkMasks.writable) ) ) { + FD_SET( i, &writableMask ); } - if (FD_ISSET(i, &(tsdPtr->checkMasks.exceptional))) { - FD_SET(i, &exceptionalMask); + if ( FD_ISSET( i, &(tsdPtr->checkMasks.exceptional) ) ) { + FD_SET( i, &exceptionalMask ); } } - if (tsdPtr->numFdBits > numFdBits) { + if ( tsdPtr->numFdBits > numFdBits ) { numFdBits = tsdPtr->numFdBits; } if (tsdPtr->pollState & POLL_WANT) { /* - * Here we make sure we go through select() with the same mask - * bits that were present when the thread tried to poll. + * Here we make sure we go through select() with the same + * mask bits that were present when the thread tried to poll. */ tsdPtr->pollState |= POLL_DONE; @@ -1125,54 +1117,54 @@ NotifierThreadProc( * Set up the select mask to include the receive pipe. */ - if (receivePipe >= numFdBits) { + if ( receivePipe >= numFdBits ) { numFdBits = receivePipe + 1; } - FD_SET(receivePipe, &readableMask); + FD_SET( receivePipe, &readableMask ); - if (select(numFdBits, &readableMask, &writableMask, &exceptionalMask, - timePtr) == -1) { + if ( select( numFdBits, &readableMask, &writableMask, + &exceptionalMask, timePtr) == -1 ) { /* * Try again immediately on an error. */ continue; - } + } /* * Alert any threads that are waiting on a ready file descriptor. */ Tcl_MutexLock(¬ifierMutex); - for (tsdPtr = waitingListPtr; tsdPtr; tsdPtr = tsdPtr->nextPtr) { + for (tsdPtr = waitingListPtr; tsdPtr; tsdPtr = tsdPtr->nextPtr) { found = 0; - for (i = tsdPtr->numFdBits-1; i >= 0; --i) { - if (FD_ISSET(i, &(tsdPtr->checkMasks.readable)) - && FD_ISSET(i, &readableMask)) { - FD_SET(i, &(tsdPtr->readyMasks.readable)); + for ( i = tsdPtr->numFdBits-1; i >= 0; --i ) { + if ( FD_ISSET( i, &(tsdPtr->checkMasks.readable) ) + && FD_ISSET( i, &readableMask ) ) { + FD_SET( i, &(tsdPtr->readyMasks.readable) ); found = 1; } - if (FD_ISSET(i, &(tsdPtr->checkMasks.writable)) - && FD_ISSET(i, &writableMask)) { - FD_SET(i, &(tsdPtr->readyMasks.writable)); + if ( FD_ISSET( i, &(tsdPtr->checkMasks.writable) ) + && FD_ISSET( i, &writableMask ) ) { + FD_SET( i, &(tsdPtr->readyMasks.writable) ); found = 1; } - if (FD_ISSET(i, &(tsdPtr->checkMasks.exceptional)) - && FD_ISSET(i, &exceptionalMask)) { - FD_SET(i, &(tsdPtr->readyMasks.exceptional)); + if ( FD_ISSET( i, &(tsdPtr->checkMasks.exceptional) ) + && FD_ISSET( i, &exceptionalMask ) ) { + FD_SET( i, &(tsdPtr->readyMasks.exceptional) ); found = 1; } } - if (found || (tsdPtr->pollState & POLL_DONE)) { - tsdPtr->eventReady = 1; + if (found || (tsdPtr->pollState & POLL_DONE)) { + tsdPtr->eventReady = 1; if (tsdPtr->onList) { /* - * Remove the ThreadSpecificData structure of this thread - * from the waiting list. This prevents us from - * continuously spining on select until the other threads - * runs and services the file event. + * Remove the ThreadSpecificData structure of this + * thread from the waiting list. This prevents us from + * continuously spining on select until the other + * threads runs and services the file event. */ if (tsdPtr->prevPtr) { @@ -1190,26 +1182,26 @@ NotifierThreadProc( #ifdef __CYGWIN__ PostMessageW(tsdPtr->hwnd, 1024, 0, 0); #else /* __CYGWIN__ */ - Tcl_ConditionNotify(&tsdPtr->waitCV); + Tcl_ConditionNotify(&tsdPtr->waitCV); #endif /* __CYGWIN__ */ - } - } + } + } Tcl_MutexUnlock(¬ifierMutex); /* * Consume the next byte from the notifier pipe if the pipe was - * readable. Note that there may be multiple bytes pending, but to - * avoid a race condition we only read one at a time. + * readable. Note that there may be multiple bytes pending, but + * to avoid a race condition we only read one at a time. */ - if (FD_ISSET(receivePipe, &readableMask)) { + if ( FD_ISSET( receivePipe, &readableMask ) ) { i = read(receivePipe, buf, 1); if ((i == 0) || ((i == 1) && (buf[0] == 'q'))) { /* - * Someone closed the write end of the pipe or sent us a Quit - * message [Bug: 4139] and then closed the write end of the - * pipe so we need to shut down the notifier thread. + * Someone closed the write end of the pipe or sent us a + * Quit message [Bug: 4139] and then closed the write end + * of the pipe so we need to shut down the notifier thread. */ break; @@ -1230,14 +1222,6 @@ NotifierThreadProc( TclpThreadExit (0); } -#endif /* TCL_THREADS */ +#endif #endif /* HAVE_COREFOUNDATION */ - -/* - * Local Variables: - * mode: c - * c-basic-offset: 4 - * fill-column: 78 - * End: - */ |
