diff options
Diffstat (limited to 'macosx/tclMacOSXNotify.c')
| -rw-r--r-- | macosx/tclMacOSXNotify.c | 930 |
1 files changed, 319 insertions, 611 deletions
diff --git a/macosx/tclMacOSXNotify.c b/macosx/tclMacOSXNotify.c index de633a5..2252ec1 100644 --- a/macosx/tclMacOSXNotify.c +++ b/macosx/tclMacOSXNotify.c @@ -5,27 +5,15 @@ * based notifier, which is the lowest-level part of the Tcl event loop. * This file works together with generic/tclNotify.c. * - * Copyright © 1995-1997 Sun Microsystems, Inc. - * Copyright © 2001-2009, Apple Inc. - * Copyright © 2005-2009 Daniel A. Steffen <das@users.sourceforge.net> + * Copyright (c) 1995-1997 Sun Microsystems, Inc. + * Copyright 2001-2009, Apple Inc. + * Copyright (c) 2005-2009 Daniel A. Steffen <das@users.sourceforge.net> * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" - -/* - * In macOS 10.12 the os_unfair_lock was introduced as a replacement for the - * OSSpinLock, and the OSSpinLock was deprecated. - */ - -#if MAC_OS_X_VERSION_MIN_REQUIRED >= 101200 -#define USE_OS_UNFAIR_LOCK -#include <os/lock.h> -#undef TCL_MAC_DEBUG_NOTIFIER -#endif - #ifdef HAVE_COREFOUNDATION /* Traditional unix select-based notifier is * in tclUnixNotfy.c */ #include <CoreFoundation/CoreFoundation.h> @@ -33,7 +21,8 @@ /* #define TCL_MAC_DEBUG_NOTIFIER 1 */ -#if !defined(USE_OS_UNFAIR_LOCK) +extern TclStubs tclStubs; +extern Tcl_NotifierProcs tclOriginalNotifier; /* * We use the Darwin-native spinlock API rather than pthread mutexes for @@ -45,9 +34,6 @@ */ #if defined(HAVE_LIBKERN_OSATOMIC_H) && defined(HAVE_OSSPINLOCKLOCK) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wdeprecated-declarations" -#pragma GCC diagnostic ignored "-Wunused-function" /* * Use OSSpinLock API where available (Tiger or later). */ @@ -59,37 +45,26 @@ * Support for weakly importing spinlock API. */ #define WEAK_IMPORT_SPINLOCKLOCK - #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1050 #define VOLATILE volatile #else #define VOLATILE -#endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1050 */ - +#endif #ifndef bool #define bool int #endif - -extern void OSSpinLockLock(VOLATILE OSSpinLock *lock) - WEAK_IMPORT_ATTRIBUTE; -extern void OSSpinLockUnlock(VOLATILE OSSpinLock *lock) - WEAK_IMPORT_ATTRIBUTE; -extern bool OSSpinLockTry(VOLATILE OSSpinLock *lock) - WEAK_IMPORT_ATTRIBUTE; -extern void _spin_lock(VOLATILE OSSpinLock *lock) - WEAK_IMPORT_ATTRIBUTE; -extern void _spin_unlock(VOLATILE OSSpinLock *lock) - WEAK_IMPORT_ATTRIBUTE; -extern bool _spin_lock_try(VOLATILE OSSpinLock *lock) - WEAK_IMPORT_ATTRIBUTE; +extern void OSSpinLockLock(VOLATILE OSSpinLock *lock) WEAK_IMPORT_ATTRIBUTE; +extern void OSSpinLockUnlock(VOLATILE OSSpinLock *lock) WEAK_IMPORT_ATTRIBUTE; +extern bool OSSpinLockTry(VOLATILE OSSpinLock *lock) WEAK_IMPORT_ATTRIBUTE; +extern void _spin_lock(VOLATILE OSSpinLock *lock) WEAK_IMPORT_ATTRIBUTE; +extern void _spin_unlock(VOLATILE OSSpinLock *lock) WEAK_IMPORT_ATTRIBUTE; +extern bool _spin_lock_try(VOLATILE OSSpinLock *lock) WEAK_IMPORT_ATTRIBUTE; static void (* lockLock)(VOLATILE OSSpinLock *lock) = NULL; static void (* lockUnlock)(VOLATILE OSSpinLock *lock) = NULL; static bool (* lockTry)(VOLATILE OSSpinLock *lock) = NULL; #undef VOLATILE static pthread_once_t spinLockLockInitControl = PTHREAD_ONCE_INIT; -static void -SpinLockLockInit(void) -{ +static void SpinLockLockInit(void) { lockLock = OSSpinLockLock != NULL ? OSSpinLockLock : _spin_lock; lockUnlock = OSSpinLockUnlock != NULL ? OSSpinLockUnlock : _spin_unlock; lockTry = OSSpinLockTry != NULL ? OSSpinLockTry : _spin_lock_try; @@ -97,56 +72,15 @@ SpinLockLockInit(void) Tcl_Panic("SpinLockLockInit: no spinlock API available"); } } - -/* - * Wrappers so that we get warnings in just one small part of this file. - */ - -static inline void -SpinLockLock( - VOLATILE OSSpinLock *lock) -{ - lockLock(lock); -} -static inline void -SpinLockUnlock( - VOLATILE OSSpinLock *lock) -{ - lockUnlock(lock); -} -static inline bool -SpinLockTry( - VOLATILE OSSpinLock *lock) -{ - return lockTry(lock); -} - -#else /* !HAVE_WEAK_IMPORT */ - -/* - * Wrappers so that we get warnings in just one small part of this file. - */ - -static inline void -SpinLockLock( - OSSpinLock *lock) -{ - OSSpinLockLock(lock); -} -static inline void -SpinLockUnlock( - OSSpinLock *lock) -{ - OSSpinLockUnlock(lock); -} -static inline bool -SpinLockTry( - OSSpinLock *lock) -{ - return OSSpinLockTry(lock); -} +#define SpinLockLock(p) lockLock(p) +#define SpinLockUnlock(p) lockUnlock(p) +#define SpinLockTry(p) lockTry(p) +#else +#define SpinLockLock(p) OSSpinLockLock(p) +#define SpinLockUnlock(p) OSSpinLockUnlock(p) +#define SpinLockTry(p) OSSpinLockTry(p) #endif /* HAVE_WEAK_IMPORT */ -#define SPINLOCK_INIT OS_SPINLOCK_INIT +#define SPINLOCK_INIT OS_SPINLOCK_INIT #else /* @@ -154,147 +88,99 @@ SpinLockTry( */ typedef uint32_t OSSpinLock; +extern void _spin_lock(OSSpinLock *lock); +extern void _spin_unlock(OSSpinLock *lock); +extern int _spin_lock_try(OSSpinLock *lock); +#define SpinLockLock(p) _spin_lock(p) +#define SpinLockUnlock(p) _spin_unlock(p) +#define SpinLockTry(p) _spin_lock_try(p) +#define SPINLOCK_INIT 0 -static inline void -SpinLockLock( - OSSpinLock *lock) -{ - extern void _spin_lock(OSSpinLock *lock); - - _spin_lock(lock); -} - -static inline void -SpinLockUnlock( - OSSpinLock *lock) -{ - extern void _spin_unlock(OSSpinLock *lock); - - _spin_unlock(lock); -} - -static inline int -SpinLockTry( - OSSpinLock *lock) -{ - extern int _spin_lock_try(OSSpinLock *lock); - - return _spin_lock_try(lock); -} - -#define SPINLOCK_INIT 0 - -#pragma GCC diagnostic pop #endif /* HAVE_LIBKERN_OSATOMIC_H && HAVE_OSSPINLOCKLOCK */ -#endif /* not using os_unfair_lock */ /* - * These locks control access to the global notifier state. + * These spinlocks lock access to the global notifier state. */ -#if defined(USE_OS_UNFAIR_LOCK) -static os_unfair_lock notifierInitLock = OS_UNFAIR_LOCK_INIT; -static os_unfair_lock notifierLock = OS_UNFAIR_LOCK_INIT; -#else static OSSpinLock notifierInitLock = SPINLOCK_INIT; static OSSpinLock notifierLock = SPINLOCK_INIT; -#endif /* - * Macros that abstract notifier locking/unlocking + * Macros abstracting notifier locking/unlocking */ -#if defined(USE_OS_UNFAIR_LOCK) -#define LOCK_NOTIFIER_INIT os_unfair_lock_lock(¬ifierInitLock) -#define UNLOCK_NOTIFIER_INIT os_unfair_lock_unlock(¬ifierInitLock) -#define LOCK_NOTIFIER os_unfair_lock_lock(¬ifierLock) -#define UNLOCK_NOTIFIER os_unfair_lock_unlock(¬ifierLock) -#define LOCK_NOTIFIER_TSD os_unfair_lock_lock(&tsdPtr->tsdLock) -#define UNLOCK_NOTIFIER_TSD os_unfair_lock_unlock(&tsdPtr->tsdLock) -#else #define LOCK_NOTIFIER_INIT SpinLockLock(¬ifierInitLock) #define UNLOCK_NOTIFIER_INIT SpinLockUnlock(¬ifierInitLock) #define LOCK_NOTIFIER SpinLockLock(¬ifierLock) #define UNLOCK_NOTIFIER SpinLockUnlock(¬ifierLock) #define LOCK_NOTIFIER_TSD SpinLockLock(&tsdPtr->tsdLock) #define UNLOCK_NOTIFIER_TSD SpinLockUnlock(&tsdPtr->tsdLock) -#endif - -/* - * The debug version of the Notifier only works if using OSSpinLock. - */ -#if defined(TCL_MAC_DEBUG_NOTIFIER) && !defined(USE_OS_UNFAIR_LOCK) -#define TclMacOSXNotifierDbgMsg(m, ...) \ - do { \ - fprintf(notifierLog?notifierLog:stderr, "tclMacOSXNotify.c:%d: " \ - "%s() pid %5d thread %10p: " m "\n", __LINE__, __func__, \ - getpid(), pthread_self(), ##__VA_ARGS__); \ - fflush(notifierLog?notifierLog:stderr); \ - } while (0) +#ifdef TCL_MAC_DEBUG_NOTIFIER +#define TclMacOSXNotifierDbgMsg(m, ...) do { \ + fprintf(notifierLog?notifierLog:stderr, "tclMacOSXNotify.c:%d: " \ + "%s() pid %5d thread %10p: " m "\n", __LINE__, __func__, \ + getpid(), pthread_self(), ##__VA_ARGS__); \ + fflush(notifierLog?notifierLog:stderr); \ + } while (0) /* * Debug version of SpinLockLock that logs the time spent waiting for the lock */ -#define SpinLockLockDbg(p) \ - if (!SpinLockTry(p)) { \ - long long s = TclpGetWideClicks(), e; \ - \ - SpinLockLock(p); \ - e = TclpGetWideClicks(); \ - TclMacOSXNotifierDbgMsg("waited on %s for %8.0f ns", \ - #p, TclpWideClicksToNanoseconds(e-s)); \ - } +#define SpinLockLockDbg(p) if (!SpinLockTry(p)) { \ + Tcl_WideInt s = TclpGetWideClicks(), e; \ + SpinLockLock(p); e = TclpGetWideClicks(); \ + TclMacOSXNotifierDbgMsg("waited on %s for %8.0f ns", \ + #p, TclpWideClicksToNanoseconds(e-s)); \ + } #undef LOCK_NOTIFIER_INIT #define LOCK_NOTIFIER_INIT SpinLockLockDbg(¬ifierInitLock) #undef LOCK_NOTIFIER #define LOCK_NOTIFIER SpinLockLockDbg(¬ifierLock) #undef LOCK_NOTIFIER_TSD -#define LOCK_NOTIFIER_TSD SpinLockLockDbg(tsdPtr->tsdLock) +#define LOCK_NOTIFIER_TSD SpinLockLockDbg(&tsdPtr->tsdLock) #include <asl.h> static FILE *notifierLog = NULL; #ifndef NOTIFIER_LOG #define NOTIFIER_LOG "/tmp/tclMacOSXNotify.log" #endif -#define OPEN_NOTIFIER_LOG \ - if (!notifierLog) { \ - notifierLog = fopen(NOTIFIER_LOG, "a"); \ - /*TclMacOSXNotifierDbgMsg("open log"); \ - *asl_set_filter(NULL, \ - * ASL_FILTER_MASK_UPTO(ASL_LEVEL_DEBUG)); \ - *asl_add_log_file(NULL, fileno(notifierLog));*/ \ - } -#define CLOSE_NOTIFIER_LOG \ - if (notifierLog) { \ - /*asl_remove_log_file(NULL, fileno(notifierLog)); \ - *TclMacOSXNotifierDbgMsg("close log");*/ \ - fclose(notifierLog); \ - notifierLog = NULL; \ - } -#define ENABLE_ASL \ - if (notifierLog) { \ - /*tsdPtr->asl = asl_open(NULL, "com.apple.console", \ - * ASL_OPT_NO_REMOTE); \ - *asl_set_filter(tsdPtr->asl, \ - * ASL_FILTER_MASK_UPTO(ASL_LEVEL_DEBUG)); \ - *asl_add_log_file(tsdPtr->asl, fileno(notifierLog));*/ \ - } -#define DISABLE_ASL \ - /*if (tsdPtr->asl) { \ - * if (notifierLog) { \ - * asl_remove_log_file(tsdPtr->asl, fileno(notifierLog)); \ - * } \ - * asl_close(tsdPtr->asl); \ - *}*/ -#define ASLCLIENT_DECL /*aslclient asl*/ +#define OPEN_NOTIFIER_LOG if (!notifierLog) { \ + notifierLog = fopen(NOTIFIER_LOG, "a"); \ + /*TclMacOSXNotifierDbgMsg("open log"); \ + asl_set_filter(NULL, \ + ASL_FILTER_MASK_UPTO(ASL_LEVEL_DEBUG)); \ + asl_add_log_file(NULL, \ + fileno(notifierLog));*/ \ + } +#define CLOSE_NOTIFIER_LOG if (notifierLog) { \ + /*asl_remove_log_file(NULL, \ + fileno(notifierLog)); \ + TclMacOSXNotifierDbgMsg("close log");*/ \ + fclose(notifierLog); \ + notifierLog = NULL; \ + } +#define ENABLE_ASL if (notifierLog) { \ + /*tsdPtr->asl = asl_open(NULL, "com.apple.console", ASL_OPT_NO_REMOTE); \ + asl_set_filter(tsdPtr->asl, \ + ASL_FILTER_MASK_UPTO(ASL_LEVEL_DEBUG)); \ + asl_add_log_file(tsdPtr->asl, \ + fileno(notifierLog));*/ \ + } +#define DISABLE_ASL /*if (tsdPtr->asl) { \ + if (notifierLog) { \ + asl_remove_log_file(tsdPtr->asl, \ + fileno(notifierLog)); \ + } \ + asl_close(tsdPtr->asl); \ + }*/ +#define ASLCLIENT /*aslclient asl*/ #else #define TclMacOSXNotifierDbgMsg(m, ...) #define OPEN_NOTIFIER_LOG #define CLOSE_NOTIFIER_LOG #define ENABLE_ASL #define DISABLE_ASL -#define ASLCLIENT_DECL #endif /* TCL_MAC_DEBUG_NOTIFIER */ /* @@ -311,7 +197,7 @@ typedef struct FileHandler { * for this file. */ Tcl_FileProc *proc; /* Function to call, in the style of * Tcl_CreateFileHandler. */ - void *clientData; /* Argument to pass to proc. */ + ClientData clientData; /* Argument to pass to proc. */ struct FileHandler *nextPtr;/* Next in list of all files we care about. */ } FileHandler; @@ -320,7 +206,7 @@ typedef struct FileHandler { * handlers are ready to fire. */ -typedef struct { +typedef struct FileHandlerEvent { Tcl_Event header; /* Information that is standard for all * events. */ int fd; /* File descriptor that is ready. Used to find @@ -335,7 +221,7 @@ typedef struct { * writable, and exceptional conditions. */ -typedef struct { +typedef struct SelectMasks { fd_set readable; fd_set writable; fd_set exceptional; @@ -351,33 +237,28 @@ typedef struct ThreadSpecificData { FileHandler *firstFileHandlerPtr; /* Pointer to head of file handler list. */ int polled; /* True if the notifier thread has polled for - * this thread. */ + * this thread. + */ int sleeping; /* True if runloop is inside Tcl_Sleep. */ int runLoopSourcePerformed; /* True after the runLoopSource callack was * performed. */ - int runLoopRunning; /* True if this thread's Tcl runLoop is - * running. */ - int runLoopNestingLevel; /* Level of nested runLoop invocations. */ - + int runLoopRunning; /* True if this thread's Tcl runLoop is running */ + int runLoopNestingLevel; /* Level of nested runLoop invocations */ + int runLoopServicingEvents; /* True if this thread's runLoop is servicing + * tcl events */ /* Must hold the notifierLock before accessing the following fields: */ /* Start notifierLock section */ - int onList; /* True if this thread is on the - * waitingList */ + int onList; /* True if this thread is on the waitingList */ 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. */ + * from these pointers. + */ /* End notifierLock section */ - -#if defined(USE_OS_UNFAIR_LOCK) - os_unfair_lock tsdLock; -#else OSSpinLock tsdLock; /* Must hold this lock before acessing the - * following fields from more than one - * thread. */ -#endif - + * following fields from more than one thread. + */ /* Start tsdLock section */ SelectMasks checkMasks; /* This structure is used to build up the * masks to be used in the next call to @@ -389,11 +270,9 @@ typedef struct ThreadSpecificData { int numFdBits; /* Number of valid bits in checkMasks (one * more than highest fd for which * Tcl_WatchFile has been called). */ - int polling; /* True if this thread is polling for - * events. */ + int polling; /* True if this thread is polling for events */ CFRunLoopRef runLoop; /* This thread's CFRunLoop, needs to be woken - * up whenever the runLoopSource is - * signaled. */ + * up whenever the runLoopSource is signaled */ CFRunLoopSourceRef runLoopSource; /* Any other thread alerts a notifier that an * event is ready to be processed by signaling @@ -405,10 +284,11 @@ typedef struct ThreadSpecificData { /* Wakes up CFRunLoop after given timeout when * running embedded. */ /* End tsdLock section */ - CFTimeInterval waitTime; /* runLoopTimer wait time when running * embedded. */ - ASLCLIENT_DECL; +#ifdef TCL_MAC_DEBUG_NOTIFIER + ASLCLIENT; +#endif } ThreadSpecificData; static Tcl_ThreadDataKey dataKey; @@ -458,22 +338,8 @@ static int receivePipe = -1; /* Output end of triggerPipe */ static int notifierThreadRunning; /* - * The following static flag indicates that async handlers are pending. - */ - -#if TCL_THREADS -static int asyncPending = 0; -#endif - -/* - * Signal mask information for notifier thread. - */ -static sigset_t notifierSigMask; -static sigset_t allSigMask; - -/* - * This is the thread ID of the notifier thread that does select. Only valid - * when notifierThreadRunning is non-zero. + * This is the thread ID of the notifier thread that does select. + * Only valid when notifierThreadRunning is non-zero. * * You must hold the notifierInitLock before accessing this variable. */ @@ -482,7 +348,7 @@ static pthread_t notifierThread; /* * Custom runloop mode for running with only the runloop source for the - * notifier thread. + * notifier thread */ #ifndef TCL_EVENTS_ONLY_RUN_LOOP_MODE @@ -504,102 +370,45 @@ static CFStringRef tclEventsOnlyRunLoopMode = NULL; * Static routines defined in this file. */ -static void StartNotifierThread(void); -static TCL_NORETURN void NotifierThreadProc(void *clientData); -static int FileHandlerEventProc(Tcl_Event *evPtr, int flags); -static void TimerWakeUp(CFRunLoopTimerRef timer, void *info); -static void QueueFileEvents(void *info); -static void UpdateWaitingListAndServiceEvents( - CFRunLoopObserverRef observer, - CFRunLoopActivity activity, void *info); -static int OnOffWaitingList(ThreadSpecificData *tsdPtr, - int onList, int signalNotifier); +static void StartNotifierThread(void); +static void NotifierThreadProc(ClientData clientData) + __attribute__ ((__noreturn__)); +static int FileHandlerEventProc(Tcl_Event *evPtr, int flags); +static void TimerWakeUp(CFRunLoopTimerRef timer, void *info); +static void QueueFileEvents(void *info); +static void UpdateWaitingListAndServiceEvents(CFRunLoopObserverRef observer, + CFRunLoopActivity activity, void *info); +static int OnOffWaitingList(ThreadSpecificData *tsdPtr, int onList, + int signalNotifier); #ifdef HAVE_PTHREAD_ATFORK -static int atForkInit = 0; -static void AtForkPrepare(void); -static void AtForkParent(void); -static void AtForkChild(void); +static int atForkInit = 0; +static void AtForkPrepare(void); +static void AtForkParent(void); +static void AtForkChild(void); #if defined(HAVE_WEAK_IMPORT) && MAC_OS_X_VERSION_MIN_REQUIRED < 1040 /* Support for weakly importing pthread_atfork. */ #define WEAK_IMPORT_PTHREAD_ATFORK -extern int pthread_atfork(void (*prepare)(void), - void (*parent)(void), void (*child)(void)) - WEAK_IMPORT_ATTRIBUTE; -#define MayUsePthreadAtfork() (pthread_atfork != NULL) -#else -#define MayUsePthreadAtfork() (1) +extern int pthread_atfork(void (*prepare)(void), void (*parent)(void), + void (*child)(void)) WEAK_IMPORT_ATTRIBUTE; #endif /* HAVE_WEAK_IMPORT */ - /* * On Darwin 9 and later, it is not possible to call CoreFoundation after * a fork. */ - #if !defined(MAC_OS_X_VERSION_MIN_REQUIRED) || \ MAC_OS_X_VERSION_MIN_REQUIRED < 1050 MODULE_SCOPE long tclMacOSXDarwinRelease; -#define noCFafterFork (tclMacOSXDarwinRelease >= 9) +#define noCFafterFork (tclMacOSXDarwinRelease >= 9) #else /* MAC_OS_X_VERSION_MIN_REQUIRED */ -#define noCFafterFork 1 +#define noCFafterFork 1 #endif /* MAC_OS_X_VERSION_MIN_REQUIRED */ #endif /* HAVE_PTHREAD_ATFORK */ /* *---------------------------------------------------------------------- * - * LookUpFileHandler -- - * - * Look up the file handler structure (and optionally the previous one in - * the chain) associated with a file descriptor. - * - * Returns: - * A pointer to the file handler, or NULL if it can't be found. - * - * Side effects: - * If prevPtrPtr is non-NULL, it will be written to if the file handler - * is found. - * - *---------------------------------------------------------------------- - */ - -static inline FileHandler * -LookUpFileHandler( - ThreadSpecificData *tsdPtr, /* Where to look things up. */ - int fd, /* What we are looking for. */ - FileHandler **prevPtrPtr) /* If non-NULL, where to report the previous - * pointer. */ -{ - FileHandler *filePtr, *prevPtr; - - /* - * Find the entry for the given file (and return if there isn't one). - */ - - for (prevPtr = NULL, filePtr = tsdPtr->firstFileHandlerPtr; ; - prevPtr = filePtr, filePtr = filePtr->nextPtr) { - if (filePtr == NULL) { - return NULL; - } - if (filePtr->fd == fd) { - break; - } - } - - /* - * Report what we've found to our caller. - */ - - if (prevPtrPtr) { - *prevPtrPtr = prevPtr; - } - return filePtr; -} - -/* - *---------------------------------------------------------------------- - * - * TclpInitNotifier -- + * Tcl_InitNotifier -- * * Initializes the platform specific notifier state. * @@ -612,17 +421,20 @@ LookUpFileHandler( *---------------------------------------------------------------------- */ -void * -TclpInitNotifier(void) +ClientData +Tcl_InitNotifier(void) { - ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); + ThreadSpecificData *tsdPtr; + + tsdPtr = TCL_TSD_INIT(&dataKey); #ifdef WEAK_IMPORT_SPINLOCKLOCK /* * Initialize support for weakly imported spinlock API. */ + if (pthread_once(&spinLockLockInitControl, SpinLockLockInit)) { - Tcl_Panic("Tcl_InitNotifier: %s", "pthread_once failed"); + Tcl_Panic("Tcl_InitNotifier: pthread_once failed"); } #endif @@ -649,8 +461,7 @@ TclpInitNotifier(void) runLoopSource = CFRunLoopSourceCreate(NULL, LONG_MIN, &runLoopSourceContext); if (!runLoopSource) { - Tcl_Panic("Tcl_InitNotifier: %s", - "could not create CFRunLoopSource"); + Tcl_Panic("Tcl_InitNotifier: could not create CFRunLoopSource"); } CFRunLoopAddSource(runLoop, runLoopSource, kCFRunLoopCommonModes); CFRunLoopAddSource(runLoop, runLoopSource, tclEventsOnlyRunLoopMode); @@ -658,12 +469,12 @@ TclpInitNotifier(void) bzero(&runLoopObserverContext, sizeof(CFRunLoopObserverContext)); runLoopObserverContext.info = tsdPtr; runLoopObserver = CFRunLoopObserverCreate(NULL, - kCFRunLoopEntry|kCFRunLoopExit, TRUE, + kCFRunLoopEntry|kCFRunLoopExit|kCFRunLoopBeforeWaiting, TRUE, LONG_MIN, UpdateWaitingListAndServiceEvents, &runLoopObserverContext); if (!runLoopObserver) { - Tcl_Panic("Tcl_InitNotifier: %s", - "could not create CFRunLoopObserver"); + Tcl_Panic("Tcl_InitNotifier: could not create " + "CFRunLoopObserver"); } CFRunLoopAddObserver(runLoop, runLoopObserver, kCFRunLoopCommonModes); @@ -676,12 +487,12 @@ TclpInitNotifier(void) */ runLoopObserverTcl = CFRunLoopObserverCreate(NULL, - kCFRunLoopEntry|kCFRunLoopExit, TRUE, + kCFRunLoopEntry|kCFRunLoopExit|kCFRunLoopBeforeWaiting, TRUE, LONG_MIN, UpdateWaitingListAndServiceEvents, &runLoopObserverContext); if (!runLoopObserverTcl) { - Tcl_Panic("Tcl_InitNotifier: %s", - "could not create CFRunLoopObserver"); + Tcl_Panic("Tcl_InitNotifier: could not create " + "CFRunLoopObserver"); } CFRunLoopAddObserver(runLoop, runLoopObserverTcl, tclEventsOnlyRunLoopMode); @@ -692,11 +503,7 @@ TclpInitNotifier(void) tsdPtr->runLoopObserverTcl = runLoopObserverTcl; tsdPtr->runLoopTimer = NULL; tsdPtr->waitTime = CF_TIMEINTERVAL_FOREVER; -#if defined(USE_OS_UNFAIR_LOCK) - tsdPtr->tsdLock = OS_UNFAIR_LOCK_INIT; -#else tsdPtr->tsdLock = SPINLOCK_INIT; -#endif } LOCK_NOTIFIER_INIT; @@ -706,15 +513,19 @@ TclpInitNotifier(void) * child of a fork. */ - if (MayUsePthreadAtfork() && !atForkInit) { + if ( +#ifdef WEAK_IMPORT_PTHREAD_ATFORK + pthread_atfork != NULL && +#endif + !atForkInit) { int result = pthread_atfork(AtForkPrepare, AtForkParent, AtForkChild); if (result) { - Tcl_Panic("Tcl_InitNotifier: %s", "pthread_atfork failed"); + Tcl_Panic("Tcl_InitNotifier: pthread_atfork failed"); } atForkInit = 1; } -#endif /* HAVE_PTHREAD_ATFORK */ +#endif if (notifierCount == 0) { int fds[2], status; @@ -723,20 +534,20 @@ TclpInitNotifier(void) */ if (pipe(fds) != 0) { - Tcl_Panic("Tcl_InitNotifier: %s", "could not create trigger pipe"); + Tcl_Panic("Tcl_InitNotifier: could not create trigger pipe"); } status = fcntl(fds[0], F_GETFL); status |= O_NONBLOCK; if (fcntl(fds[0], F_SETFL, status) < 0) { - Tcl_Panic("Tcl_InitNotifier: %s", - "could not make receive pipe non-blocking"); + Tcl_Panic("Tcl_InitNotifier: could not make receive pipe non " + "blocking"); } status = fcntl(fds[1], F_GETFL); status |= O_NONBLOCK; if (fcntl(fds[1], F_SETFL, status) < 0) { - Tcl_Panic("Tcl_InitNotifier: %s", - "could not make trigger pipe non-blocking"); + Tcl_Panic("Tcl_InitNotifier: could not make trigger pipe non " + "blocking"); } receivePipe = fds[0]; @@ -754,13 +565,14 @@ TclpInitNotifier(void) ENABLE_ASL; notifierCount++; UNLOCK_NOTIFIER_INIT; - return tsdPtr; + + return (ClientData) tsdPtr; } /* *---------------------------------------------------------------------- * - * Tcl_MacOSXNotifierAddRunLoopMode -- + * TclMacOSXNotifierAddRunLoopMode -- * * Add the tcl notifier RunLoop source, observer and timer (if any) * to the given RunLoop mode. @@ -775,8 +587,8 @@ TclpInitNotifier(void) */ void -Tcl_MacOSXNotifierAddRunLoopMode( - const void *runLoopMode) +TclMacOSXNotifierAddRunLoopMode( + CONST void *runLoopMode) { ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); CFStringRef mode = (CFStringRef) runLoopMode; @@ -817,32 +629,17 @@ StartNotifierThread(void) int result; pthread_attr_t attr; - /* - * Arrange for the notifier thread to start with all - * signals blocked. In its mainloop it unblocks the - * signals at safe points. - */ - - sigfillset(&allSigMask); - pthread_sigmask(SIG_BLOCK, &allSigMask, ¬ifierSigMask); - pthread_attr_init(&attr); pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); pthread_attr_setstacksize(&attr, 60 * 1024); result = pthread_create(¬ifierThread, &attr, - (void * (*)(void *)) NotifierThreadProc, NULL); + (void * (*)(void *))NotifierThreadProc, NULL); pthread_attr_destroy(&attr); if (result) { Tcl_Panic("StartNotifierThread: unable to start notifier thread"); } notifierThreadRunning = 1; - - /* - * Restore original signal mask. - */ - - pthread_sigmask(SIG_SETMASK, ¬ifierSigMask, NULL); } UNLOCK_NOTIFIER_INIT; } @@ -851,7 +648,7 @@ StartNotifierThread(void) /* *---------------------------------------------------------------------- * - * TclpFinalizeNotifier -- + * Tcl_FinalizeNotifier -- * * This function is called to cleanup the notifier state before a thread * is terminated. @@ -867,10 +664,12 @@ StartNotifierThread(void) */ void -TclpFinalizeNotifier( - TCL_UNUSED(void *)) +Tcl_FinalizeNotifier( + ClientData clientData) /* Not used. */ { - ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); + ThreadSpecificData *tsdPtr; + + tsdPtr = TCL_TSD_INIT(&dataKey); LOCK_NOTIFIER_INIT; notifierCount--; @@ -888,10 +687,10 @@ TclpFinalizeNotifier( * 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] + * 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] */ write(triggerPipe, "q", 1); @@ -905,14 +704,6 @@ TclpFinalizeNotifier( "thread"); } notifierThreadRunning = 0; - - /* - * If async marks are outstanding, perform actions now. - */ - if (asyncPending) { - asyncPending = 0; - TclAsyncMarkFromNotifier(); - } } close(receivePipe); @@ -952,7 +743,7 @@ TclpFinalizeNotifier( /* *---------------------------------------------------------------------- * - * TclpAlertNotifier -- + * Tcl_AlertNotifier -- * * Wake up the specified notifier from any thread. This routine is called * by the platform independent notifier code whenever the Tcl_ThreadAlert @@ -969,10 +760,10 @@ TclpFinalizeNotifier( */ void -TclpAlertNotifier( - void *clientData) +Tcl_AlertNotifier( + ClientData clientData) { - ThreadSpecificData *tsdPtr = (ThreadSpecificData *) clientData; + ThreadSpecificData *tsdPtr = clientData; LOCK_NOTIFIER_TSD; if (tsdPtr->runLoop) { @@ -985,7 +776,7 @@ TclpAlertNotifier( /* *---------------------------------------------------------------------- * - * TclpSetTimer -- + * Tcl_SetTimer -- * * This function sets the current notifier timer value. * @@ -999,23 +790,28 @@ TclpAlertNotifier( */ void -TclpSetTimer( - const Tcl_Time *timePtr) /* Timeout value, may be NULL. */ +Tcl_SetTimer( + Tcl_Time *timePtr) /* Timeout value, may be NULL. */ { ThreadSpecificData *tsdPtr; CFRunLoopTimerRef runLoopTimer; CFTimeInterval waitTime; + if (tclStubs.tcl_SetTimer != tclOriginalNotifier.setTimerProc) { + tclStubs.tcl_SetTimer(timePtr); + return; + } + tsdPtr = TCL_TSD_INIT(&dataKey); runLoopTimer = tsdPtr->runLoopTimer; if (!runLoopTimer) { return; } if (timePtr) { - Tcl_Time vTime = *timePtr; + Tcl_Time vTime = *timePtr; if (vTime.sec != 0 || vTime.usec != 0) { - TclScaleTime(&vTime); + tclScaleTimeProcPtr(&vTime, tclTimeClientData); waitTime = vTime.sec + 1.0e-6 * vTime.usec; } else { waitTime = 0; @@ -1046,15 +842,15 @@ TclpSetTimer( static void TimerWakeUp( - TCL_UNUSED(CFRunLoopTimerRef), - TCL_UNUSED(void *)) + CFRunLoopTimerRef timer, + void *info) { } /* *---------------------------------------------------------------------- * - * TclpServiceModeHook -- + * Tcl_ServiceModeHook -- * * This function is invoked whenever the service mode changes. * @@ -1068,11 +864,13 @@ TimerWakeUp( */ void -TclpServiceModeHook( +Tcl_ServiceModeHook( int mode) /* Either TCL_SERVICE_ALL, or * TCL_SERVICE_NONE. */ { - ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); + ThreadSpecificData *tsdPtr; + + tsdPtr = TCL_TSD_INIT(&dataKey); if (mode == TCL_SERVICE_ALL && !tsdPtr->runLoopTimer) { if (!tsdPtr->runLoop) { @@ -1092,9 +890,9 @@ TclpServiceModeHook( /* *---------------------------------------------------------------------- * - * TclpCreateFileHandler -- + * Tcl_CreateFileHandler -- * - * This function registers a file handler with the notifier. + * This function registers a file handler with the select notifier. * * Results: * None. @@ -1106,7 +904,7 @@ TclpServiceModeHook( */ void -TclpCreateFileHandler( +Tcl_CreateFileHandler( int fd, /* Handle of stream to watch. */ int mask, /* OR'ed combination of TCL_READABLE, * TCL_WRITABLE, and TCL_EXCEPTION: indicates @@ -1114,11 +912,25 @@ TclpCreateFileHandler( * called. */ Tcl_FileProc *proc, /* Function to call for each selected * event. */ - void *clientData) /* Arbitrary data to pass to proc. */ + ClientData clientData) /* Arbitrary data to pass to proc. */ { - ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); - FileHandler *filePtr = LookUpFileHandler(tsdPtr, fd, NULL); + ThreadSpecificData *tsdPtr; + FileHandler *filePtr; + + if (tclStubs.tcl_CreateFileHandler != + tclOriginalNotifier.createFileHandlerProc) { + tclStubs.tcl_CreateFileHandler(fd, mask, proc, clientData); + return; + } + tsdPtr = TCL_TSD_INIT(&dataKey); + + for (filePtr = tsdPtr->firstFileHandlerPtr; filePtr != NULL; + filePtr = filePtr->nextPtr) { + if (filePtr->fd == fd) { + break; + } + } if (filePtr == NULL) { filePtr = (FileHandler *) ckalloc(sizeof(FileHandler)); filePtr->fd = fd; @@ -1136,19 +948,19 @@ TclpCreateFileHandler( LOCK_NOTIFIER_TSD; if (mask & TCL_READABLE) { - FD_SET(fd, &tsdPtr->checkMasks.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); + 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); + 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; @@ -1159,7 +971,7 @@ TclpCreateFileHandler( /* *---------------------------------------------------------------------- * - * TclpDeleteFileHandler -- + * Tcl_DeleteFileHandler -- * * Cancel a previously-arranged callback arrangement for a file. * @@ -1173,34 +985,48 @@ TclpCreateFileHandler( */ void -TclpDeleteFileHandler( +Tcl_DeleteFileHandler( int fd) /* Stream id for which to remove callback * function. */ { FileHandler *filePtr, *prevPtr; - int i, numFdBits = -1; - ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); + int i, numFdBits; + ThreadSpecificData *tsdPtr; + + if (tclStubs.tcl_DeleteFileHandler != + tclOriginalNotifier.deleteFileHandlerProc) { + tclStubs.tcl_DeleteFileHandler(fd); + return; + } + + tsdPtr = TCL_TSD_INIT(&dataKey); + numFdBits = -1; /* * Find the entry for the given file (and return if there isn't one). */ - filePtr = LookUpFileHandler(tsdPtr, fd, &prevPtr); - if (filePtr == NULL) { - return; + for (prevPtr = NULL, filePtr = tsdPtr->firstFileHandlerPtr; ; + prevPtr = filePtr, filePtr = filePtr->nextPtr) { + if (filePtr == NULL) { + return; + } + if (filePtr->fd == fd) { + break; + } } /* * Find current max fd. */ - if (fd + 1 == tsdPtr->numFdBits) { + if (fd+1 == tsdPtr->numFdBits) { 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; + for (i = fd-1; i >= 0; i--) { + if (FD_ISSET(i, &(tsdPtr->checkMasks.readable)) + || FD_ISSET(i, &(tsdPtr->checkMasks.writable)) + || FD_ISSET(i, &(tsdPtr->checkMasks.exceptional))) { + numFdBits = i+1; break; } } @@ -1216,13 +1042,13 @@ TclpDeleteFileHandler( */ 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)); } UNLOCK_NOTIFIER_TSD; @@ -1235,7 +1061,7 @@ TclpDeleteFileHandler( } else { prevPtr->nextPtr = filePtr->nextPtr; } - ckfree(filePtr); + ckfree((char *) filePtr); } /* @@ -1283,8 +1109,12 @@ FileHandlerEventProc( */ tsdPtr = TCL_TSD_INIT(&dataKey); - filePtr = LookUpFileHandler(tsdPtr, fileEvPtr->fd, NULL); - if (filePtr != NULL) { + for (filePtr = tsdPtr->firstFileHandlerPtr; filePtr != NULL; + 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 @@ -1302,17 +1132,18 @@ FileHandlerEventProc( if (mask != 0) { LOCK_NOTIFIER_TSD; if (mask & TCL_READABLE) { - FD_CLR(filePtr->fd, &tsdPtr->readyMasks.readable); + FD_CLR(filePtr->fd, &(tsdPtr->readyMasks.readable)); } if (mask & TCL_WRITABLE) { - FD_CLR(filePtr->fd, &tsdPtr->readyMasks.writable); + FD_CLR(filePtr->fd, &(tsdPtr->readyMasks.writable)); } if (mask & TCL_EXCEPTION) { - FD_CLR(filePtr->fd, &tsdPtr->readyMasks.exceptional); + FD_CLR(filePtr->fd, &(tsdPtr->readyMasks.exceptional)); } UNLOCK_NOTIFIER_TSD; filePtr->proc(filePtr->clientData, mask); } + break; } return 1; } @@ -1320,37 +1151,14 @@ FileHandlerEventProc( /* *---------------------------------------------------------------------- * - * TclpNotifierData -- - * - * This function returns a void pointer to be associated - * with a Tcl_AsyncHandler. - * - * Results: - * On MacOSX, returns always NULL. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -void * -TclpNotifierData(void) -{ - return NULL; -} - -/* - *---------------------------------------------------------------------- - * - * TclpWaitForEvent -- + * 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. * * Results: - * Returns 0 if a tcl event or timeout occurred and 1 if a non-tcl + * Returns 0 if a tcl event or timeout ocurred and 1 if a non-tcl * CFRunLoop source was processed. * * Side effects: @@ -1360,14 +1168,17 @@ TclpNotifierData(void) */ int -TclpWaitForEvent( - const Tcl_Time *timePtr) /* Maximum block time, or NULL. */ +Tcl_WaitForEvent( + Tcl_Time *timePtr) /* Maximum block time, or NULL. */ { int result, polling, runLoopRunning; CFTimeInterval waitTime; SInt32 runLoopStatus; ThreadSpecificData *tsdPtr; + if (tclStubs.tcl_WaitForEvent != tclOriginalNotifier.waitForEventProc) { + return tclStubs.tcl_WaitForEvent(timePtr); + } result = -1; polling = 0; waitTime = CF_TIMEINTERVAL_FOREVER; @@ -1377,12 +1188,8 @@ TclpWaitForEvent( Tcl_Panic("Tcl_WaitForEvent: Notifier not initialized"); } - /* - * A NULL timePtr means wait forever. - */ - if (timePtr) { - Tcl_Time vTime = *timePtr; + Tcl_Time vTime = *timePtr; /* * TIP #233 (Virtualized Time). Is virtual time in effect? And do we @@ -1391,25 +1198,17 @@ TclpWaitForEvent( */ if (vTime.sec != 0 || vTime.usec != 0) { - TclScaleTime(&vTime); + tclScaleTimeProcPtr(&vTime, tclTimeClientData); waitTime = vTime.sec + 1.0e-6 * vTime.usec; } else { /* - * The max block time was set to 0. - * - * If we set the waitTime to 0, then the call to CFRunLoopInMode - * may return without processing all of its sources. The Apple - * documentation says that if the waitTime is 0 "only one pass is - * made through the run loop before returning; if multiple sources - * or timers are ready to fire immediately, only one (possibly two - * if one is a version 0 source) will be fired, regardless of the - * value of returnAfterSourceHandled." This can cause some chanio - * tests to fail. So we use a small positive waitTime unless - * there is another RunLoop running. + * Polling: 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. */ polling = 1; - waitTime = tsdPtr->runLoopRunning ? 0 : 0.0001; } } @@ -1422,18 +1221,18 @@ TclpWaitForEvent( /* * If the Tcl runloop is already running (e.g. if Tcl_WaitForEvent was - * called recursively) start a new runloop in a custom runloop mode - * containing only the source for the notifier thread. Otherwise wakeups - * from other sources added to the common runloop mode might get lost or - * 3rd party event handlers might get called when they do not expect to - * be. + * called recursively) or is servicing events via the runloop observer, + * re-run it in a custom runloop mode containing only the source for the + * notifier thread, otherwise wakeups from other sources added to the + * common runloop modes might get lost or 3rd party event handlers might + * get called when they do not expect to be. */ runLoopRunning = tsdPtr->runLoopRunning; tsdPtr->runLoopRunning = 1; - runLoopStatus = CFRunLoopRunInMode( - runLoopRunning ? tclEventsOnlyRunLoopMode : kCFRunLoopDefaultMode, - waitTime, TRUE); + runLoopStatus = CFRunLoopRunInMode(tsdPtr->runLoopServicingEvents || + runLoopRunning ? tclEventsOnlyRunLoopMode : kCFRunLoopDefaultMode, + waitTime, TRUE); tsdPtr->runLoopRunning = runLoopRunning; LOCK_NOTIFIER_TSD; @@ -1441,7 +1240,7 @@ TclpWaitForEvent( UNLOCK_NOTIFIER_TSD; switch (runLoopStatus) { case kCFRunLoopRunFinished: - Tcl_Panic("Tcl_WaitForEvent: CFRunLoop finished"); + Tcl_Panic("Tcl_WaitForEvent: CFRunLoop finished"); break; case kCFRunLoopRunTimedOut: QueueFileEvents(tsdPtr); @@ -1485,12 +1284,12 @@ QueueFileEvents( */ LOCK_NOTIFIER_TSD; - FD_COPY(&tsdPtr->readyMasks.readable, &readyMasks.readable); - FD_COPY(&tsdPtr->readyMasks.writable, &readyMasks.writable); - FD_COPY(&tsdPtr->readyMasks.exceptional, &readyMasks.exceptional); - FD_ZERO(&tsdPtr->readyMasks.readable); - FD_ZERO(&tsdPtr->readyMasks.writable); - FD_ZERO(&tsdPtr->readyMasks.exceptional); + FD_COPY(&(tsdPtr->readyMasks.readable), &readyMasks.readable); + FD_COPY(&(tsdPtr->readyMasks.writable), &readyMasks.writable); + FD_COPY(&(tsdPtr->readyMasks.exceptional), &readyMasks.exceptional); + FD_ZERO(&(tsdPtr->readyMasks.readable)); + FD_ZERO(&(tsdPtr->readyMasks.writable)); + FD_ZERO(&(tsdPtr->readyMasks.exceptional)); UNLOCK_NOTIFIER_TSD; tsdPtr->runLoopSourcePerformed = 1; @@ -1519,7 +1318,6 @@ QueueFileEvents( if (filePtr->readyMask == 0) { FileHandlerEvent *fileEvPtr = (FileHandlerEvent *) ckalloc(sizeof(FileHandlerEvent)); - fileEvPtr->header.proc = FileHandlerEventProc; fileEvPtr->fd = filePtr->fd; Tcl_QueueEvent((Tcl_Event *) fileEvPtr, TCL_QUEUE_TAIL); @@ -1533,8 +1331,8 @@ QueueFileEvents( * * UpdateWaitingListAndServiceEvents -- * - * CFRunLoopObserver callback for updating waitingList and servicing Tcl - * events. + * CFRunLoopObserver callback for updating waitingList and + * servicing Tcl events. * * Results: * None. @@ -1547,11 +1345,11 @@ QueueFileEvents( static void UpdateWaitingListAndServiceEvents( - TCL_UNUSED(CFRunLoopObserverRef), + CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info) { - ThreadSpecificData *tsdPtr = (ThreadSpecificData *) info; + ThreadSpecificData *tsdPtr = (ThreadSpecificData*) info; if (tsdPtr->sleeping) { return; @@ -1562,7 +1360,7 @@ UpdateWaitingListAndServiceEvents( if (tsdPtr->numFdBits > 0 || tsdPtr->polling) { LOCK_NOTIFIER; if (!OnOffWaitingList(tsdPtr, 1, 1) && tsdPtr->polling) { - write(triggerPipe, "", 1); + write(triggerPipe, "", 1); } UNLOCK_NOTIFIER; } @@ -1575,6 +1373,15 @@ UpdateWaitingListAndServiceEvents( } tsdPtr->runLoopNestingLevel--; break; + case kCFRunLoopBeforeWaiting: + if (tsdPtr->runLoopTimer && !tsdPtr->runLoopServicingEvents && + (tsdPtr->runLoopNestingLevel > 1 || !tsdPtr->runLoopRunning)) { + tsdPtr->runLoopServicingEvents = 1; + /* This call seems to simply force event processing through and prevents hangups that have long been observed with Tk-Cocoa. */ + Tcl_ServiceAll(); + tsdPtr->runLoopServicingEvents = 0; + } + break; default: break; } @@ -1585,8 +1392,8 @@ UpdateWaitingListAndServiceEvents( * * OnOffWaitingList -- * - * Add/remove the specified thread to/from the global waitingList and - * optionally signal the notifier. + * Add/remove the specified thread to/from the global waitingList + * and optionally signal the notifier. * * !!! Requires notifierLock to be held !!! * @@ -1606,9 +1413,8 @@ OnOffWaitingList( int signalNotifier) { int changeWaitingList; - -#if defined(TCL_MAC_DEBUG_NOTIFIER) && !defined(USE_OS_UNFAIR_LOCK) - if (SpinLockTry(¬ifierLock)) { +#ifdef TCL_MAC_DEBUG_NOTIFIER + if(SpinLockTry(¬ifierLock)) { Tcl_Panic("OnOffWaitingList: notifierLock unlocked"); } #endif @@ -1635,7 +1441,7 @@ OnOffWaitingList( tsdPtr->onList = 0; } if (signalNotifier) { - write(triggerPipe, "", 1); + write(triggerPipe, "", 1); } } @@ -1673,9 +1479,10 @@ Tcl_Sleep( * TIP #233: Scale from virtual time to real-time. */ - vdelay.sec = ms / 1000; + vdelay.sec = ms / 1000; vdelay.usec = (ms % 1000) * 1000; - TclScaleTime(&vdelay); + tclScaleTimeProcPtr(&vdelay, tclTimeClientData); + if (tsdPtr->runLoop) { CFTimeInterval waitTime; @@ -1698,8 +1505,8 @@ Tcl_Sleep( } tsdPtr->sleeping = 1; do { - runLoopStatus = CFRunLoopRunInMode(kCFRunLoopDefaultMode, - waitTime, FALSE); + runLoopStatus = CFRunLoopRunInMode(kCFRunLoopDefaultMode, waitTime, + FALSE); switch (runLoopStatus) { case kCFRunLoopRunFinished: Tcl_Panic("Tcl_Sleep: CFRunLoop finished"); @@ -1835,10 +1642,10 @@ TclUnixWaitForFile( * Setup the select masks for the fd. */ - if (mask & TCL_READABLE) { + if (mask & TCL_READABLE) { FD_SET(fd, &readableMask); } - if (mask & TCL_WRITABLE) { + if (mask & TCL_WRITABLE) { FD_SET(fd, &writableMask); } if (mask & TCL_EXCEPTION) { @@ -1852,10 +1659,10 @@ TclUnixWaitForFile( numFound = select(fd + 1, &readableMask, &writableMask, &exceptionalMask, timeoutPtr); if (numFound == 1) { - if (FD_ISSET(fd, &readableMask)) { + if (FD_ISSET(fd, &readableMask)) { SET_BITS(result, TCL_READABLE); } - if (FD_ISSET(fd, &writableMask)) { + if (FD_ISSET(fd, &writableMask)) { SET_BITS(result, TCL_WRITABLE); } if (FD_ISSET(fd, &exceptionalMask)) { @@ -1889,61 +1696,6 @@ TclUnixWaitForFile( /* *---------------------------------------------------------------------- * - * TclAsyncNotifier -- - * - * This procedure sets the async mark of an async handler to a - * given value, if it is called from the notifier thread. - * - * Result: - * True, when the handler will be marked, false otherwise. - * - * Side effetcs: - * The trigger pipe is written when called from the notifier - * thread. - * - *---------------------------------------------------------------------- - */ - -int -TclAsyncNotifier( - int sigNumber, /* Signal number. */ - TCL_UNUSED(Tcl_ThreadId), /* Target thread. */ - TCL_UNUSED(void *), /* Notifier data. */ - int *flagPtr, /* Flag to mark. */ - int value) /* Value of mark. */ -{ -#if TCL_THREADS - /* - * WARNING: - * This code most likely runs in a signal handler. Thus, - * only few async-signal-safe system calls are allowed, - * e.g. pthread_self(), sem_post(), write(). - */ - - if (pthread_equal(pthread_self(), (pthread_t) notifierThread)) { - if (notifierThreadRunning) { - *flagPtr = value; - if (!asyncPending) { - asyncPending = 1; - write(triggerPipe, "S", 1); - } - return 1; - } - return 0; - } - - /* - * Re-send the signal to the notifier thread. - */ - - pthread_kill((pthread_t) notifierThread, sigNumber); -#endif - return 0; -} - -/* - *---------------------------------------------------------------------- - * * NotifierThreadProc -- * * This routine is the initial (and only) function executed by the @@ -1956,7 +1708,7 @@ TclAsyncNotifier( * * Result: * None. Once started, this routine never exits. It dies with the overall - * process or terminates its own thread (on notifier termination). + * process. * * Side effects: * The trigger pipe used to signal the notifier thread is created when @@ -1965,13 +1717,13 @@ TclAsyncNotifier( *---------------------------------------------------------------------- */ -static TCL_NORETURN void +static void NotifierThreadProc( - TCL_UNUSED(void *)) + ClientData clientData) /* Not used. */ { ThreadSpecificData *tsdPtr; fd_set readableMask, writableMask, exceptionalMask; - int i, ret, numFdBits = 0, polling; + int i, numFdBits = 0, polling; struct timeval poll = {0., 0.}, *timePtr; char buf[2]; @@ -1994,13 +1746,13 @@ NotifierThreadProc( for (tsdPtr = waitingListPtr; tsdPtr; tsdPtr = tsdPtr->nextPtr) { LOCK_NOTIFIER_TSD; for (i = tsdPtr->numFdBits-1; i >= 0; --i) { - if (FD_ISSET(i, &tsdPtr->checkMasks.readable)) { + if (FD_ISSET(i, &(tsdPtr->checkMasks.readable))) { FD_SET(i, &readableMask); } - if (FD_ISSET(i, &tsdPtr->checkMasks.writable)) { + if (FD_ISSET(i, &(tsdPtr->checkMasks.writable))) { FD_SET(i, &writableMask); } - if (FD_ISSET(i, &tsdPtr->checkMasks.exceptional)) { + if (FD_ISSET(i, &(tsdPtr->checkMasks.exceptional))) { FD_SET(i, &exceptionalMask); } } @@ -2024,25 +1776,8 @@ NotifierThreadProc( } FD_SET(receivePipe, &readableMask); - /* - * Signals are unblocked only during select(). - */ - - pthread_sigmask(SIG_SETMASK, ¬ifierSigMask, NULL); - ret = select(numFdBits, &readableMask, &writableMask, &exceptionalMask, - timePtr); - pthread_sigmask(SIG_BLOCK, &allSigMask, NULL); - - if (ret == -1) { - /* - * In case a signal was caught during select(), - * perform work on async handlers now. - */ - if (errno == EINTR && asyncPending) { - asyncPending = 0; - TclAsyncMarkFromNotifier(); - } - + if (select(numFdBits, &readableMask, &writableMask, &exceptionalMask, + timePtr) == -1) { /* * Try again immediately on an error. */ @@ -2060,9 +1795,9 @@ NotifierThreadProc( SelectMasks readyMasks, checkMasks; LOCK_NOTIFIER_TSD; - FD_COPY(&tsdPtr->checkMasks.readable, &checkMasks.readable); - FD_COPY(&tsdPtr->checkMasks.writable, &checkMasks.writable); - FD_COPY(&tsdPtr->checkMasks.exceptional, &checkMasks.exceptional); + FD_COPY(&(tsdPtr->checkMasks.readable), &checkMasks.readable); + FD_COPY(&(tsdPtr->checkMasks.writable), &checkMasks.writable); + FD_COPY(&(tsdPtr->checkMasks.exceptional), &checkMasks.exceptional); UNLOCK_NOTIFIER_TSD; found = tsdPtr->polled; FD_ZERO(&readyMasks.readable); @@ -2098,10 +1833,9 @@ NotifierThreadProc( OnOffWaitingList(tsdPtr, 0, 0); LOCK_NOTIFIER_TSD; - FD_COPY(&readyMasks.readable, &tsdPtr->readyMasks.readable); - FD_COPY(&readyMasks.writable, &tsdPtr->readyMasks.writable); - FD_COPY(&readyMasks.exceptional, - &tsdPtr->readyMasks.exceptional); + FD_COPY(&readyMasks.readable, &(tsdPtr->readyMasks.readable)); + FD_COPY(&readyMasks.writable, &(tsdPtr->readyMasks.writable)); + FD_COPY(&readyMasks.exceptional, &(tsdPtr->readyMasks.exceptional)); UNLOCK_NOTIFIER_TSD; tsdPtr->polled = 0; if (tsdPtr->runLoop) { @@ -2130,11 +1864,6 @@ NotifierThreadProc( break; } - - if (asyncPending) { - asyncPending = 0; - TclAsyncMarkFromNotifier(); - } } } pthread_exit(0); @@ -2214,24 +1943,9 @@ AtForkChild(void) { ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); - /* - * If a child process unlocks an os_unfair_lock that was created in its - * parent the child will exit with an illegal instruction error. So we - * reinitialize the lock in the child rather than attempt to unlock it. - */ - -#if defined(USE_OS_UNFAIR_LOCK) - notifierInitLock = OS_UNFAIR_LOCK_INIT; - notifierLock = OS_UNFAIR_LOCK_INIT; - tsdPtr->tsdLock = OS_UNFAIR_LOCK_INIT; -#else UNLOCK_NOTIFIER_TSD; UNLOCK_NOTIFIER; UNLOCK_NOTIFIER_INIT; -#endif - - asyncPending = 0; - if (tsdPtr->runLoop) { tsdPtr->runLoop = NULL; if (!noCFafterFork) { @@ -2261,12 +1975,6 @@ AtForkChild(void) if (!noCFafterFork) { Tcl_InitNotifier(); } - - /* - * Restart the notifier thread for signal handling. - */ - - StartNotifierThread(); } } #endif /* HAVE_PTHREAD_ATFORK */ @@ -2274,10 +1982,10 @@ AtForkChild(void) #else /* HAVE_COREFOUNDATION */ void -Tcl_MacOSXNotifierAddRunLoopMode( - const void *runLoopMode) +TclMacOSXNotifierAddRunLoopMode( + CONST void *runLoopMode) { - Tcl_Panic("Tcl_MacOSXNotifierAddRunLoopMode: " + Tcl_Panic("TclMacOSXNotifierAddRunLoopMode: " "Tcl not built with CoreFoundation support"); } |
