4 * This file contains the implementation of the select-based
5 * Unix-specific notifier, which is the lowest-level part of the
6 * Tcl event loop. This file works together with
7 * ../generic/tclNotify.c.
9 * Copyright (c) 1995-1997 Sun Microsystems, Inc.
11 * See the file "license.terms" for information on usage and redistribution
12 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
21 extern TclStubs tclStubs;
24 * This structure is used to keep track of the notifier info for a
28 typedef struct FileHandler {
30 int mask; /* Mask of desired events: TCL_READABLE,
32 int readyMask; /* Mask of events that have been seen since the
33 * last time file handlers were invoked for
35 Tcl_FileProc *proc; /* Procedure to call, in the style of
36 * Tcl_CreateFileHandler. */
37 ClientData clientData; /* Argument to pass to proc. */
38 struct FileHandler *nextPtr;/* Next in list of all files we care about. */
42 * The following structure is what is added to the Tcl event queue when
43 * file handlers are ready to fire.
46 typedef struct FileHandlerEvent {
47 Tcl_Event header; /* Information that is standard for
49 int fd; /* File descriptor that is ready. Used
50 * to find the FileHandler structure for
51 * the file (can't point directly to the
52 * FileHandler structure because it could
53 * go away while the event is queued). */
57 * The following static structure contains the state information for the
58 * select based implementation of the Tcl notifier. One of these structures
59 * is created for each thread that is using the notifier.
62 typedef struct ThreadSpecificData {
63 FileHandler *firstFileHandlerPtr;
64 /* Pointer to head of file handler list. */
65 fd_mask checkMasks[3*MASK_SIZE];
66 /* This array is used to build up the masks
67 * to be used in the next call to select.
68 * Bits are set in response to calls to
69 * Tcl_CreateFileHandler. */
70 fd_mask readyMasks[3*MASK_SIZE];
71 /* This array reflects the readable/writable
72 * conditions that were found to exist by the
73 * last call to select. */
74 int numFdBits; /* Number of valid bits in checkMasks
75 * (one more than highest fd for which
76 * Tcl_WatchFile has been called). */
78 int onList; /* True if it is in this list */
79 unsigned int pollState; /* pollState is used to implement a polling
80 * handshake between each thread and the
81 * notifier thread. Bits defined below. */
82 struct ThreadSpecificData *nextPtr, *prevPtr;
83 /* All threads that are currently waiting on
84 * an event have their ThreadSpecificData
85 * structure on a doubly-linked listed formed
86 * from these pointers. You must hold the
87 * notifierMutex lock before accessing these
89 Tcl_Condition waitCV; /* Any other thread alerts a notifier
90 * that an event is ready to be processed
91 * by signaling this condition variable. */
92 int eventReady; /* True if an event is ready to be processed.
93 * Used as condition flag together with
98 static Tcl_ThreadDataKey dataKey;
102 * The following static indicates the number of threads that have
103 * initialized notifiers.
105 * You must hold the notifierMutex lock before accessing this variable.
108 static int notifierCount = 0;
111 * The following variable points to the head of a doubly-linked list of
112 * of ThreadSpecificData structures for all threads that are currently
113 * waiting on an event.
115 * You must hold the notifierMutex lock before accessing this list.
118 static ThreadSpecificData *waitingListPtr = NULL;
121 * The notifier thread spends all its time in select() waiting for a
122 * file descriptor associated with one of the threads on the waitingListPtr
123 * list to do something interesting. But if the contents of the
124 * waitingListPtr list ever changes, we need to wake up and restart
125 * the select() system call. You can wake up the notifier thread by
126 * writing a single byte to the file descriptor defined below. This
127 * file descriptor is the input-end of a pipe and the notifier thread is
128 * listening for data on the output-end of the same pipe. Hence writing
129 * to this file descriptor will cause the select() system call to return
130 * and wake up the notifier thread.
132 * You must hold the notifierMutex lock before accessing this list.
135 static int triggerPipe = -1;
138 * The notifierMutex locks access to all of the global notifier state.
141 TCL_DECLARE_MUTEX(notifierMutex)
144 * The notifier thread signals the notifierCV when it has finished
145 * initializing the triggerPipe and right before the notifier
149 static Tcl_Condition notifierCV;
153 * POLL_WANT is set by each thread before it waits on its condition
154 * variable. It is checked by the notifier before it does
156 * POLL_DONE is set by the notifier if it goes into select after
157 * seeing POLL_WANT. The idea is to ensure it tries a select
158 * with the same bits the initial thread had set.
160 #define POLL_WANT 0x1
161 #define POLL_DONE 0x2
164 * This is the thread ID of the notifier thread that does select.
166 static Tcl_ThreadId notifierThread;
171 * Static routines defined in this file.
175 static void NotifierThreadProc _ANSI_ARGS_((ClientData clientData));
177 static int FileHandlerEventProc _ANSI_ARGS_((Tcl_Event *evPtr,
181 *----------------------------------------------------------------------
183 * Tcl_InitNotifier --
185 * Initializes the platform specific notifier state.
188 * Returns a handle to the notifier state for this thread..
193 *----------------------------------------------------------------------
199 ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
202 tsdPtr->eventReady = 0;
205 * Start the Notifier thread if necessary.
208 Tcl_MutexLock(¬ifierMutex);
209 if (notifierCount == 0) {
210 if (Tcl_CreateThread(¬ifierThread, NotifierThreadProc, NULL,
211 TCL_THREAD_STACK_DEFAULT, TCL_THREAD_NOFLAGS) != TCL_OK) {
212 panic("Tcl_InitNotifier: unable to start notifier thread");
218 * Wait for the notifier pipe to be created.
221 while (triggerPipe < 0) {
222 Tcl_ConditionWait(¬ifierCV, ¬ifierMutex, NULL);
225 Tcl_MutexUnlock(¬ifierMutex);
227 return (ClientData) tsdPtr;
231 *----------------------------------------------------------------------
233 * Tcl_FinalizeNotifier --
235 * This function is called to cleanup the notifier state before
236 * a thread is terminated.
242 * May terminate the background notifier thread if this is the
243 * last notifier instance.
245 *----------------------------------------------------------------------
249 Tcl_FinalizeNotifier(clientData)
250 ClientData clientData; /* Not used. */
253 ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
255 Tcl_MutexLock(¬ifierMutex);
259 * If this is the last thread to use the notifier, close the notifier
260 * pipe and wait for the background thread to terminate.
263 if (notifierCount == 0) {
264 if (triggerPipe < 0) {
265 panic("Tcl_FinalizeNotifier: notifier pipe not initialized");
269 * Send "q" message to the notifier thread so that it will
270 * terminate. The notifier will return from its call to select()
271 * and notice that a "q" message has arrived, it will then close
272 * its side of the pipe and terminate its thread. Note the we can
273 * not just close the pipe and check for EOF in the notifier
274 * thread because if a background child process was created with
275 * exec, select() would not register the EOF on the pipe until the
276 * child processes had terminated. [Bug: 4139]
278 write(triggerPipe, "q", 1);
281 Tcl_ConditionWait(¬ifierCV, ¬ifierMutex, NULL);
285 * Clean up any synchronization objects in the thread local storage.
288 Tcl_ConditionFinalize(&(tsdPtr->waitCV));
290 Tcl_MutexUnlock(¬ifierMutex);
295 *----------------------------------------------------------------------
297 * Tcl_AlertNotifier --
299 * Wake up the specified notifier from any thread. This routine
300 * is called by the platform independent notifier code whenever
301 * the Tcl_ThreadAlert routine is called. This routine is
302 * guaranteed not to be called on a given notifier after
303 * Tcl_FinalizeNotifier is called for that notifier.
309 * Signals the notifier condition variable for the specified
312 *----------------------------------------------------------------------
316 Tcl_AlertNotifier(clientData)
317 ClientData clientData;
320 ThreadSpecificData *tsdPtr = (ThreadSpecificData *) clientData;
321 Tcl_MutexLock(¬ifierMutex);
322 tsdPtr->eventReady = 1;
323 Tcl_ConditionNotify(&tsdPtr->waitCV);
324 Tcl_MutexUnlock(¬ifierMutex);
329 *----------------------------------------------------------------------
333 * This procedure sets the current notifier timer value. This
334 * interface is not implemented in this notifier because we are
335 * always running inside of Tcl_DoOneEvent.
343 *----------------------------------------------------------------------
347 Tcl_SetTimer(timePtr)
348 Tcl_Time *timePtr; /* Timeout value, may be NULL. */
351 * The interval timer doesn't do anything in this implementation,
352 * because the only event loop is via Tcl_DoOneEvent, which passes
353 * timeout values to Tcl_WaitForEvent.
356 if (tclStubs.tcl_SetTimer != Tcl_SetTimer) {
357 tclStubs.tcl_SetTimer(timePtr);
362 *----------------------------------------------------------------------
364 * Tcl_ServiceModeHook --
366 * This function is invoked whenever the service mode changes.
374 *----------------------------------------------------------------------
378 Tcl_ServiceModeHook(mode)
379 int mode; /* Either TCL_SERVICE_ALL, or
380 * TCL_SERVICE_NONE. */
385 *----------------------------------------------------------------------
387 * Tcl_CreateFileHandler --
389 * This procedure registers a file handler with the select notifier.
395 * Creates a new file handler structure.
397 *----------------------------------------------------------------------
401 Tcl_CreateFileHandler(fd, mask, proc, clientData)
402 int fd; /* Handle of stream to watch. */
403 int mask; /* OR'ed combination of TCL_READABLE,
404 * TCL_WRITABLE, and TCL_EXCEPTION:
405 * indicates conditions under which
406 * proc should be called. */
407 Tcl_FileProc *proc; /* Procedure to call for each
409 ClientData clientData; /* Arbitrary data to pass to proc. */
411 ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
412 FileHandler *filePtr;
415 if (tclStubs.tcl_CreateFileHandler != Tcl_CreateFileHandler) {
416 tclStubs.tcl_CreateFileHandler(fd, mask, proc, clientData);
420 for (filePtr = tsdPtr->firstFileHandlerPtr; filePtr != NULL;
421 filePtr = filePtr->nextPtr) {
422 if (filePtr->fd == fd) {
426 if (filePtr == NULL) {
427 filePtr = (FileHandler*) ckalloc(sizeof(FileHandler));
429 filePtr->readyMask = 0;
430 filePtr->nextPtr = tsdPtr->firstFileHandlerPtr;
431 tsdPtr->firstFileHandlerPtr = filePtr;
433 filePtr->proc = proc;
434 filePtr->clientData = clientData;
435 filePtr->mask = mask;
438 * Update the check masks for this file.
441 index = fd/(NBBY*sizeof(fd_mask));
442 bit = 1 << (fd%(NBBY*sizeof(fd_mask)));
443 if (mask & TCL_READABLE) {
444 tsdPtr->checkMasks[index] |= bit;
446 tsdPtr->checkMasks[index] &= ~bit;
448 if (mask & TCL_WRITABLE) {
449 (tsdPtr->checkMasks+MASK_SIZE)[index] |= bit;
451 (tsdPtr->checkMasks+MASK_SIZE)[index] &= ~bit;
453 if (mask & TCL_EXCEPTION) {
454 (tsdPtr->checkMasks+2*(MASK_SIZE))[index] |= bit;
456 (tsdPtr->checkMasks+2*(MASK_SIZE))[index] &= ~bit;
458 if (tsdPtr->numFdBits <= fd) {
459 tsdPtr->numFdBits = fd+1;
464 *----------------------------------------------------------------------
466 * Tcl_DeleteFileHandler --
468 * Cancel a previously-arranged callback arrangement for
475 * If a callback was previously registered on file, remove it.
477 *----------------------------------------------------------------------
481 Tcl_DeleteFileHandler(fd)
482 int fd; /* Stream id for which to remove callback procedure. */
484 FileHandler *filePtr, *prevPtr;
487 ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
489 if (tclStubs.tcl_DeleteFileHandler != Tcl_DeleteFileHandler) {
490 tclStubs.tcl_DeleteFileHandler(fd);
495 * Find the entry for the given file (and return if there isn't one).
498 for (prevPtr = NULL, filePtr = tsdPtr->firstFileHandlerPtr; ;
499 prevPtr = filePtr, filePtr = filePtr->nextPtr) {
500 if (filePtr == NULL) {
503 if (filePtr->fd == fd) {
509 * Update the check masks for this file.
512 index = fd/(NBBY*sizeof(fd_mask));
513 bit = 1 << (fd%(NBBY*sizeof(fd_mask)));
515 if (filePtr->mask & TCL_READABLE) {
516 tsdPtr->checkMasks[index] &= ~bit;
518 if (filePtr->mask & TCL_WRITABLE) {
519 (tsdPtr->checkMasks+MASK_SIZE)[index] &= ~bit;
521 if (filePtr->mask & TCL_EXCEPTION) {
522 (tsdPtr->checkMasks+2*(MASK_SIZE))[index] &= ~bit;
526 * Find current max fd.
529 if (fd+1 == tsdPtr->numFdBits) {
530 for (tsdPtr->numFdBits = 0; index >= 0; index--) {
531 flags = tsdPtr->checkMasks[index]
532 | (tsdPtr->checkMasks+MASK_SIZE)[index]
533 | (tsdPtr->checkMasks+2*(MASK_SIZE))[index];
535 for (i = (NBBY*sizeof(fd_mask)); i > 0; i--) {
536 if (flags & (((unsigned long)1) << (i-1))) {
540 tsdPtr->numFdBits = index * (NBBY*sizeof(fd_mask)) + i;
547 * Clean up information in the callback record.
550 if (prevPtr == NULL) {
551 tsdPtr->firstFileHandlerPtr = filePtr->nextPtr;
553 prevPtr->nextPtr = filePtr->nextPtr;
555 ckfree((char *) filePtr);
559 *----------------------------------------------------------------------
561 * FileHandlerEventProc --
563 * This procedure is called by Tcl_ServiceEvent when a file event
564 * reaches the front of the event queue. This procedure is
565 * responsible for actually handling the event by invoking the
566 * callback for the file handler.
569 * Returns 1 if the event was handled, meaning it should be removed
570 * from the queue. Returns 0 if the event was not handled, meaning
571 * it should stay on the queue. The only time the event isn't
572 * handled is if the TCL_FILE_EVENTS flag bit isn't set.
575 * Whatever the file handler's callback procedure does.
577 *----------------------------------------------------------------------
581 FileHandlerEventProc(evPtr, flags)
582 Tcl_Event *evPtr; /* Event to service. */
583 int flags; /* Flags that indicate what events to
584 * handle, such as TCL_FILE_EVENTS. */
587 FileHandler *filePtr;
588 FileHandlerEvent *fileEvPtr = (FileHandlerEvent *) evPtr;
589 ThreadSpecificData *tsdPtr;
591 if (!(flags & TCL_FILE_EVENTS)) {
596 * Search through the file handlers to find the one whose handle matches
597 * the event. We do this rather than keeping a pointer to the file
598 * handler directly in the event, so that the handler can be deleted
599 * while the event is queued without leaving a dangling pointer.
602 tsdPtr = TCL_TSD_INIT(&dataKey);
603 for (filePtr = tsdPtr->firstFileHandlerPtr; filePtr != NULL;
604 filePtr = filePtr->nextPtr) {
605 if (filePtr->fd != fileEvPtr->fd) {
610 * The code is tricky for two reasons:
611 * 1. The file handler's desired events could have changed
612 * since the time when the event was queued, so AND the
613 * ready mask with the desired mask.
614 * 2. The file could have been closed and re-opened since
615 * the time when the event was queued. This is why the
616 * ready mask is stored in the file handler rather than
617 * the queued event: it will be zeroed when a new
618 * file handler is created for the newly opened file.
621 mask = filePtr->readyMask & filePtr->mask;
622 filePtr->readyMask = 0;
624 (*filePtr->proc)(filePtr->clientData, mask);
632 *----------------------------------------------------------------------
634 * Tcl_WaitForEvent --
636 * This function is called by Tcl_DoOneEvent to wait for new
637 * events on the message queue. If the block time is 0, then
638 * Tcl_WaitForEvent just polls without blocking.
641 * Returns -1 if the select would block forever, otherwise
645 * Queues file events that are detected by the select.
647 *----------------------------------------------------------------------
651 Tcl_WaitForEvent(timePtr)
652 Tcl_Time *timePtr; /* Maximum block time, or NULL. */
654 FileHandler *filePtr;
655 FileHandlerEvent *fileEvPtr;
656 struct timeval timeout, *timeoutPtr;
657 int bit, index, mask;
663 ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
665 if (tclStubs.tcl_WaitForEvent != Tcl_WaitForEvent) {
666 return tclStubs.tcl_WaitForEvent(timePtr);
670 * Set up the timeout structure. Note that if there are no events to
671 * check for, we return with a negative result rather than blocking
676 timeout.tv_sec = timePtr->sec;
677 timeout.tv_usec = timePtr->usec;
678 timeoutPtr = &timeout;
680 } else if (tsdPtr->numFdBits == 0) {
682 * If there are no threads, no timeout, and no fds registered,
683 * then there are no events possible and we must avoid deadlock.
684 * Note that this is not entirely correct because there might
685 * be a signal that could interrupt the select call, but we
686 * don't handle that case if we aren't using threads.
697 * Place this thread on the list of interested threads, signal the
698 * notifier thread, and wait for a response or a timeout.
701 Tcl_MutexLock(¬ifierMutex);
703 waitForFiles = (tsdPtr->numFdBits > 0);
704 if (timePtr != NULL && timePtr->sec == 0 && timePtr->usec == 0) {
706 * Cannot emulate a polling select with a polling condition variable.
707 * Instead, pretend to wait for files and tell the notifier
708 * thread what we are doing. The notifier thread makes sure
709 * it goes through select with its select mask in the same state
710 * as ours currently is. We block until that happens.
714 tsdPtr->pollState = POLL_WANT;
717 tsdPtr->pollState = 0;
722 * Add the ThreadSpecificData structure of this thread to the list
723 * of ThreadSpecificData structures of all threads that are waiting
728 tsdPtr->nextPtr = waitingListPtr;
729 if (waitingListPtr) {
730 waitingListPtr->prevPtr = tsdPtr;
733 waitingListPtr = tsdPtr;
736 write(triggerPipe, "", 1);
739 memset((VOID *) tsdPtr->readyMasks, 0, 3*MASK_SIZE*sizeof(fd_mask));
741 if (!tsdPtr->eventReady) {
742 Tcl_ConditionWait(&tsdPtr->waitCV, ¬ifierMutex, timePtr);
744 tsdPtr->eventReady = 0;
746 if (waitForFiles && tsdPtr->onList) {
748 * Remove the ThreadSpecificData structure of this thread from the
749 * waiting list. Alert the notifier thread to recompute its select
750 * masks - skipping this caused a hang when trying to close a pipe
751 * which the notifier thread was still doing a select on.
754 if (tsdPtr->prevPtr) {
755 tsdPtr->prevPtr->nextPtr = tsdPtr->nextPtr;
757 waitingListPtr = tsdPtr->nextPtr;
759 if (tsdPtr->nextPtr) {
760 tsdPtr->nextPtr->prevPtr = tsdPtr->prevPtr;
762 tsdPtr->nextPtr = tsdPtr->prevPtr = NULL;
764 write(triggerPipe, "", 1);
769 memcpy((VOID *) tsdPtr->readyMasks, (VOID *) tsdPtr->checkMasks,
770 3*MASK_SIZE*sizeof(fd_mask));
771 numFound = select(tsdPtr->numFdBits,
772 (SELECT_MASK *) &tsdPtr->readyMasks[0],
773 (SELECT_MASK *) &tsdPtr->readyMasks[MASK_SIZE],
774 (SELECT_MASK *) &tsdPtr->readyMasks[2*MASK_SIZE], timeoutPtr);
777 * Some systems don't clear the masks after an error, so
778 * we have to do it here.
781 if (numFound == -1) {
782 memset((VOID *) tsdPtr->readyMasks, 0, 3*MASK_SIZE*sizeof(fd_mask));
787 * Queue all detected file events before returning.
790 for (filePtr = tsdPtr->firstFileHandlerPtr; (filePtr != NULL);
791 filePtr = filePtr->nextPtr) {
792 index = filePtr->fd / (NBBY*sizeof(fd_mask));
793 bit = 1 << (filePtr->fd % (NBBY*sizeof(fd_mask)));
796 if (tsdPtr->readyMasks[index] & bit) {
797 mask |= TCL_READABLE;
799 if ((tsdPtr->readyMasks+MASK_SIZE)[index] & bit) {
800 mask |= TCL_WRITABLE;
802 if ((tsdPtr->readyMasks+2*(MASK_SIZE))[index] & bit) {
803 mask |= TCL_EXCEPTION;
811 * Don't bother to queue an event if the mask was previously
812 * non-zero since an event must still be on the queue.
815 if (filePtr->readyMask == 0) {
816 fileEvPtr = (FileHandlerEvent *) ckalloc(
817 sizeof(FileHandlerEvent));
818 fileEvPtr->header.proc = FileHandlerEventProc;
819 fileEvPtr->fd = filePtr->fd;
820 Tcl_QueueEvent((Tcl_Event *) fileEvPtr, TCL_QUEUE_TAIL);
822 filePtr->readyMask = mask;
825 Tcl_MutexUnlock(¬ifierMutex);
832 *----------------------------------------------------------------------
834 * NotifierThreadProc --
836 * This routine is the initial (and only) function executed by the
837 * special notifier thread. Its job is to wait for file descriptors
838 * to become readable or writable or to have an exception condition
839 * and then to notify other threads who are interested in this
840 * information by signalling a condition variable. Other threads
841 * can signal this notifier thread of a change in their interests
842 * by writing a single byte to a special pipe that the notifier
843 * thread is monitoring.
846 * None. Once started, this routine never exits. It dies with
847 * the overall process.
850 * The trigger pipe used to signal the notifier thread is created
851 * when the notifier thread first starts.
853 *----------------------------------------------------------------------
857 NotifierThreadProc(clientData)
858 ClientData clientData; /* Not used. */
860 ThreadSpecificData *tsdPtr;
861 fd_mask masks[3*MASK_SIZE];
862 long *maskPtr = (long *)masks; /* masks[] cast to type long[] */
864 int i, status, index, bit, numFdBits, found, receivePipe, word;
865 struct timeval poll = {0., 0.}, *timePtr;
866 int maskSize = 3 * ((MASK_SIZE) / sizeof(long)) * sizeof(fd_mask);
869 if (pipe(fds) != 0) {
870 panic("NotifierThreadProc: could not create trigger pipe.");
873 receivePipe = fds[0];
876 status = fcntl(receivePipe, F_GETFL);
877 status |= O_NONBLOCK;
878 if (fcntl(receivePipe, F_SETFL, status) < 0) {
879 panic("NotifierThreadProc: could not make receive pipe non blocking.");
881 status = fcntl(fds[1], F_GETFL);
882 status |= O_NONBLOCK;
883 if (fcntl(fds[1], F_SETFL, status) < 0) {
884 panic("NotifierThreadProc: could not make trigger pipe non blocking.");
887 if (ioctl(receivePipe, (int) FIONBIO, &status) < 0) {
888 panic("NotifierThreadProc: could not make receive pipe non blocking.");
890 if (ioctl(fds[1], (int) FIONBIO, &status) < 0) {
891 panic("NotifierThreadProc: could not make trigger pipe non blocking.");
896 * Install the write end of the pipe into the global variable.
899 Tcl_MutexLock(¬ifierMutex);
900 triggerPipe = fds[1];
903 * Signal any threads that are waiting.
906 Tcl_ConditionNotify(¬ifierCV);
907 Tcl_MutexUnlock(¬ifierMutex);
910 * Look for file events and report them to interested threads.
915 * Set up the select mask to include the receive pipe.
918 memset((VOID *)masks, 0, 3*MASK_SIZE*sizeof(fd_mask));
919 numFdBits = receivePipe + 1;
920 index = receivePipe / (NBBY*sizeof(fd_mask));
921 bit = 1 << (receivePipe % (NBBY*sizeof(fd_mask)));
925 * Add in the check masks from all of the waiting notifiers.
928 Tcl_MutexLock(¬ifierMutex);
930 for (tsdPtr = waitingListPtr; tsdPtr; tsdPtr = tsdPtr->nextPtr) {
931 for (i = 0; i < maskSize; i++) {
932 maskPtr[i] |= ((long*)tsdPtr->checkMasks)[i];
934 if (tsdPtr->numFdBits > numFdBits) {
935 numFdBits = tsdPtr->numFdBits;
937 if (tsdPtr->pollState & POLL_WANT) {
939 * Here we make sure we go through select() with the same
940 * mask bits that were present when the thread tried to poll.
943 tsdPtr->pollState |= POLL_DONE;
947 Tcl_MutexUnlock(¬ifierMutex);
949 maskSize = 3 * ((MASK_SIZE) / sizeof(long)) * sizeof(fd_mask);
951 if (select(numFdBits, (SELECT_MASK *) &masks[0],
952 (SELECT_MASK *) &masks[MASK_SIZE],
953 (SELECT_MASK *) &masks[2*MASK_SIZE], timePtr) == -1) {
955 * Try again immediately on an error.
962 * Alert any threads that are waiting on a ready file descriptor.
965 Tcl_MutexLock(¬ifierMutex);
966 for (tsdPtr = waitingListPtr; tsdPtr; tsdPtr = tsdPtr->nextPtr) {
969 for (i = 0; i < maskSize; i++) {
970 word = maskPtr[i] & ((long*)tsdPtr->checkMasks)[i];
972 (((long*)(tsdPtr->readyMasks))[i]) = word;
974 if (found || (tsdPtr->pollState & POLL_DONE)) {
975 tsdPtr->eventReady = 1;
976 if (tsdPtr->onList) {
978 * Remove the ThreadSpecificData structure of this
979 * thread from the waiting list. This prevents us from
980 * continuously spining on select until the other
981 * threads runs and services the file event.
984 if (tsdPtr->prevPtr) {
985 tsdPtr->prevPtr->nextPtr = tsdPtr->nextPtr;
987 waitingListPtr = tsdPtr->nextPtr;
989 if (tsdPtr->nextPtr) {
990 tsdPtr->nextPtr->prevPtr = tsdPtr->prevPtr;
992 tsdPtr->nextPtr = tsdPtr->prevPtr = NULL;
994 tsdPtr->pollState = 0;
996 Tcl_ConditionNotify(&tsdPtr->waitCV);
999 Tcl_MutexUnlock(¬ifierMutex);
1002 * Consume the next byte from the notifier pipe if the pipe was
1003 * readable. Note that there may be multiple bytes pending, but
1004 * to avoid a race condition we only read one at a time.
1007 if (masks[index] & bit) {
1008 i = read(receivePipe, buf, 1);
1010 if ((i == 0) || ((i == 1) && (buf[0] == 'q'))) {
1012 * Someone closed the write end of the pipe or sent us a
1013 * Quit message [Bug: 4139] and then closed the write end
1014 * of the pipe so we need to shut down the notifier thread.
1023 * Clean up the read end of the pipe and signal any threads waiting on
1024 * termination of the notifier thread.
1028 Tcl_MutexLock(¬ifierMutex);
1030 Tcl_ConditionNotify(¬ifierCV);
1031 Tcl_MutexUnlock(¬ifierMutex);