1/* 2 * tclUnixNotify.c -- 3 * 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. 8 * 9 * Copyright (c) 1995-1997 Sun Microsystems, Inc. 10 * 11 * See the file "license.terms" for information on usage and redistribution 12 * of this file, and for a DISCLAIMER OF ALL WARRANTIES. 13 * 14 * RCS: @(#) $Id: tclUnixNotfy.c,v 1.11.2.16 2006/08/22 17:45:02 andreas_kupries Exp $ 15 */ 16 17#include "tclInt.h" 18#include "tclPort.h" 19#ifndef HAVE_COREFOUNDATION /* Darwin/Mac OS X CoreFoundation notifier 20 * is in tclMacOSXNotify.c */ 21#include <signal.h> 22 23extern TclStubs tclStubs; 24extern Tcl_NotifierProcs tclOriginalNotifier; 25 26/* 27 * This structure is used to keep track of the notifier info for a 28 * a registered file. 29 */ 30 31typedef struct FileHandler { 32 int fd; 33 int mask; /* Mask of desired events: TCL_READABLE, 34 * etc. */ 35 int readyMask; /* Mask of events that have been seen since the 36 * last time file handlers were invoked for 37 * this file. */ 38 Tcl_FileProc *proc; /* Procedure to call, in the style of 39 * Tcl_CreateFileHandler. */ 40 ClientData clientData; /* Argument to pass to proc. */ 41 struct FileHandler *nextPtr;/* Next in list of all files we care about. */ 42} FileHandler; 43 44/* 45 * The following structure is what is added to the Tcl event queue when 46 * file handlers are ready to fire. 47 */ 48 49typedef struct FileHandlerEvent { 50 Tcl_Event header; /* Information that is standard for 51 * all events. */ 52 int fd; /* File descriptor that is ready. Used 53 * to find the FileHandler structure for 54 * the file (can't point directly to the 55 * FileHandler structure because it could 56 * go away while the event is queued). */ 57} FileHandlerEvent; 58 59/* 60 * 61 * The following structure contains a set of select() masks to track 62 * readable, writable, and exceptional conditions. 63 */ 64 65typedef struct SelectMasks { 66 fd_set readable; 67 fd_set writable; 68 fd_set exceptional; 69} SelectMasks; 70 71/* 72 * The following static structure contains the state information for the 73 * select based implementation of the Tcl notifier. One of these structures 74 * is created for each thread that is using the notifier. 75 */ 76 77typedef struct ThreadSpecificData { 78 FileHandler *firstFileHandlerPtr; 79 /* Pointer to head of file handler list. */ 80 81 SelectMasks checkMasks; /* This structure is used to build up the masks 82 * to be used in the next call to select. 83 * Bits are set in response to calls to 84 * Tcl_CreateFileHandler. */ 85 SelectMasks readyMasks; /* This array reflects the readable/writable 86 * conditions that were found to exist by the 87 * last call to select. */ 88 int numFdBits; /* Number of valid bits in checkMasks 89 * (one more than highest fd for which 90 * Tcl_WatchFile has been called). */ 91#ifdef TCL_THREADS 92 int onList; /* True if it is in this list */ 93 unsigned int pollState; /* pollState is used to implement a polling 94 * handshake between each thread and the 95 * notifier thread. Bits defined below. */ 96 struct ThreadSpecificData *nextPtr, *prevPtr; 97 /* All threads that are currently waiting on 98 * an event have their ThreadSpecificData 99 * structure on a doubly-linked listed formed 100 * from these pointers. You must hold the 101 * notifierMutex lock before accessing these 102 * fields. */ 103 Tcl_Condition waitCV; /* Any other thread alerts a notifier 104 * that an event is ready to be processed 105 * by signaling this condition variable. */ 106 int eventReady; /* True if an event is ready to be processed. 107 * Used as condition flag together with 108 * waitCV above. */ 109#endif 110} ThreadSpecificData; 111 112static Tcl_ThreadDataKey dataKey; 113 114#ifdef TCL_THREADS 115/* 116 * The following static indicates the number of threads that have 117 * initialized notifiers. 118 * 119 * You must hold the notifierMutex lock before accessing this variable. 120 */ 121 122static int notifierCount = 0; 123 124/* 125 * The following variable points to the head of a doubly-linked list of 126 * of ThreadSpecificData structures for all threads that are currently 127 * waiting on an event. 128 * 129 * You must hold the notifierMutex lock before accessing this list. 130 */ 131 132static ThreadSpecificData *waitingListPtr = NULL; 133 134/* 135 * The notifier thread spends all its time in select() waiting for a 136 * file descriptor associated with one of the threads on the waitingListPtr 137 * list to do something interesting. But if the contents of the 138 * waitingListPtr list ever changes, we need to wake up and restart 139 * the select() system call. You can wake up the notifier thread by 140 * writing a single byte to the file descriptor defined below. This 141 * file descriptor is the input-end of a pipe and the notifier thread is 142 * listening for data on the output-end of the same pipe. Hence writing 143 * to this file descriptor will cause the select() system call to return 144 * and wake up the notifier thread. 145 * 146 * You must hold the notifierMutex lock before accessing this list. 147 */ 148 149static int triggerPipe = -1; 150 151/* 152 * The notifierMutex locks access to all of the global notifier state. 153 */ 154 155TCL_DECLARE_MUTEX(notifierMutex) 156 157/* 158 * The notifier thread signals the notifierCV when it has finished 159 * initializing the triggerPipe and right before the notifier 160 * thread terminates. 161 */ 162 163static Tcl_Condition notifierCV; 164 165/* 166 * The pollState bits 167 * POLL_WANT is set by each thread before it waits on its condition 168 * variable. It is checked by the notifier before it does 169 * select. 170 * POLL_DONE is set by the notifier if it goes into select after 171 * seeing POLL_WANT. The idea is to ensure it tries a select 172 * with the same bits the initial thread had set. 173 */ 174#define POLL_WANT 0x1 175#define POLL_DONE 0x2 176 177/* 178 * This is the thread ID of the notifier thread that does select. 179 */ 180static Tcl_ThreadId notifierThread; 181 182#endif 183 184/* 185 * Static routines defined in this file. 186 */ 187 188#ifdef TCL_THREADS 189static void NotifierThreadProc _ANSI_ARGS_((ClientData clientData)); 190#endif 191static int FileHandlerEventProc _ANSI_ARGS_((Tcl_Event *evPtr, 192 int flags)); 193 194/* 195 *---------------------------------------------------------------------- 196 * 197 * Tcl_InitNotifier -- 198 * 199 * Initializes the platform specific notifier state. 200 * 201 * Results: 202 * Returns a handle to the notifier state for this thread.. 203 * 204 * Side effects: 205 * None. 206 * 207 *---------------------------------------------------------------------- 208 */ 209 210ClientData 211Tcl_InitNotifier() 212{ 213 ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); 214 215#ifdef TCL_THREADS 216 tsdPtr->eventReady = 0; 217 218 /* 219 * Start the Notifier thread if necessary. 220 */ 221 222 Tcl_MutexLock(¬ifierMutex); 223 if (notifierCount == 0) { 224 if (TclpThreadCreate(¬ifierThread, NotifierThreadProc, NULL, 225 TCL_THREAD_STACK_DEFAULT, TCL_THREAD_JOINABLE) != TCL_OK) { 226 panic("Tcl_InitNotifier: unable to start notifier thread"); 227 } 228 } 229 notifierCount++; 230 231 /* 232 * Wait for the notifier pipe to be created. 233 */ 234 235 while (triggerPipe < 0) { 236 Tcl_ConditionWait(¬ifierCV, ¬ifierMutex, NULL); 237 } 238 239 Tcl_MutexUnlock(¬ifierMutex); 240#endif 241 return (ClientData) tsdPtr; 242} 243 244/* 245 *---------------------------------------------------------------------- 246 * 247 * Tcl_FinalizeNotifier -- 248 * 249 * This function is called to cleanup the notifier state before 250 * a thread is terminated. 251 * 252 * Results: 253 * None. 254 * 255 * Side effects: 256 * May terminate the background notifier thread if this is the 257 * last notifier instance. 258 * 259 *---------------------------------------------------------------------- 260 */ 261 262void 263Tcl_FinalizeNotifier(clientData) 264 ClientData clientData; /* Not used. */ 265{ 266#ifdef TCL_THREADS 267 ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); 268 269 Tcl_MutexLock(¬ifierMutex); 270 notifierCount--; 271 272 /* 273 * If this is the last thread to use the notifier, close the notifier 274 * pipe and wait for the background thread to terminate. 275 */ 276 277 if (notifierCount == 0) { 278 int result; 279 if (triggerPipe < 0) { 280 panic("Tcl_FinalizeNotifier: notifier pipe not initialized"); 281 } 282 283 /* 284 * Send "q" message to the notifier thread so that it will 285 * terminate. The notifier will return from its call to select() 286 * and notice that a "q" message has arrived, it will then close 287 * its side of the pipe and terminate its thread. Note the we can 288 * not just close the pipe and check for EOF in the notifier 289 * thread because if a background child process was created with 290 * exec, select() would not register the EOF on the pipe until the 291 * child processes had terminated. [Bug: 4139] [Bug: 1222872] 292 */ 293 294 write(triggerPipe, "q", 1); 295 close(triggerPipe); 296 while(triggerPipe >= 0) { 297 Tcl_ConditionWait(¬ifierCV, ¬ifierMutex, NULL); 298 } 299 result = Tcl_JoinThread(notifierThread, NULL); 300 if (result) { 301 Tcl_Panic("Tcl_FinalizeNotifier: unable to join notifier thread"); 302 } 303 } 304 305 /* 306 * Clean up any synchronization objects in the thread local storage. 307 */ 308 309 Tcl_ConditionFinalize(&(tsdPtr->waitCV)); 310 311 Tcl_MutexUnlock(¬ifierMutex); 312#endif 313} 314 315/* 316 *---------------------------------------------------------------------- 317 * 318 * Tcl_AlertNotifier -- 319 * 320 * Wake up the specified notifier from any thread. This routine 321 * is called by the platform independent notifier code whenever 322 * the Tcl_ThreadAlert routine is called. This routine is 323 * guaranteed not to be called on a given notifier after 324 * Tcl_FinalizeNotifier is called for that notifier. 325 * 326 * Results: 327 * None. 328 * 329 * Side effects: 330 * Signals the notifier condition variable for the specified 331 * notifier. 332 * 333 *---------------------------------------------------------------------- 334 */ 335 336void 337Tcl_AlertNotifier(clientData) 338 ClientData clientData; 339{ 340#ifdef TCL_THREADS 341 ThreadSpecificData *tsdPtr = (ThreadSpecificData *) clientData; 342 Tcl_MutexLock(¬ifierMutex); 343 tsdPtr->eventReady = 1; 344 Tcl_ConditionNotify(&tsdPtr->waitCV); 345 Tcl_MutexUnlock(¬ifierMutex); 346#endif 347} 348 349/* 350 *---------------------------------------------------------------------- 351 * 352 * Tcl_SetTimer -- 353 * 354 * This procedure sets the current notifier timer value. This 355 * interface is not implemented in this notifier because we are 356 * always running inside of Tcl_DoOneEvent. 357 * 358 * Results: 359 * None. 360 * 361 * Side effects: 362 * None. 363 * 364 *---------------------------------------------------------------------- 365 */ 366 367void 368Tcl_SetTimer(timePtr) 369 Tcl_Time *timePtr; /* Timeout value, may be NULL. */ 370{ 371 /* 372 * The interval timer doesn't do anything in this implementation, 373 * because the only event loop is via Tcl_DoOneEvent, which passes 374 * timeout values to Tcl_WaitForEvent. 375 */ 376 377 if (tclStubs.tcl_SetTimer != tclOriginalNotifier.setTimerProc) { 378 tclStubs.tcl_SetTimer(timePtr); 379 } 380} 381 382/* 383 *---------------------------------------------------------------------- 384 * 385 * Tcl_ServiceModeHook -- 386 * 387 * This function is invoked whenever the service mode changes. 388 * 389 * Results: 390 * None. 391 * 392 * Side effects: 393 * None. 394 * 395 *---------------------------------------------------------------------- 396 */ 397 398void 399Tcl_ServiceModeHook(mode) 400 int mode; /* Either TCL_SERVICE_ALL, or 401 * TCL_SERVICE_NONE. */ 402{ 403} 404 405/* 406 *---------------------------------------------------------------------- 407 * 408 * Tcl_CreateFileHandler -- 409 * 410 * This procedure registers a file handler with the select notifier. 411 * 412 * Results: 413 * None. 414 * 415 * Side effects: 416 * Creates a new file handler structure. 417 * 418 *---------------------------------------------------------------------- 419 */ 420 421void 422Tcl_CreateFileHandler(fd, mask, proc, clientData) 423 int fd; /* Handle of stream to watch. */ 424 int mask; /* OR'ed combination of TCL_READABLE, 425 * TCL_WRITABLE, and TCL_EXCEPTION: 426 * indicates conditions under which 427 * proc should be called. */ 428 Tcl_FileProc *proc; /* Procedure to call for each 429 * selected event. */ 430 ClientData clientData; /* Arbitrary data to pass to proc. */ 431{ 432 ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); 433 FileHandler *filePtr; 434 435 if (tclStubs.tcl_CreateFileHandler != tclOriginalNotifier.createFileHandlerProc) { 436 tclStubs.tcl_CreateFileHandler(fd, mask, proc, clientData); 437 return; 438 } 439 440 for (filePtr = tsdPtr->firstFileHandlerPtr; filePtr != NULL; 441 filePtr = filePtr->nextPtr) { 442 if (filePtr->fd == fd) { 443 break; 444 } 445 } 446 if (filePtr == NULL) { 447 filePtr = (FileHandler*) ckalloc(sizeof(FileHandler)); 448 filePtr->fd = fd; 449 filePtr->readyMask = 0; 450 filePtr->nextPtr = tsdPtr->firstFileHandlerPtr; 451 tsdPtr->firstFileHandlerPtr = filePtr; 452 } 453 filePtr->proc = proc; 454 filePtr->clientData = clientData; 455 filePtr->mask = mask; 456 457 /* 458 * Update the check masks for this file. 459 */ 460 461 if ( mask & TCL_READABLE ) { 462 FD_SET( fd, &(tsdPtr->checkMasks.readable) ); 463 } else { 464 FD_CLR( fd, &(tsdPtr->checkMasks.readable) ); 465 } 466 if ( mask & TCL_WRITABLE ) { 467 FD_SET( fd, &(tsdPtr->checkMasks.writable) ); 468 } else { 469 FD_CLR( fd, &(tsdPtr->checkMasks.writable) ); 470 } 471 if ( mask & TCL_EXCEPTION ) { 472 FD_SET( fd, &(tsdPtr->checkMasks.exceptional) ); 473 } else { 474 FD_CLR( fd, &(tsdPtr->checkMasks.exceptional) ); 475 } 476 if (tsdPtr->numFdBits <= fd) { 477 tsdPtr->numFdBits = fd+1; 478 } 479} 480 481/* 482 *---------------------------------------------------------------------- 483 * 484 * Tcl_DeleteFileHandler -- 485 * 486 * Cancel a previously-arranged callback arrangement for 487 * a file. 488 * 489 * Results: 490 * None. 491 * 492 * Side effects: 493 * If a callback was previously registered on file, remove it. 494 * 495 *---------------------------------------------------------------------- 496 */ 497 498void 499Tcl_DeleteFileHandler(fd) 500 int fd; /* Stream id for which to remove callback procedure. */ 501{ 502 FileHandler *filePtr, *prevPtr; 503 int i; 504 ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); 505 506 if (tclStubs.tcl_DeleteFileHandler != tclOriginalNotifier.deleteFileHandlerProc) { 507 tclStubs.tcl_DeleteFileHandler(fd); 508 return; 509 } 510 511 /* 512 * Find the entry for the given file (and return if there isn't one). 513 */ 514 515 for (prevPtr = NULL, filePtr = tsdPtr->firstFileHandlerPtr; ; 516 prevPtr = filePtr, filePtr = filePtr->nextPtr) { 517 if (filePtr == NULL) { 518 return; 519 } 520 if (filePtr->fd == fd) { 521 break; 522 } 523 } 524 525 /* 526 * Update the check masks for this file. 527 */ 528 529 if (filePtr->mask & TCL_READABLE) { 530 FD_CLR( fd, &(tsdPtr->checkMasks.readable) ); 531 } 532 if (filePtr->mask & TCL_WRITABLE) { 533 FD_CLR( fd, &(tsdPtr->checkMasks.writable) ); 534 } 535 if (filePtr->mask & TCL_EXCEPTION) { 536 FD_CLR( fd, &(tsdPtr->checkMasks.exceptional) ); 537 } 538 539 /* 540 * Find current max fd. 541 */ 542 543 if (fd+1 == tsdPtr->numFdBits) { 544 tsdPtr->numFdBits = 0; 545 for (i = fd-1; i >= 0; i--) { 546 if ( FD_ISSET( i, &(tsdPtr->checkMasks.readable) ) 547 || FD_ISSET( i, &(tsdPtr->checkMasks.writable) ) 548 || FD_ISSET( i, &(tsdPtr->checkMasks.exceptional ) ) ) { 549 tsdPtr->numFdBits = i+1; 550 break; 551 } 552 } 553 } 554 555 /* 556 * Clean up information in the callback record. 557 */ 558 559 if (prevPtr == NULL) { 560 tsdPtr->firstFileHandlerPtr = filePtr->nextPtr; 561 } else { 562 prevPtr->nextPtr = filePtr->nextPtr; 563 } 564 ckfree((char *) filePtr); 565} 566 567/* 568 *---------------------------------------------------------------------- 569 * 570 * FileHandlerEventProc -- 571 * 572 * This procedure is called by Tcl_ServiceEvent when a file event 573 * reaches the front of the event queue. This procedure is 574 * responsible for actually handling the event by invoking the 575 * callback for the file handler. 576 * 577 * Results: 578 * Returns 1 if the event was handled, meaning it should be removed 579 * from the queue. Returns 0 if the event was not handled, meaning 580 * it should stay on the queue. The only time the event isn't 581 * handled is if the TCL_FILE_EVENTS flag bit isn't set. 582 * 583 * Side effects: 584 * Whatever the file handler's callback procedure does. 585 * 586 *---------------------------------------------------------------------- 587 */ 588 589static int 590FileHandlerEventProc(evPtr, flags) 591 Tcl_Event *evPtr; /* Event to service. */ 592 int flags; /* Flags that indicate what events to 593 * handle, such as TCL_FILE_EVENTS. */ 594{ 595 int mask; 596 FileHandler *filePtr; 597 FileHandlerEvent *fileEvPtr = (FileHandlerEvent *) evPtr; 598 ThreadSpecificData *tsdPtr; 599 600 if (!(flags & TCL_FILE_EVENTS)) { 601 return 0; 602 } 603 604 /* 605 * Search through the file handlers to find the one whose handle matches 606 * the event. We do this rather than keeping a pointer to the file 607 * handler directly in the event, so that the handler can be deleted 608 * while the event is queued without leaving a dangling pointer. 609 */ 610 611 tsdPtr = TCL_TSD_INIT(&dataKey); 612 for (filePtr = tsdPtr->firstFileHandlerPtr; filePtr != NULL; 613 filePtr = filePtr->nextPtr) { 614 if (filePtr->fd != fileEvPtr->fd) { 615 continue; 616 } 617 618 /* 619 * The code is tricky for two reasons: 620 * 1. The file handler's desired events could have changed 621 * since the time when the event was queued, so AND the 622 * ready mask with the desired mask. 623 * 2. The file could have been closed and re-opened since 624 * the time when the event was queued. This is why the 625 * ready mask is stored in the file handler rather than 626 * the queued event: it will be zeroed when a new 627 * file handler is created for the newly opened file. 628 */ 629 630 mask = filePtr->readyMask & filePtr->mask; 631 filePtr->readyMask = 0; 632 if (mask != 0) { 633 (*filePtr->proc)(filePtr->clientData, mask); 634 } 635 break; 636 } 637 return 1; 638} 639 640/* 641 *---------------------------------------------------------------------- 642 * 643 * Tcl_WaitForEvent -- 644 * 645 * This function is called by Tcl_DoOneEvent to wait for new 646 * events on the message queue. If the block time is 0, then 647 * Tcl_WaitForEvent just polls without blocking. 648 * 649 * Results: 650 * Returns -1 if the select would block forever, otherwise 651 * returns 0. 652 * 653 * Side effects: 654 * Queues file events that are detected by the select. 655 * 656 *---------------------------------------------------------------------- 657 */ 658 659int 660Tcl_WaitForEvent(timePtr) 661 Tcl_Time *timePtr; /* Maximum block time, or NULL. */ 662{ 663 FileHandler *filePtr; 664 FileHandlerEvent *fileEvPtr; 665 int mask; 666#ifdef TCL_THREADS 667 int waitForFiles; 668#else 669 /* Impl. notes: timeout & timeoutPtr are used if, and only if 670 * threads are not enabled. They are the arguments for the regular 671 * select() used when the core is not thread-enabled. */ 672 673 struct timeval timeout, *timeoutPtr; 674 int numFound; 675#endif 676 ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); 677 678 if (tclStubs.tcl_WaitForEvent != tclOriginalNotifier.waitForEventProc) { 679 return tclStubs.tcl_WaitForEvent(timePtr); 680 } 681 682#ifndef TCL_THREADS 683 /* 684 * Set up the timeout structure. Note that if there are no events to 685 * check for, we return with a negative result rather than blocking 686 * forever. 687 */ 688 689 if (timePtr) { 690 timeout.tv_sec = timePtr->sec; 691 timeout.tv_usec = timePtr->usec; 692 timeoutPtr = &timeout; 693 } else if (tsdPtr->numFdBits == 0) { 694 /* 695 * If there are no threads, no timeout, and no fds registered, 696 * then there are no events possible and we must avoid deadlock. 697 * Note that this is not entirely correct because there might 698 * be a signal that could interrupt the select call, but we 699 * don't handle that case if we aren't using threads. 700 */ 701 702 return -1; 703 } else { 704 timeoutPtr = NULL; 705 } 706#endif 707 708#ifdef TCL_THREADS 709 /* 710 * Place this thread on the list of interested threads, signal the 711 * notifier thread, and wait for a response or a timeout. 712 */ 713 714 Tcl_MutexLock(¬ifierMutex); 715 716 waitForFiles = (tsdPtr->numFdBits > 0); 717 if (timePtr != NULL && timePtr->sec == 0 && (timePtr->usec == 0 718#if defined(__APPLE__) && defined(__LP64__) 719 /* 720 * On 64-bit Darwin, pthread_cond_timedwait() appears to have a bug 721 * that causes it to wait forever when passed an absolute time which 722 * has already been exceeded by the system time; as a workaround, 723 * when given a very brief timeout, just do a poll. [Bug 1457797] 724 */ 725 || timePtr->usec < 10 726#endif 727 )) { 728 /* 729 * Cannot emulate a polling select with a polling condition variable. 730 * Instead, pretend to wait for files and tell the notifier 731 * thread what we are doing. The notifier thread makes sure 732 * it goes through select with its select mask in the same state 733 * as ours currently is. We block until that happens. 734 */ 735 736 waitForFiles = 1; 737 tsdPtr->pollState = POLL_WANT; 738 timePtr = NULL; 739 } else { 740 tsdPtr->pollState = 0; 741 } 742 743 if (waitForFiles) { 744 /* 745 * Add the ThreadSpecificData structure of this thread to the list 746 * of ThreadSpecificData structures of all threads that are waiting 747 * on file events. 748 */ 749 750 751 tsdPtr->nextPtr = waitingListPtr; 752 if (waitingListPtr) { 753 waitingListPtr->prevPtr = tsdPtr; 754 } 755 tsdPtr->prevPtr = 0; 756 waitingListPtr = tsdPtr; 757 tsdPtr->onList = 1; 758 759 write(triggerPipe, "", 1); 760 } 761 762 FD_ZERO( &(tsdPtr->readyMasks.readable) ); 763 FD_ZERO( &(tsdPtr->readyMasks.writable) ); 764 FD_ZERO( &(tsdPtr->readyMasks.exceptional) ); 765 766 if (!tsdPtr->eventReady) { 767 Tcl_ConditionWait(&tsdPtr->waitCV, ¬ifierMutex, timePtr); 768 } 769 tsdPtr->eventReady = 0; 770 771 if (waitForFiles && tsdPtr->onList) { 772 /* 773 * Remove the ThreadSpecificData structure of this thread from the 774 * waiting list. Alert the notifier thread to recompute its select 775 * masks - skipping this caused a hang when trying to close a pipe 776 * which the notifier thread was still doing a select on. 777 */ 778 779 if (tsdPtr->prevPtr) { 780 tsdPtr->prevPtr->nextPtr = tsdPtr->nextPtr; 781 } else { 782 waitingListPtr = tsdPtr->nextPtr; 783 } 784 if (tsdPtr->nextPtr) { 785 tsdPtr->nextPtr->prevPtr = tsdPtr->prevPtr; 786 } 787 tsdPtr->nextPtr = tsdPtr->prevPtr = NULL; 788 tsdPtr->onList = 0; 789 write(triggerPipe, "", 1); 790 } 791 792 793#else 794 tsdPtr->readyMasks = tsdPtr->checkMasks; 795 numFound = select( tsdPtr->numFdBits, 796 &(tsdPtr->readyMasks.readable), 797 &(tsdPtr->readyMasks.writable), 798 &(tsdPtr->readyMasks.exceptional), 799 timeoutPtr ); 800 801 /* 802 * Some systems don't clear the masks after an error, so 803 * we have to do it here. 804 */ 805 806 if (numFound == -1) { 807 FD_ZERO( &(tsdPtr->readyMasks.readable ) ); 808 FD_ZERO( &(tsdPtr->readyMasks.writable ) ); 809 FD_ZERO( &(tsdPtr->readyMasks.exceptional ) ); 810 } 811#endif 812 813 /* 814 * Queue all detected file events before returning. 815 */ 816 817 for (filePtr = tsdPtr->firstFileHandlerPtr; (filePtr != NULL); 818 filePtr = filePtr->nextPtr) { 819 820 mask = 0; 821 if ( FD_ISSET( filePtr->fd, &(tsdPtr->readyMasks.readable) ) ) { 822 mask |= TCL_READABLE; 823 } 824 if ( FD_ISSET( filePtr->fd, &(tsdPtr->readyMasks.writable) ) ) { 825 mask |= TCL_WRITABLE; 826 } 827 if ( FD_ISSET( filePtr->fd, &(tsdPtr->readyMasks.exceptional) ) ) { 828 mask |= TCL_EXCEPTION; 829 } 830 831 if (!mask) { 832 continue; 833 } 834 835 /* 836 * Don't bother to queue an event if the mask was previously 837 * non-zero since an event must still be on the queue. 838 */ 839 840 if (filePtr->readyMask == 0) { 841 fileEvPtr = (FileHandlerEvent *) ckalloc( 842 sizeof(FileHandlerEvent)); 843 fileEvPtr->header.proc = FileHandlerEventProc; 844 fileEvPtr->fd = filePtr->fd; 845 Tcl_QueueEvent((Tcl_Event *) fileEvPtr, TCL_QUEUE_TAIL); 846 } 847 filePtr->readyMask = mask; 848 } 849#ifdef TCL_THREADS 850 Tcl_MutexUnlock(¬ifierMutex); 851#endif 852 return 0; 853} 854 855#ifdef TCL_THREADS 856/* 857 *---------------------------------------------------------------------- 858 * 859 * NotifierThreadProc -- 860 * 861 * This routine is the initial (and only) function executed by the 862 * special notifier thread. Its job is to wait for file descriptors 863 * to become readable or writable or to have an exception condition 864 * and then to notify other threads who are interested in this 865 * information by signalling a condition variable. Other threads 866 * can signal this notifier thread of a change in their interests 867 * by writing a single byte to a special pipe that the notifier 868 * thread is monitoring. 869 * 870 * Result: 871 * None. Once started, this routine never exits. It dies with 872 * the overall process. 873 * 874 * Side effects: 875 * The trigger pipe used to signal the notifier thread is created 876 * when the notifier thread first starts. 877 * 878 *---------------------------------------------------------------------- 879 */ 880 881static void 882NotifierThreadProc(clientData) 883 ClientData clientData; /* Not used. */ 884{ 885 ThreadSpecificData *tsdPtr; 886 fd_set readableMask; 887 fd_set writableMask; 888 fd_set exceptionalMask; 889 int fds[2]; 890 int i, status, numFdBits = 0, receivePipe; 891 long found; 892 struct timeval poll = {0., 0.}, *timePtr; 893 char buf[2]; 894 895 if (pipe(fds) != 0) { 896 panic("NotifierThreadProc: could not create trigger pipe."); 897 } 898 899 receivePipe = fds[0]; 900 901#ifndef USE_FIONBIO 902 status = fcntl(receivePipe, F_GETFL); 903 status |= O_NONBLOCK; 904 if (fcntl(receivePipe, F_SETFL, status) < 0) { 905 panic("NotifierThreadProc: could not make receive pipe non blocking."); 906 } 907 status = fcntl(fds[1], F_GETFL); 908 status |= O_NONBLOCK; 909 if (fcntl(fds[1], F_SETFL, status) < 0) { 910 panic("NotifierThreadProc: could not make trigger pipe non blocking."); 911 } 912#else 913 if (ioctl(receivePipe, (int) FIONBIO, &status) < 0) { 914 panic("NotifierThreadProc: could not make receive pipe non blocking."); 915 } 916 if (ioctl(fds[1], (int) FIONBIO, &status) < 0) { 917 panic("NotifierThreadProc: could not make trigger pipe non blocking."); 918 } 919#endif 920 921 /* 922 * Install the write end of the pipe into the global variable. 923 */ 924 925 Tcl_MutexLock(¬ifierMutex); 926 triggerPipe = fds[1]; 927 928 /* 929 * Signal any threads that are waiting. 930 */ 931 932 Tcl_ConditionNotify(¬ifierCV); 933 Tcl_MutexUnlock(¬ifierMutex); 934 935 /* 936 * Look for file events and report them to interested threads. 937 */ 938 939 while (1) { 940 941 FD_ZERO( &readableMask ); 942 FD_ZERO( &writableMask ); 943 FD_ZERO( &exceptionalMask ); 944 945 /* 946 * Compute the logical OR of the select masks from all the 947 * waiting notifiers. 948 */ 949 950 Tcl_MutexLock(¬ifierMutex); 951 timePtr = NULL; 952 for (tsdPtr = waitingListPtr; tsdPtr; tsdPtr = tsdPtr->nextPtr) { 953 for ( i = tsdPtr->numFdBits-1; i >= 0; --i ) { 954 if ( FD_ISSET( i, &(tsdPtr->checkMasks.readable) ) ) { 955 FD_SET( i, &readableMask ); 956 } 957 if ( FD_ISSET( i, &(tsdPtr->checkMasks.writable) ) ) { 958 FD_SET( i, &writableMask ); 959 } 960 if ( FD_ISSET( i, &(tsdPtr->checkMasks.exceptional) ) ) { 961 FD_SET( i, &exceptionalMask ); 962 } 963 } 964 if ( tsdPtr->numFdBits > numFdBits ) { 965 numFdBits = tsdPtr->numFdBits; 966 } 967 if (tsdPtr->pollState & POLL_WANT) { 968 /* 969 * Here we make sure we go through select() with the same 970 * mask bits that were present when the thread tried to poll. 971 */ 972 973 tsdPtr->pollState |= POLL_DONE; 974 timePtr = &poll; 975 } 976 } 977 Tcl_MutexUnlock(¬ifierMutex); 978 979 /* 980 * Set up the select mask to include the receive pipe. 981 */ 982 983 if ( receivePipe >= numFdBits ) { 984 numFdBits = receivePipe + 1; 985 } 986 FD_SET( receivePipe, &readableMask ); 987 988 if ( select( numFdBits, &readableMask, &writableMask, 989 &exceptionalMask, timePtr) == -1 ) { 990 /* 991 * Try again immediately on an error. 992 */ 993 994 continue; 995 } 996 997 /* 998 * Alert any threads that are waiting on a ready file descriptor. 999 */ 1000 1001 Tcl_MutexLock(¬ifierMutex); 1002 for (tsdPtr = waitingListPtr; tsdPtr; tsdPtr = tsdPtr->nextPtr) { 1003 found = 0; 1004 1005 for ( i = tsdPtr->numFdBits-1; i >= 0; --i ) { 1006 if ( FD_ISSET( i, &(tsdPtr->checkMasks.readable) ) 1007 && FD_ISSET( i, &readableMask ) ) { 1008 FD_SET( i, &(tsdPtr->readyMasks.readable) ); 1009 found = 1; 1010 } 1011 if ( FD_ISSET( i, &(tsdPtr->checkMasks.writable) ) 1012 && FD_ISSET( i, &writableMask ) ) { 1013 FD_SET( i, &(tsdPtr->readyMasks.writable) ); 1014 found = 1; 1015 } 1016 if ( FD_ISSET( i, &(tsdPtr->checkMasks.exceptional) ) 1017 && FD_ISSET( i, &exceptionalMask ) ) { 1018 FD_SET( i, &(tsdPtr->readyMasks.exceptional) ); 1019 found = 1; 1020 } 1021 } 1022 1023 if (found || (tsdPtr->pollState & POLL_DONE)) { 1024 tsdPtr->eventReady = 1; 1025 if (tsdPtr->onList) { 1026 /* 1027 * Remove the ThreadSpecificData structure of this 1028 * thread from the waiting list. This prevents us from 1029 * continuously spining on select until the other 1030 * threads runs and services the file event. 1031 */ 1032 1033 if (tsdPtr->prevPtr) { 1034 tsdPtr->prevPtr->nextPtr = tsdPtr->nextPtr; 1035 } else { 1036 waitingListPtr = tsdPtr->nextPtr; 1037 } 1038 if (tsdPtr->nextPtr) { 1039 tsdPtr->nextPtr->prevPtr = tsdPtr->prevPtr; 1040 } 1041 tsdPtr->nextPtr = tsdPtr->prevPtr = NULL; 1042 tsdPtr->onList = 0; 1043 tsdPtr->pollState = 0; 1044 } 1045 Tcl_ConditionNotify(&tsdPtr->waitCV); 1046 } 1047 } 1048 Tcl_MutexUnlock(¬ifierMutex); 1049 1050 /* 1051 * Consume the next byte from the notifier pipe if the pipe was 1052 * readable. Note that there may be multiple bytes pending, but 1053 * to avoid a race condition we only read one at a time. 1054 */ 1055 1056 if ( FD_ISSET( receivePipe, &readableMask ) ) { 1057 i = read(receivePipe, buf, 1); 1058 1059 if ((i == 0) || ((i == 1) && (buf[0] == 'q'))) { 1060 /* 1061 * Someone closed the write end of the pipe or sent us a 1062 * Quit message [Bug: 4139] and then closed the write end 1063 * of the pipe so we need to shut down the notifier thread. 1064 */ 1065 1066 break; 1067 } 1068 } 1069 } 1070 1071 /* 1072 * Clean up the read end of the pipe and signal any threads waiting on 1073 * termination of the notifier thread. 1074 */ 1075 1076 close(receivePipe); 1077 Tcl_MutexLock(¬ifierMutex); 1078 triggerPipe = -1; 1079 Tcl_ConditionNotify(¬ifierCV); 1080 Tcl_MutexUnlock(¬ifierMutex); 1081 1082 TclpThreadExit (0); 1083} 1084#endif 1085 1086#endif /* HAVE_COREFOUNDATION */ 1087