summaryrefslogtreecommitdiffstats
path: root/macosx/tclMacOSXNotify.c
diff options
context:
space:
mode:
Diffstat (limited to 'macosx/tclMacOSXNotify.c')
-rw-r--r--macosx/tclMacOSXNotify.c930
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(&notifierInitLock)
-#define UNLOCK_NOTIFIER_INIT os_unfair_lock_unlock(&notifierInitLock)
-#define LOCK_NOTIFIER os_unfair_lock_lock(&notifierLock)
-#define UNLOCK_NOTIFIER os_unfair_lock_unlock(&notifierLock)
-#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(&notifierInitLock)
#define UNLOCK_NOTIFIER_INIT SpinLockUnlock(&notifierInitLock)
#define LOCK_NOTIFIER SpinLockLock(&notifierLock)
#define UNLOCK_NOTIFIER SpinLockUnlock(&notifierLock)
#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(&notifierInitLock)
#undef LOCK_NOTIFIER
#define LOCK_NOTIFIER SpinLockLockDbg(&notifierLock)
#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, &notifierSigMask);
-
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(&notifierThread, &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, &notifierSigMask, 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(&notifierLock)) {
+#ifdef TCL_MAC_DEBUG_NOTIFIER
+ if(SpinLockTry(&notifierLock)) {
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, &notifierSigMask, 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");
}