summaryrefslogtreecommitdiffstats
path: root/unix/tclKqueueNotfy.c
diff options
context:
space:
mode:
Diffstat (limited to 'unix/tclKqueueNotfy.c')
-rw-r--r--unix/tclKqueueNotfy.c840
1 files changed, 0 insertions, 840 deletions
diff --git a/unix/tclKqueueNotfy.c b/unix/tclKqueueNotfy.c
deleted file mode 100644
index 627fa6e..0000000
--- a/unix/tclKqueueNotfy.c
+++ /dev/null
@@ -1,840 +0,0 @@
-/*
- * tclKqueueNotfy.c --
- *
- * This file contains the implementation of the kqueue()-based
- * DragonFly/Free/Net/OpenBSD-specific 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 © 2016 Lucio Andrés Illanes Albornoz <l.illanes@gmx.de>
- *
- * See the file "license.terms" for information on usage and redistribution
- * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
- */
-
-#include "tclInt.h"
-#ifndef HAVE_COREFOUNDATION /* Darwin/Mac OS X CoreFoundation notifier is
- * in tclMacOSXNotify.c */
-#if defined(NOTIFIER_KQUEUE) && TCL_THREADS
-
-#include <signal.h>
-#include <sys/types.h>
-#include <sys/event.h>
-#include <sys/queue.h>
-#include <sys/time.h>
-
-/*
- * This structure is used to keep track of the notifier info for a registered
- * file.
- */
-
-struct PlatformEventData;
-typedef struct FileHandler {
- int fd; /* File descriptor that this is describing a
- * handler for. */
- int mask; /* Mask of desired events: TCL_READABLE,
- * etc. */
- int readyMask; /* Mask of events that have been seen since
- * the last time file handlers were invoked
- * for this file. */
- Tcl_FileProc *proc; /* Function to call, in the style of
- * Tcl_CreateFileHandler. */
- void *clientData; /* Argument to pass to proc. */
- struct FileHandler *nextPtr;/* Next in list of all files we care about. */
- LIST_ENTRY(FileHandler) readyNode;
- /* Next/previous in list of FileHandlers asso-
- * ciated with regular files (S_IFREG) that are
- * ready for I/O. */
- struct PlatformEventData *pedPtr;
- /* Pointer to PlatformEventData associating this
- * FileHandler with kevent(2) events. */
-} FileHandler;
-
-/*
- * The following structure associates a FileHandler and the thread that owns
- * it with the file descriptors of interest and their event masks passed to
- * kevent(2) and their corresponding event(s) returned by kevent(2).
- */
-
-struct ThreadSpecificData;
-struct PlatformEventData {
- FileHandler *filePtr;
- struct ThreadSpecificData *tsdPtr;
-};
-
-/*
- * The following structure is what is added to the Tcl event queue when file
- * handlers are ready to fire.
- */
-
-typedef struct {
- Tcl_Event header; /* Information that is standard for all
- * events. */
- int fd; /* File descriptor that is ready. Used to find
- * the FileHandler structure for the file
- * (can't point directly to the FileHandler
- * structure because it could go away while
- * the event is queued). */
-} FileHandlerEvent;
-
-/*
- * The following static structure contains the state information for the
- * kqueue based implementation of the Tcl notifier. One of these structures is
- * created for each thread that is using the notifier.
- */
-
-LIST_HEAD(PlatformReadyFileHandlerList, FileHandler);
-typedef struct ThreadSpecificData {
- FileHandler *firstFileHandlerPtr;
- /* Pointer to head of file handler list. */
- struct PlatformReadyFileHandlerList firstReadyFileHandlerPtr;
- /* Pointer to head of list of FileHandlers
- * associated with regular files (S_IFREG)
- * that are ready for I/O. */
- pthread_mutex_t notifierMutex;
- /* Mutex protecting notifier termination in
- * TclpFinalizeNotifier. */
- int triggerPipe[2]; /* pipe(2) used by other threads to wake
- * up this thread for inter-thread IPC. */
- int eventsFd; /* kqueue(2) file descriptor used to wait for
- * fds. */
- 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;
-
-/*
- * Forward declarations of internal functions.
- */
-
-static void PlatformEventsControl(FileHandler *filePtr,
- ThreadSpecificData *tsdPtr, int op, int isNew);
-static int PlatformEventsTranslate(struct kevent *eventPtr);
-static int PlatformEventsWait(struct kevent *events,
- size_t numEvents, struct timeval *timePtr);
-
-/*
- * Incorporate the base notifier implementation.
- */
-
-#include "tclUnixNotfy.c"
-
-/*
- *----------------------------------------------------------------------
- *
- * PlatformEventsControl --
- *
- * This function registers interest for the file descriptor and the mask
- * of TCL_* bits associated with filePtr on the kqueue file descriptor
- * associated with tsdPtr.
- *
- * Future calls to kevent will return filePtr and tsdPtr alongside with
- * the event registered here via the PlatformEventData struct.
- *
- * Results:
- * None.
- *
- * Side effects:
- * - If adding a new file descriptor, a PlatformEventData struct will be
- * allocated and associated with filePtr.
- * - fstat is called on the file descriptor; if it is associated with
- * a regular file (S_IFREG,) filePtr is considered to be ready for I/O
- * and added to or deleted from the corresponding list in tsdPtr.
- * - If it is not associated with a regular file, the file descriptor is
- * added, modified concerning its mask of events of interest, or
- * deleted from the epoll file descriptor of the calling thread.
- * - If deleting a file descriptor, kevent(2) is called twice specifying
- * EVFILT_READ first and then EVFILT_WRITE (see note below.)
- *
- *----------------------------------------------------------------------
- */
-
-static void
-PlatformEventsControl(
- FileHandler *filePtr,
- ThreadSpecificData *tsdPtr,
- int op,
- int isNew)
-{
- int numChanges;
- struct kevent changeList[2];
- struct PlatformEventData *newPedPtr;
- Tcl_StatBuf fdStat;
-
- if (isNew) {
- newPedPtr = (struct PlatformEventData *)
- ckalloc(sizeof(struct PlatformEventData));
- newPedPtr->filePtr = filePtr;
- newPedPtr->tsdPtr = tsdPtr;
- filePtr->pedPtr = newPedPtr;
- }
-
- /*
- * N.B. As discussed in Tcl_WaitForEvent(), kqueue(2) does not reproduce
- * the `always ready' {select,poll}(2) behaviour for regular files
- * (S_IFREG) prior to FreeBSD 11.0-RELEASE. Therefore, filePtr is in these
- * cases simply added or deleted from the list of FileHandlers associated
- * with regular files belonging to tsdPtr.
- */
-
- if (TclOSfstat(filePtr->fd, &fdStat) == -1) {
- Tcl_Panic("fstat: %s", strerror(errno));
- } else if ((fdStat.st_mode & S_IFMT) == S_IFREG
- || (fdStat.st_mode & S_IFMT) == S_IFDIR
- || (fdStat.st_mode & S_IFMT) == S_IFLNK
- ) {
- switch (op) {
- case EV_ADD:
- if (isNew) {
- LIST_INSERT_HEAD(&tsdPtr->firstReadyFileHandlerPtr, filePtr,
- readyNode);
- }
- break;
- case EV_DELETE:
- LIST_REMOVE(filePtr, readyNode);
- break;
- }
- return;
- }
-
- numChanges = 0;
- switch (op) {
- case EV_ADD:
- if (filePtr->mask & (TCL_READABLE | TCL_EXCEPTION)) {
- EV_SET(&changeList[numChanges], (uintptr_t) filePtr->fd,
- EVFILT_READ, op, 0, 0, filePtr->pedPtr);
- numChanges++;
- }
- if (filePtr->mask & TCL_WRITABLE) {
- EV_SET(&changeList[numChanges], (uintptr_t) filePtr->fd,
- EVFILT_WRITE, op, 0, 0, filePtr->pedPtr);
- numChanges++;
- }
- if (numChanges) {
- if (kevent(tsdPtr->eventsFd, changeList, numChanges, NULL, 0,
- NULL) == -1) {
- Tcl_Panic("kevent: %s", strerror(errno));
- }
- }
- break;
- case EV_DELETE:
- /*
- * N.B. kqueue(2) has separate filters for readability and writability
- * fd events. We therefore need to ensure that fds are ompletely
- * removed from the kqueue(2) fd when deleting. This is exacerbated
- * by changes to filePtr->mask w/o calls to PlatforEventsControl()
- * after e.g. an exec(3) in a child process.
- *
- * As one of these calls can fail, two separate kevent(2) calls are
- * made for EVFILT_{READ,WRITE}.
- */
- EV_SET(&changeList[0], (uintptr_t) filePtr->fd, EVFILT_READ, op, 0, 0,
- NULL);
- if ((kevent(tsdPtr->eventsFd, changeList, 1, NULL, 0, NULL) == -1)
- && (errno != ENOENT)) {
- Tcl_Panic("kevent: %s", strerror(errno));
- }
- EV_SET(&changeList[0], (uintptr_t) filePtr->fd, EVFILT_WRITE, op, 0, 0,
- NULL);
- if ((kevent(tsdPtr->eventsFd, changeList, 1, NULL, 0, NULL) == -1)
- && (errno != ENOENT)) {
- Tcl_Panic("kevent: %s", strerror(errno));
- }
- break;
- }
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TclpFinalizeNotifier --
- *
- * This function closes the pipe and the kqueue file descriptors and
- * frees the kevent structs owned by the thread of the caller. The above
- * operations are protected by tsdPtr->notifierMutex, which is destroyed
- * thereafter.
- *
- * Results:
- * None.
- *
- * Side effects:
- * While tsdPtr->notifierMutex is held:
- * The per-thread pipe(2) fds are closed, if non-zero, and set to -1.
- * The per-thread kqueue(2) fd is closed, if non-zero, and set to 0.
- * The per-thread kevent structs are freed, if any, and set to 0.
- *
- * tsdPtr->notifierMutex is destroyed.
- *
- *----------------------------------------------------------------------
- */
-
-void
-TclpFinalizeNotifier(
- TCL_UNUSED(void *))
-{
- ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
-
- pthread_mutex_lock(&tsdPtr->notifierMutex);
- if (tsdPtr->triggerPipe[0]) {
- close(tsdPtr->triggerPipe[0]);
- tsdPtr->triggerPipe[0] = -1;
- }
- if (tsdPtr->triggerPipe[1]) {
- close(tsdPtr->triggerPipe[1]);
- tsdPtr->triggerPipe[1] = -1;
- }
- if (tsdPtr->eventsFd > 0) {
- close(tsdPtr->eventsFd);
- tsdPtr->eventsFd = 0;
- }
- if (tsdPtr->readyEvents) {
- ckfree(tsdPtr->readyEvents);
- tsdPtr->maxReadyEvents = 0;
- }
- pthread_mutex_unlock(&tsdPtr->notifierMutex);
- if ((errno = pthread_mutex_destroy(&tsdPtr->notifierMutex))) {
- Tcl_Panic("pthread_mutex_destroy: %s", strerror(errno));
- }
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TclpInitNotifier --
- *
- * Initializes the platform specific notifier state.
- *
- * This function abstracts creating a kqueue fd via the kqueue system
- * call and allocating memory for the kevents structs in tsdPtr for the
- * thread of the caller.
- *
- * Results:
- * Returns a handle to the notifier state for this thread.
- *
- * Side effects:
- * The following per-thread entities are initialised:
- * - notifierMutex is initialised.
- * - The pipe(2) is created; fcntl(2) is called on both fds to set
- * FD_CLOEXEC and O_NONBLOCK.
- * - The kqueue(2) fd is created; fcntl(2) is called on it to set
- * FD_CLOEXEC.
- * - A FileHandler struct is allocated and initialised for the event-
- * fd(2), registering interest for TCL_READABLE on it via Platform-
- * EventsControl().
- * - readyEvents and maxReadyEvents are initialised with 512 kevents.
- *
- *----------------------------------------------------------------------
- */
-
-void *
-TclpInitNotifier(void)
-{
- ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
- int i, fdFl;
- FileHandler *filePtr;
-
- errno = pthread_mutex_init(&tsdPtr->notifierMutex, NULL);
- if (errno) {
- Tcl_Panic("Tcl_InitNotifier: %s", "could not create mutex");
- }
- if (pipe(tsdPtr->triggerPipe) != 0) {
- Tcl_Panic("Tcl_InitNotifier: %s", "could not create trigger pipe");
- } else for (i = 0; i < 2; i++) {
- if (fcntl(tsdPtr->triggerPipe[i], F_SETFD, FD_CLOEXEC) == -1) {
- Tcl_Panic("fcntl: %s", strerror(errno));
- } else {
- fdFl = fcntl(tsdPtr->triggerPipe[i], F_GETFL);
- fdFl |= O_NONBLOCK;
- }
- if (fcntl(tsdPtr->triggerPipe[i], F_SETFL, fdFl) == -1) {
- Tcl_Panic("fcntl: %s", strerror(errno));
- }
- }
- if ((tsdPtr->eventsFd = kqueue()) == -1) {
- Tcl_Panic("kqueue: %s", strerror(errno));
- } else if (fcntl(tsdPtr->eventsFd, F_SETFD, FD_CLOEXEC) == -1) {
- Tcl_Panic("fcntl: %s", strerror(errno));
- }
- filePtr = (FileHandler *) ckalloc(sizeof(FileHandler));
- filePtr->fd = tsdPtr->triggerPipe[0];
- filePtr->mask = TCL_READABLE;
- PlatformEventsControl(filePtr, tsdPtr, EV_ADD, 1);
- if (!tsdPtr->readyEvents) {
- tsdPtr->maxReadyEvents = 512;
- tsdPtr->readyEvents = (struct kevent *) ckalloc(
- tsdPtr->maxReadyEvents * sizeof(tsdPtr->readyEvents[0]));
- }
- LIST_INIT(&tsdPtr->firstReadyFileHandlerPtr);
-
- return tsdPtr;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * PlatformEventsTranslate --
- *
- * This function translates the platform-specific mask of returned
- * events in eventPtr to a mask of TCL_* bits.
- *
- * Results:
- * Returns the translated mask.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-static int
-PlatformEventsTranslate(
- struct kevent *eventPtr)
-{
- int mask;
-
- mask = 0;
- if (eventPtr->filter == EVFILT_READ) {
- mask |= TCL_READABLE;
- if (eventPtr->flags & EV_ERROR) {
- mask |= TCL_EXCEPTION;
- }
- }
- if (eventPtr->filter == EVFILT_WRITE) {
- mask |= TCL_WRITABLE;
- if (eventPtr->flags & EV_ERROR) {
- mask |= TCL_EXCEPTION;
- }
- }
- return mask;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * PlatformEventsWait --
- *
- * This function abstracts waiting for I/O events via the kevent system
- * call.
- *
- * Results:
- * Returns -1 if kevent failed. Returns 0 if polling and if no events
- * became available whilst polling. Returns a pointer to and the count of
- * all returned events in all other cases.
- *
- * Side effects:
- * gettimeofday(2), kevent(2), and gettimeofday(2) are called, in the
- * specified order.
- * If timePtr specifies a positive value, it is updated to reflect the
- * amount of time that has passed; if its value would {under, over}flow,
- * it is set to zero.
- *
- *----------------------------------------------------------------------
- */
-
-static int
-PlatformEventsWait(
- struct kevent *events,
- size_t numEvents,
- struct timeval *timePtr)
-{
- int numFound;
- struct timeval tv0, tv1, tv_delta;
- struct timespec timeout, *timeoutPtr;
-
- ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
-
- /*
- * If timePtr is NULL, kevent(2) will wait indefinitely. If it specifies a
- * timeout of {0,0}, kevent(2) will poll. Otherwise, the timeout will
- * simply be converted to a timespec.
- */
-
- if (!timePtr) {
- timeoutPtr = NULL;
- } else if (!timePtr->tv_sec && !timePtr->tv_usec) {
- timeout.tv_sec = 0;
- timeout.tv_nsec = 0;
- timeoutPtr = &timeout;
- } else {
- timeout.tv_sec = timePtr->tv_sec;
- timeout.tv_nsec = timePtr->tv_usec * 1000;
- timeoutPtr = &timeout;
- }
-
- /*
- * Call (and possibly block on) kevent(2) and substract the delta of
- * gettimeofday(2) before and after the call from timePtr if the latter is
- * not NULL. Return the number of events returned by kevent(2).
- */
-
- gettimeofday(&tv0, NULL);
- numFound = kevent(tsdPtr->eventsFd, NULL, 0, events, (int) numEvents,
- timeoutPtr);
- gettimeofday(&tv1, NULL);
- if (timePtr && (timePtr->tv_sec && timePtr->tv_usec)) {
- timersub(&tv1, &tv0, &tv_delta);
- if (!timercmp(&tv_delta, timePtr, >)) {
- timersub(timePtr, &tv_delta, timePtr);
- } else {
- timePtr->tv_sec = 0;
- timePtr->tv_usec = 0;
- }
- }
- if (tsdPtr->asyncPending) {
- tsdPtr->asyncPending = 0;
- TclAsyncMarkFromNotifier();
- }
- return numFound;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TclpCreateFileHandler --
- *
- * This function registers a file handler with the kqueue notifier
- * of the thread of the caller.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Creates a new file handler structure.
- * PlatformEventsControl() is called for the new file handler structure.
- *
- *----------------------------------------------------------------------
- */
-
-void
-TclpCreateFileHandler(
- int fd, /* Handle of stream to watch. */
- int mask, /* OR'ed combination of TCL_READABLE,
- * TCL_WRITABLE, and TCL_EXCEPTION: indicates
- * conditions under which proc should be
- * called. */
- Tcl_FileProc *proc, /* Function to call for each selected
- * event. */
- void *clientData) /* Arbitrary data to pass to proc. */
-{
- ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
- FileHandler *filePtr = LookUpFileHandler(tsdPtr, fd, NULL);
- int isNew = (filePtr == NULL);
-
- if (isNew) {
- filePtr = (FileHandler *) ckalloc(sizeof(FileHandler));
- filePtr->fd = fd;
- filePtr->readyMask = 0;
- filePtr->nextPtr = tsdPtr->firstFileHandlerPtr;
- tsdPtr->firstFileHandlerPtr = filePtr;
- }
- filePtr->proc = proc;
- filePtr->clientData = clientData;
- filePtr->mask = mask;
-
- PlatformEventsControl(filePtr, tsdPtr, EV_ADD, isNew);
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TclpDeleteFileHandler --
- *
- * Cancel a previously-arranged callback arrangement for a file on the
- * kqueue of the thread of the caller.
- *
- * Results:
- * None.
- *
- * Side effects:
- * If a callback was previously registered on file, remove it.
- * PlatformEventsControl() is called for the file handler structure.
- * The PlatformEventData struct associated with the new file handler
- * structure is freed.
- *
- *----------------------------------------------------------------------
- */
-
-void
-TclpDeleteFileHandler(
- int fd) /* Stream id for which to remove callback
- * function. */
-{
- ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
- FileHandler *filePtr, *prevPtr;
-
- /*
- * Find the entry for the given file (and return if there isn't one).
- */
-
- filePtr = LookUpFileHandler(tsdPtr, fd, &prevPtr);
- if (filePtr == NULL) {
- return;
- }
-
- /*
- * Update the check masks for this file.
- */
-
- PlatformEventsControl(filePtr, tsdPtr, EV_DELETE, 0);
- if (filePtr->pedPtr) {
- ckfree(filePtr->pedPtr);
- }
-
- /*
- * Clean up information in the callback record.
- */
-
- if (prevPtr == NULL) {
- tsdPtr->firstFileHandlerPtr = filePtr->nextPtr;
- } else {
- prevPtr->nextPtr = filePtr->nextPtr;
- }
- ckfree(filePtr);
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TclpWaitForEvent --
- *
- * This function is called by Tcl_DoOneEvent to wait for new events on
- * the message queue. If the block time is 0, then TclpWaitForEvent just
- * polls without blocking.
- *
- * The waiting logic is implemented in PlatformEventsWait.
- *
- * Results:
- * Returns -1 if PlatformEventsWait() would block forever, otherwise
- * returns 0.
- *
- * Side effects:
- * Queues file events that are detected by PlatformEventsWait().
- *
- *----------------------------------------------------------------------
- */
-
-int
-TclpWaitForEvent(
- const Tcl_Time *timePtr) /* Maximum block time, or NULL. */
-{
- FileHandler *filePtr;
- int mask;
- Tcl_Time vTime;
- struct timeval timeout, *timeoutPtr;
- /* Impl. notes: timeout & timeoutPtr are used
- * if, and only if threads are not enabled.
- * They are the arguments for the regular
- * epoll_wait() used when the core is not
- * thread-enabled. */
- int numFound, numEvent;
- struct PlatformEventData *pedPtr;
- ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
- int numQueued;
- ssize_t i;
- char buf[1];
-
- /*
- * Set up the timeout structure. Note that if there are no events to check
- * for, we return with a negative result rather than blocking forever.
- */
-
- if (timePtr != NULL) {
- /*
- * TIP #233 (Virtualized Time). Is virtual time in effect? And do we
- * actually have something to scale? If yes to both then we call the
- * handler to do this scaling.
- */
-
- if (timePtr->sec != 0 || timePtr->usec != 0) {
- vTime = *timePtr;
- TclScaleTime(&vTime);
- timePtr = &vTime;
- }
- timeout.tv_sec = timePtr->sec;
- timeout.tv_usec = timePtr->usec;
- timeoutPtr = &timeout;
- } else {
- timeoutPtr = NULL;
- }
-
- /*
- * Walk the list of FileHandlers associated with regular files (S_IFREG)
- * belonging to tsdPtr, queue Tcl events for them, and update their mask
- * of events of interest.
- *
- * kqueue(2), unlike epoll(7), does support regular files, but EVFILT_READ
- * only `[r]eturns when the file pointer is not at the end of file' as
- * opposed to unconditionally. While FreeBSD 11.0-RELEASE adds support for
- * this mode (NOTE_FILE_POLL,) this is not used for reasons of
- * compatibility.
- *
- * Therefore, the behaviour of {select,poll}(2) is simply simulated here:
- * fds associated with regular files are added to this list by
- * PlatformEventsControl() and processed here before calling (and possibly
- * blocking) on PlatformEventsWait().
- */
-
- numQueued = 0;
- LIST_FOREACH(filePtr, &tsdPtr->firstReadyFileHandlerPtr, readyNode) {
- mask = 0;
- if (filePtr->mask & TCL_READABLE) {
- mask |= TCL_READABLE;
- }
- if (filePtr->mask & TCL_WRITABLE) {
- mask |= TCL_WRITABLE;
- }
-
- /*
- * Don't bother to queue an event if the mask was previously non-zero
- * since an event must still be on the queue.
- */
-
- 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);
- numQueued++;
- }
- filePtr->readyMask = mask;
- }
-
- /*
- * If any events were queued in the above loop, force PlatformEventsWait()
- * to poll as there already are events that need to be processed at this
- * point.
- */
-
- if (numQueued) {
- timeout.tv_sec = 0;
- timeout.tv_usec = 0;
- timeoutPtr = &timeout;
- }
-
- /*
- * Wait or poll for new events, queue Tcl events for the FileHandlers
- * corresponding to them, and update the FileHandlers' mask of events of
- * interest registered by the last call to Tcl_CreateFileHandler().
- *
- * Events for the trigger pipe are processed here in order to facilitate
- * inter-thread IPC. If another thread intends to wake up this thread
- * whilst it's blocking on PlatformEventsWait(), it write(2)s to the other
- * end of the pipe (see Tcl_AlertNotifier(),) which in turn will cause
- * PlatformEventsWait() to return immediately.
- */
-
- numFound = PlatformEventsWait(tsdPtr->readyEvents,
- tsdPtr->maxReadyEvents, timeoutPtr);
- for (numEvent = 0; numEvent < numFound; numEvent++) {
- pedPtr = (struct PlatformEventData *)
- tsdPtr->readyEvents[numEvent].udata;
- filePtr = pedPtr->filePtr;
- mask = PlatformEventsTranslate(&tsdPtr->readyEvents[numEvent]);
- if (filePtr->fd == tsdPtr->triggerPipe[0]) {
- i = read(tsdPtr->triggerPipe[0], buf, 1);
- if ((i == -1) && (errno != EAGAIN)) {
- Tcl_Panic("Tcl_WaitForEvent: read from %p->triggerPipe: %s",
- (void *) tsdPtr, strerror(errno));
- }
- continue;
- }
- if (!mask) {
- continue;
- }
-
- /*
- * Don't bother to queue an event if the mask was previously non-zero
- * since an event must still be on the queue.
- */
-
- 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);
- }
- filePtr->readyMask |= mask;
- }
- 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. */
- void *clientData, /* 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) 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);
-#else
- (void)sigNumber;
- (void)threadId;
- (void)clientData;
- (void)flagPtr;
- (void)value;
-#endif
- return 0;
-}
-
-#endif /* NOTIFIER_KQUEUE && TCL_THREADS */
-#else
-TCL_MAC_EMPTY_FILE(unix_tclKqueueNotfy_c)
-#endif /* !HAVE_COREFOUNDATION */
-
-/*
- * Local Variables:
- * mode: c
- * c-basic-offset: 4
- * fill-column: 78
- * End:
- */