diff options
Diffstat (limited to 'unix/tclKqueueNotfy.c')
-rw-r--r-- | unix/tclKqueueNotfy.c | 71 |
1 files changed, 65 insertions, 6 deletions
diff --git a/unix/tclKqueueNotfy.c b/unix/tclKqueueNotfy.c index c0b9f6f..872f71c 100644 --- a/unix/tclKqueueNotfy.c +++ b/unix/tclKqueueNotfy.c @@ -102,6 +102,7 @@ typedef struct ThreadSpecificData { struct kevent *readyEvents; /* Pointer to at most maxReadyEvents events * returned by kevent(2). */ size_t maxReadyEvents; /* Count of kevents in readyEvents. */ + int asyncPending; /* True when signal triggered thread. */ } ThreadSpecificData; static Tcl_ThreadDataKey dataKey; @@ -165,11 +166,11 @@ PlatformEventsControl( Tcl_StatBuf fdStat; if (isNew) { - newPedPtr = (struct PlatformEventData *) + newPedPtr = (struct PlatformEventData *) ckalloc(sizeof(struct PlatformEventData)); - newPedPtr->filePtr = filePtr; - newPedPtr->tsdPtr = tsdPtr; - filePtr->pedPtr = newPedPtr; + newPedPtr->filePtr = filePtr; + newPedPtr->tsdPtr = tsdPtr; + filePtr->pedPtr = newPedPtr; } /* @@ -213,7 +214,7 @@ PlatformEventsControl( EVFILT_WRITE, op, 0, 0, filePtr->pedPtr); numChanges++; } - if (numChanges) { + if (numChanges) { if (kevent(tsdPtr->eventsFd, changeList, numChanges, NULL, 0, NULL) == -1) { Tcl_Panic("kevent: %s", strerror(errno)); @@ -363,7 +364,7 @@ TclpInitNotifier(void) filePtr->mask = TCL_READABLE; PlatformEventsControl(filePtr, tsdPtr, EV_ADD, 1); if (!tsdPtr->readyEvents) { - tsdPtr->maxReadyEvents = 512; + tsdPtr->maxReadyEvents = 512; tsdPtr->readyEvents = (struct kevent *) ckalloc( tsdPtr->maxReadyEvents * sizeof(tsdPtr->readyEvents[0])); } @@ -483,6 +484,10 @@ PlatformEventsWait( timePtr->tv_usec = 0; } } + if (tsdPtr->asyncPending) { + tsdPtr->asyncPending = 0; + TclAsyncMarkFromNotifier(); + } return numFound; } @@ -761,6 +766,60 @@ TclpWaitForEvent( return 0; } +/* + *---------------------------------------------------------------------- + * + * TclAsyncNotifier -- + * + * This procedure sets the async mark of an async handler to a + * given value, if it is called from the target thread. + * + * Result: + * True, when the handler will be marked, false otherwise. + * + * Side effects: + * The signal may be resent to the target thread. + * + *---------------------------------------------------------------------- + */ + +int +TclAsyncNotifier( + int sigNumber, /* Signal number. */ + Tcl_ThreadId threadId, /* Target thread. */ + ClientData clientData, /* Notifier data. */ + int *flagPtr, /* Flag to mark. */ + int value) /* Value of mark. */ +{ +#ifdef 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) threadId)) { + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) clientData; + + *flagPtr = value; + if (tsdPtr != NULL && !tsdPtr->asyncPending) { + tsdPtr->asyncPending = 1; + TclpAlertNotifier(tsdPtr); + return 1; + } + return 0; + } + + /* + * Re-send the signal to the proper target thread. + */ + + pthread_kill((pthread_t) threadId, sigNumber); +#endif + return 0; +} + #endif /* NOTIFIER_KQUEUE && TCL_THREADS */ #else TCL_MAC_EMPTY_FILE(unix_tclKqueueNotfy_c) |