diff options
-rw-r--r-- | tests/registry.test | 4 | ||||
-rw-r--r-- | unix/tclEpollNotfy.c | 225 | ||||
-rw-r--r-- | unix/tclKqueueNotfy.c | 231 | ||||
-rw-r--r-- | unix/tclSelectNotfy.c | 125 | ||||
-rw-r--r-- | unix/tclUnixNotfy.c | 52 | ||||
-rw-r--r-- | win/Makefile.in | 4 | ||||
-rw-r--r-- | win/makefile.vc | 2 |
7 files changed, 337 insertions, 306 deletions
diff --git a/tests/registry.test b/tests/registry.test index fec4cc0..539ba2d 100644 --- a/tests/registry.test +++ b/tests/registry.test @@ -19,7 +19,7 @@ testConstraint reg 0 if {[testConstraint win]} { if {![catch { ::tcltest::loadTestedCommands - set ::regver [package require registry 1.3.2] + set ::regver [package require registry 1.3.3] }]} { testConstraint reg 1 } @@ -33,7 +33,7 @@ testConstraint english [expr { test registry-1.0 {check if we are testing the right dll} {win reg} { set ::regver -} {1.3.2} +} {1.3.3} test registry-1.1 {argument parsing for registry command} {win reg} { list [catch {registry} msg] $msg } {1 {wrong # args: should be "registry ?-32bit|-64bit? option ?arg ...?"}} diff --git a/unix/tclEpollNotfy.c b/unix/tclEpollNotfy.c index 0350ae0..a8f2a50 100644 --- a/unix/tclEpollNotfy.c +++ b/unix/tclEpollNotfy.c @@ -2,8 +2,8 @@ * tclEpollNotfy.c -- * * This file contains the implementation of the epoll()-based - * Linux-specific notifier, which is the lowest-level part of the - * Tcl event loop. This file works together with generic/tclNotify.c. + * Linux-specific notifier, which is the lowest-level part of the Tcl + * event loop. This file works together with generic/tclNotify.c. * * Copyright (c) 1995-1997 Sun Microsystems, Inc. * Copyright (c) 2016 Lucio AndrĂ©s Illanes Albornoz <l.illanes@gmx.de> @@ -13,11 +13,10 @@ */ #include "tclInt.h" -#if defined(NOTIFIER_EPOLL) && TCL_THREADS - -#define _GNU_SOURCE /* For pipe2(2) */ #ifndef HAVE_COREFOUNDATION /* Darwin/Mac OS X CoreFoundation notifier is * in tclMacOSXNotify.c */ +#if defined(NOTIFIER_EPOLL) && TCL_THREADS +#define _GNU_SOURCE /* For pipe2(2) */ #include <fcntl.h> #include <signal.h> #include <sys/epoll.h> @@ -54,9 +53,9 @@ typedef struct FileHandler { } 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 epoll_ctl(2) - * and their corresponding event(s) returned by epoll_wait(2). + * The following structure associates a FileHandler and the thread that owns + * it with the file descriptors of interest and their event masks passed to + * epoll_ctl(2) and their corresponding event(s) returned by epoll_wait(2). */ struct ThreadSpecificData; @@ -105,7 +104,8 @@ typedef struct ThreadSpecificData { int triggerPipe[2]; /* pipe(2) used by other threads to wake * up this thread for inter-thread IPC. */ #endif /* HAVE_EVENTFD */ - int eventsFd; /* epoll(7) file descriptor used to wait for fds */ + int eventsFd; /* epoll(7) file descriptor used to wait for + * fds */ struct epoll_event *readyEvents; /* Pointer to at most maxReadyEvents events * returned by epoll_wait(2). */ @@ -113,13 +113,23 @@ typedef struct ThreadSpecificData { } ThreadSpecificData; static Tcl_ThreadDataKey dataKey; - -static void PlatformEventsControl(FileHandler *filePtr, ThreadSpecificData *tsdPtr, int op, int isNew); -static void PlatformEventsFinalize(void); -static void PlatformEventsInit(void); -static int PlatformEventsTranslate(struct epoll_event *event); -static int PlatformEventsWait(struct epoll_event *events, size_t numEvents, struct timeval *timePtr); - + +/* + * Forward declarations. + */ + +static void PlatformEventsControl(FileHandler *filePtr, + ThreadSpecificData *tsdPtr, int op, int isNew); +static void PlatformEventsFinalize(void); +static void PlatformEventsInit(void); +static int PlatformEventsTranslate(struct epoll_event *event); +static int PlatformEventsWait(struct epoll_event *events, + size_t numEvents, struct timeval *timePtr); + +/* + * Incorporate the base notifier API. + */ + #include "tclUnixNotfy.c" /* @@ -190,31 +200,32 @@ Tcl_FinalizeNotifier( * This function registers interest for the file descriptor and the mask * of TCL_* bits associated with filePtr on the epoll file descriptor * associated with tsdPtr. - * Future calls to epoll_wait will return filePtr and tsdPtr alongside with - * the event registered here via the PlatformEventData struct. + * + * Future calls to epoll_wait 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 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. * *---------------------------------------------------------------------- */ void PlatformEventsControl( - FileHandler *filePtr, - ThreadSpecificData *tsdPtr, - int op, - int isNew) + FileHandler *filePtr, + ThreadSpecificData *tsdPtr, + int op, + int isNew) { struct epoll_event newEvent; struct PlatformEventData *newPedPtr; @@ -236,10 +247,10 @@ PlatformEventsControl( newEvent.data.ptr = filePtr->pedPtr; /* - * N.B. As discussed in Tcl_WaitForEvent(), epoll(7) does not sup- - * port regular files (S_IFREG.) Therefore, filePtr is in these - * cases simply added or deleted from the list of FileHandlers - * associated with regular files belonging to tsdPtr. + * N.B. As discussed in Tcl_WaitForEvent(), epoll(7) does not support + * regular files (S_IFREG.) Therefore, filePtr is in these cases simply + * added or deleted from the list of FileHandlers associated with regular + * files belonging to tsdPtr. */ if (fstat(filePtr->fd, &fdStat) == -1) { @@ -248,7 +259,8 @@ PlatformEventsControl( switch (op) { case EPOLL_CTL_ADD: if (isNew) { - LIST_INSERT_HEAD(&tsdPtr->firstReadyFileHandlerPtr, filePtr, readyNode); + LIST_INSERT_HEAD(&tsdPtr->firstReadyFileHandlerPtr, filePtr, + readyNode); } break; case EPOLL_CTL_DEL: @@ -267,18 +279,18 @@ PlatformEventsControl( * PlatformEventsFinalize -- * * This function closes the eventfd and the epoll file descriptor and - * frees the epoll_event structs owned by the thread of the caller. - * The above operations are protected by tsdPtr->notifierMutex, which - * is destroyed thereafter. + * frees the epoll_event 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 eventfd(2) is closed, if non-zero, and set to -1. - * The per-thread epoll(7) fd is closed, if non-zero, and set to 0. - * The per-thread epoll_event structs are freed, if any, and set to 0. + * - The per-thread eventfd(2) is closed, if non-zero, and set to -1. + * - The per-thread epoll(7) fd is closed, if non-zero, and set to 0. + * - The per-thread epoll_event structs are freed, if any, and set to 0. * * tsdPtr->notifierMutex is destroyed. * @@ -297,7 +309,7 @@ PlatformEventsFinalize( close(tsdPtr->triggerEventFd); tsdPtr->triggerEventFd = -1; } -#else +#else /* !HAVE_EVENTFD */ if (tsdPtr->triggerPipe[0]) { close(tsdPtr->triggerPipe[0]); tsdPtr->triggerPipe[0] = -1; @@ -337,20 +349,20 @@ PlatformEventsFinalize( * * Side effects: * The following per-thread entities are initialised: - * notifierMutex is initialised. - * The eventfd(2) is created w/ EFD_CLOEXEC and EFD_NONBLOCK. - * The epoll(7) fd is created w/ EPOLL_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 epoll_events. + * - notifierMutex is initialised. + * - The eventfd(2) is created w/ EFD_CLOEXEC and EFD_NONBLOCK. + * - The epoll(7) fd is created w/ EPOLL_CLOEXEC. + * - A FileHandler struct is allocated and initialised for the + * eventfd(2), registering interest for TCL_READABLE on it via + * PlatformEventsControl(). + * - readyEvents and maxReadyEvents are initialised with 512 + * epoll_events. * *---------------------------------------------------------------------- */ void -PlatformEventsInit( - void) +PlatformEventsInit(void) { ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); FileHandler *filePtr; @@ -361,16 +373,17 @@ PlatformEventsInit( } filePtr = Tcl_Alloc(sizeof(*filePtr)); #ifdef HAVE_EVENTFD - if ((tsdPtr->triggerEventFd = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK)) <= 0) { + tsdPtr->triggerEventFd = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK); + if (tsdPtr->triggerEventFd <= 0) { Tcl_Panic("Tcl_InitNotifier: %s", "could not create trigger eventfd"); } filePtr->fd = tsdPtr->triggerEventFd; -#else +#else /* !HAVE_EVENTFD */ if (pipe2(tsdPtr->triggerPipe, O_CLOEXEC | O_NONBLOCK) != 0) { Tcl_Panic("Tcl_InitNotifier: %s", "could not create trigger pipe"); } filePtr->fd = tsdPtr->triggerPipe[0]; -#endif +#endif /* HAVE_EVENTFD */ tsdPtr->triggerFilePtr = filePtr; if ((tsdPtr->eventsFd = epoll_create1(EPOLL_CLOEXEC)) == -1) { Tcl_Panic("epoll_create1: %s", strerror(errno)); @@ -379,8 +392,8 @@ PlatformEventsInit( PlatformEventsControl(filePtr, tsdPtr, EPOLL_CTL_ADD, 1); if (!tsdPtr->readyEvents) { tsdPtr->maxReadyEvents = 512; - tsdPtr->readyEvents = Tcl_Alloc(tsdPtr->maxReadyEvents - * sizeof(tsdPtr->readyEvents[0])); + tsdPtr->readyEvents = Tcl_Alloc( + tsdPtr->maxReadyEvents * sizeof(tsdPtr->readyEvents[0])); } LIST_INIT(&tsdPtr->firstReadyFileHandlerPtr); } @@ -390,8 +403,8 @@ PlatformEventsInit( * * PlatformEventsTranslate -- * - * This function translates the platform-specific mask of returned - * events in eventPtr to a mask of TCL_* bits. + * This function translates the platform-specific mask of returned events + * in eventPtr to a mask of TCL_* bits. * * Results: * Returns the translated mask. @@ -404,7 +417,7 @@ PlatformEventsInit( int PlatformEventsTranslate( - struct epoll_event *eventPtr) + struct epoll_event *eventPtr) { int mask; @@ -429,16 +442,16 @@ PlatformEventsTranslate( * This function abstracts waiting for I/O events via epoll_wait. * * Results: - * Returns -1 if epoll_wait 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. + * Returns -1 if epoll_wait 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), epoll_wait(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. + * gettimeofday(2), epoll_wait(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. * *---------------------------------------------------------------------- */ @@ -457,8 +470,8 @@ PlatformEventsWait( /* * If timePtr is NULL, epoll_wait(2) will wait indefinitely. If it - * specifies a timeout of {0,0}, epoll_wait(2) will poll. Otherwise, - * the timeout will simply be converted to milliseconds. + * specifies a timeout of {0,0}, epoll_wait(2) will poll. Otherwise, the + * timeout will simply be converted to milliseconds. */ if (!timePtr) { @@ -473,9 +486,9 @@ PlatformEventsWait( } /* - * Call (and possibly block on) epoll_wait(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 epoll_wait(2). + * Call (and possibly block on) epoll_wait(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 epoll_wait(2). */ gettimeofday(&tv0, NULL); @@ -484,10 +497,10 @@ PlatformEventsWait( if (timePtr && (timePtr->tv_sec && timePtr->tv_usec)) { timersub(&tv1, &tv0, &tv_delta); if (!timercmp(&tv_delta, timePtr, >)) { - timersub(timePtr, &tv_delta, timePtr); + timersub(timePtr, &tv_delta, timePtr); } else { - timePtr->tv_sec = 0; - timePtr->tv_usec = 0; + timePtr->tv_sec = 0; + timePtr->tv_usec = 0; } } return numFound; @@ -498,8 +511,8 @@ PlatformEventsWait( * * Tcl_CreateFileHandler -- * - * This function registers a file handler with the epoll notifier - * of the thread of the caller. + * This function registers a file handler with the epoll notifier of the + * thread of the caller. * * Results: * None. @@ -551,8 +564,8 @@ Tcl_CreateFileHandler( filePtr->clientData = clientData; filePtr->mask = mask; - PlatformEventsControl(filePtr, tsdPtr, isNew ? - EPOLL_CTL_ADD : EPOLL_CTL_MOD, isNew); + PlatformEventsControl(filePtr, tsdPtr, + isNew ? EPOLL_CTL_ADD : EPOLL_CTL_MOD, isNew); } } @@ -561,8 +574,8 @@ Tcl_CreateFileHandler( * * Tcl_DeleteFileHandler -- * - * Cancel a previously-arranged callback arrangement for a file on - * the epoll file descriptor of the thread of the caller. + * Cancel a previously-arranged callback arrangement for a file on the + * epoll file descriptor of the thread of the caller. * * Results: * None. @@ -632,6 +645,7 @@ Tcl_DeleteFileHandler( * 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. + * * The waiting logic is implemented in PlatformEventsWait. * * Results: @@ -646,7 +660,7 @@ Tcl_DeleteFileHandler( int Tcl_WaitForEvent( - const Tcl_Time *timePtr) /* Maximum block time, or NULL. */ + const Tcl_Time *timePtr) /* Maximum block time, or NULL. */ { if (tclNotifierHooks.waitForEventProc) { return tclNotifierHooks.waitForEventProc(timePtr); @@ -696,10 +710,11 @@ Tcl_WaitForEvent( * 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. + * * As epoll(7) does not support regular files, 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 + * regular files are added to this list by PlatformEventsControl() and + * processed here before calling (and possibly blocking) on * PlatformEventsWait(). */ @@ -720,7 +735,7 @@ Tcl_WaitForEvent( if (filePtr->readyMask == 0) { FileHandlerEvent *fileEvPtr = - Tcl_Alloc(sizeof(FileHandlerEvent)); + Tcl_Alloc(sizeof(FileHandlerEvent)); fileEvPtr->header.proc = FileHandlerEventProc; fileEvPtr->fd = filePtr->fd; @@ -731,9 +746,9 @@ Tcl_WaitForEvent( } /* - * If any events were queued in the above loop, force PlatformEvents- - * Wait() to poll as there already are events that need to be processed - * at this point. + * 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) { @@ -751,10 +766,12 @@ Tcl_WaitForEvent( * 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 eventfd(2)/trigger pipe (see Tcl_AlertNotifier(),) - * which in turn will cause PlatformEventsWait() to return immediately. + * which in turn will cause PlatformEventsWait() to return + * immediately. */ - numFound = PlatformEventsWait(tsdPtr->readyEvents, tsdPtr->maxReadyEvents, timeoutPtr); + numFound = PlatformEventsWait(tsdPtr->readyEvents, + tsdPtr->maxReadyEvents, timeoutPtr); for (numEvent = 0; numEvent < numFound; numEvent++) { pedPtr = tsdPtr->readyEvents[numEvent].data.ptr; filePtr = pedPtr->filePtr; @@ -762,21 +779,28 @@ Tcl_WaitForEvent( #ifdef HAVE_EVENTFD if (filePtr->fd == tsdPtr->triggerEventFd) { uint64_t eventFdVal; - i = read(tsdPtr->triggerEventFd, &eventFdVal, sizeof(eventFdVal)); + i = read(tsdPtr->triggerEventFd, &eventFdVal, + sizeof(eventFdVal)); if ((i != sizeof(eventFdVal)) && (errno != EAGAIN)) { -#else + Tcl_Panic( + "Tcl_WaitForEvent: read from %p->triggerEventFd: %s", + (void *) tsdPtr, strerror(errno)); + } + continue; + } +#else /* !HAVE_EVENTFD */ if (filePtr->fd == tsdPtr->triggerPipe[0]) { char triggerPipeVal; - i = read(tsdPtr->triggerPipe[0], &triggerPipeVal, sizeof(triggerPipeVal)); + i = read(tsdPtr->triggerPipe[0], &triggerPipeVal, + sizeof(triggerPipeVal)); if ((i != sizeof(triggerPipeVal)) && (errno != EAGAIN)) { -#endif - Tcl_Panic("Tcl_WaitForEvent: " - "read from %p->triggerEventFd: %s", - (void *)tsdPtr, strerror(errno)); - } else { - continue; + Tcl_Panic( + "Tcl_WaitForEvent: read from %p->triggerPipe[0]: %s", + (void *) tsdPtr, strerror(errno)); } + continue; } +#endif /* HAVE_EVENTFD */ if (!mask) { continue; } @@ -800,9 +824,8 @@ Tcl_WaitForEvent( } } +#endif /* NOTIFIER_EPOLL && TCL_THREADS */ #endif /* !HAVE_COREFOUNDATION */ - -#endif /* NOTIFIER_EPOLL */ /* * Local Variables: diff --git a/unix/tclKqueueNotfy.c b/unix/tclKqueueNotfy.c index bea1b30..bbb8061 100644 --- a/unix/tclKqueueNotfy.c +++ b/unix/tclKqueueNotfy.c @@ -14,10 +14,10 @@ */ #include "tclInt.h" -#if defined(NOTIFIER_KQUEUE) && TCL_THREADS - #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> @@ -51,9 +51,9 @@ typedef struct FileHandler { } 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). + * 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; @@ -96,20 +96,27 @@ typedef struct ThreadSpecificData { * PlatformEventsFinalize. */ 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. */ + 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. */ } ThreadSpecificData; static Tcl_ThreadDataKey dataKey; - -static void PlatformEventsControl(FileHandler *filePtr, ThreadSpecificData *tsdPtr, int op, int isNew); -static void PlatformEventsFinalize(void); -static void PlatformEventsInit(void); -static int PlatformEventsTranslate(struct kevent *eventPtr); -static int PlatformEventsWait(struct kevent *events, size_t numEvents, struct timeval *timePtr); - + +/* + * Forward declarations of internal functions. + */ + +static void PlatformEventsControl(FileHandler *filePtr, + ThreadSpecificData *tsdPtr, int op, int isNew); +static void PlatformEventsFinalize(void); +static void PlatformEventsInit(void); +static int PlatformEventsTranslate(struct kevent *eventPtr); +static int PlatformEventsWait(struct kevent *events, + size_t numEvents, struct timeval *timePtr); + #include "tclUnixNotfy.c" /* @@ -180,6 +187,7 @@ Tcl_FinalizeNotifier( * 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. * @@ -187,26 +195,26 @@ Tcl_FinalizeNotifier( * 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.) + * - 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.) * *---------------------------------------------------------------------- */ void PlatformEventsControl( - FileHandler *filePtr, - ThreadSpecificData *tsdPtr, - int op, - int isNew) + FileHandler *filePtr, + ThreadSpecificData *tsdPtr, + int op, + int isNew) { int numChanges; struct kevent changeList[2]; @@ -221,11 +229,11 @@ PlatformEventsControl( } /* - * N.B. As discussed in Tcl_WaitForEvent(), kqueue(2) does not repro- - * duce the `always ready' {select,poll}(2) behaviour for regular - * files (S_IFREG) prior to FreeBSD 11.0-RELEASE. Therefore, file- - * Ptr is in these cases simply added or deleted from the list of - * FileHandlers associated with regular files belonging to tsdPtr. + * 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 (fstat(filePtr->fd, &fdStat) == -1) { @@ -234,7 +242,8 @@ PlatformEventsControl( switch (op) { case EV_ADD: if (isNew) { - LIST_INSERT_HEAD(&tsdPtr->firstReadyFileHandlerPtr, filePtr, readyNode); + LIST_INSERT_HEAD(&tsdPtr->firstReadyFileHandlerPtr, filePtr, + readyNode); } break; case EV_DELETE: @@ -248,38 +257,41 @@ PlatformEventsControl( 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); + 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); + 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) { + 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 writabi- - * lity 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}. + * 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); + 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); + 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)); @@ -293,10 +305,10 @@ PlatformEventsControl( * * PlatformEventsFinalize -- * - * 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. + * 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. @@ -314,7 +326,7 @@ PlatformEventsControl( void PlatformEventsFinalize( - void) + void) { ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); @@ -346,31 +358,30 @@ PlatformEventsFinalize( * * PlatformEventsInit -- * - * 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. + * 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: * None. * * 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. - + * - 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 -PlatformEventsInit( - void) +PlatformEventsInit(void) { ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); int i, fdFl; @@ -404,8 +415,8 @@ PlatformEventsInit( PlatformEventsControl(filePtr, tsdPtr, EV_ADD, 1); if (!tsdPtr->readyEvents) { tsdPtr->maxReadyEvents = 512; - tsdPtr->readyEvents = Tcl_Alloc(tsdPtr->maxReadyEvents - * sizeof(tsdPtr->readyEvents[0])); + tsdPtr->readyEvents = Tcl_Alloc( + tsdPtr->maxReadyEvents * sizeof(tsdPtr->readyEvents[0])); } LIST_INIT(&tsdPtr->firstReadyFileHandlerPtr); } @@ -429,7 +440,7 @@ PlatformEventsInit( int PlatformEventsTranslate( - struct kevent *eventPtr) + struct kevent *eventPtr) { int mask; @@ -454,20 +465,20 @@ PlatformEventsTranslate( * * PlatformEventsWait -- * - * This function abstracts waiting for I/O events via the kevent - * system call. + * 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. + * 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. + * 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. * *---------------------------------------------------------------------- */ @@ -485,9 +496,9 @@ PlatformEventsWait( ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); /* - * If timePtr is NULL, kevent(2) will wait indefinitely. If it speci- - * fies a timeout of {0,0}, kevent(2) will poll. Otherwise, the time- - * out will simply be converted to a timespec. + * 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) { @@ -504,20 +515,21 @@ PlatformEventsWait( /* * 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(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); + 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); + timersub(timePtr, &tv_delta, timePtr); } else { - timePtr->tv_sec = 0; - timePtr->tv_usec = 0; + timePtr->tv_sec = 0; + timePtr->tv_usec = 0; } } return numFound; @@ -590,8 +602,8 @@ Tcl_CreateFileHandler( * * Tcl_DeleteFileHandler -- * - * Cancel a previously-arranged callback arrangement for a file on - * the kqueue of the thread of the caller. + * Cancel a previously-arranged callback arrangement for a file on the + * kqueue of the thread of the caller. * * Results: * None. @@ -661,6 +673,7 @@ Tcl_DeleteFileHandler( * 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. + * * The waiting logic is implemented in PlatformEventsWait. * * Results: @@ -726,11 +739,13 @@ Tcl_WaitForEvent( * 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. + * 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 @@ -754,7 +769,7 @@ Tcl_WaitForEvent( if (filePtr->readyMask == 0) { FileHandlerEvent *fileEvPtr = - Tcl_Alloc(sizeof(FileHandlerEvent)); + Tcl_Alloc(sizeof(FileHandlerEvent)); fileEvPtr->header.proc = FileHandlerEventProc; fileEvPtr->fd = filePtr->fd; @@ -788,22 +803,19 @@ Tcl_WaitForEvent( * cause PlatformEventsWait() to return immediately. */ - numFound = PlatformEventsWait(tsdPtr->readyEvents, tsdPtr->maxReadyEvents, timeoutPtr); + numFound = PlatformEventsWait(tsdPtr->readyEvents, + tsdPtr->maxReadyEvents, timeoutPtr); for (numEvent = 0; numEvent < numFound; numEvent++) { - pedPtr = (struct PlatformEventData *)tsdPtr->readyEvents[numEvent].udata; + pedPtr = (struct PlatformEventData *) + tsdPtr->readyEvents[numEvent].udata; filePtr = pedPtr->filePtr; mask = PlatformEventsTranslate(&tsdPtr->readyEvents[numEvent]); if (filePtr->fd == tsdPtr->triggerPipe[0]) { - do { - 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)); - } else { - break; - } - } while (1); + 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) { @@ -829,9 +841,8 @@ Tcl_WaitForEvent( } } +#endif /* NOTIFIER_KQUEUE && TCL_THREADS */ #endif /* !HAVE_COREFOUNDATION */ - -#endif /* NOTIFIER_KQUEUE */ /* * Local Variables: diff --git a/unix/tclSelectNotfy.c b/unix/tclSelectNotfy.c index b237307..f77379b 100644 --- a/unix/tclSelectNotfy.c +++ b/unix/tclSelectNotfy.c @@ -1,9 +1,9 @@ /* * tclSelectNotfy.c -- * - * This file contains the implementation of the select()-based - * generic Unix notifier, which is the lowest-level part of the - * Tcl event loop. This file works together with generic/tclNotify.c. + * This file contains the implementation of the select()-based generic + * Unix notifier, which is the lowest-level part of the Tcl event loop. + * This file works together with generic/tclNotify.c. * * Copyright (c) 1995-1997 Sun Microsystems, Inc. * @@ -12,10 +12,10 @@ */ #include "tclInt.h" -#if (!defined(NOTIFIER_EPOLL) && !defined(NOTIFIER_KQUEUE)) || !TCL_THREADS - #ifndef HAVE_COREFOUNDATION /* Darwin/Mac OS X CoreFoundation notifier is * in tclMacOSXNotify.c */ +#if (!defined(NOTIFIER_EPOLL) && !defined(NOTIFIER_KQUEUE)) || !TCL_THREADS + #include <signal.h> /* @@ -94,16 +94,17 @@ typedef struct ThreadSpecificData { * notifierMutex lock before accessing these * fields. */ #ifdef __CYGWIN__ - void *event; /* Any other thread alerts a notifier - * that an event is ready to be processed - * by sending this event. */ + void *event; /* Any other thread alerts a notifier that an + * event is ready to be processed by sending + * this event. */ void *hwnd; /* Messaging window. */ #else /* !__CYGWIN__ */ pthread_cond_t waitCV; /* Any other thread alerts a notifier that an * event is ready to be processed by signaling * this condition variable. */ #endif /* __CYGWIN__ */ - int waitCVinitialized; /* Variable to flag initialization of the structure */ + int waitCVinitialized; /* Variable to flag initialization of the + * structure. */ int eventReady; /* True if an event is ready to be processed. * Used as condition flag together with waitCV * above. */ @@ -171,12 +172,14 @@ static int notifierThreadRunning = 0; static pthread_cond_t notifierCV = PTHREAD_COND_INITIALIZER; /* - * The pollState bits - * POLL_WANT is set by each thread before it waits on its condition - * variable. It is checked by the notifier before it does select. - * POLL_DONE is set by the notifier if it goes into select after seeing - * POLL_WANT. The idea is to ensure it tries a select with the - * same bits the initial thread had set. + * The pollState bits: + * + * POLL_WANT is set by each thread before it waits on its condition variable. + * It is checked by the notifier before it does select. + * + * POLL_DONE is set by the notifier if it goes into select after seeing + * POLL_WANT. The idea is to ensure it tries a select with the same bits + * the initial thread had set. */ #define POLL_WANT 0x1 @@ -196,24 +199,24 @@ static Tcl_ThreadId notifierThread; #if TCL_THREADS static TCL_NORETURN void NotifierThreadProc(ClientData clientData); #if defined(HAVE_PTHREAD_ATFORK) -static int atForkInit = 0; -static void AtForkChild(void); +static int atForkInit = 0; +static void AtForkChild(void); #endif /* HAVE_PTHREAD_ATFORK */ #endif /* TCL_THREADS */ -static int FileHandlerEventProc(Tcl_Event *evPtr, int flags); +static int FileHandlerEventProc(Tcl_Event *evPtr, int flags); /* - * Import of Windows API when building threaded with Cygwin. + * Import of critical bits of Windows API when building threaded with Cygwin. */ #if defined(__CYGWIN__) typedef struct { - void *hwnd; - unsigned int *message; - int wParam; - int lParam; - int time; - int x; + void *hwnd; /* Messaging window. */ + unsigned int *message; /* Message payload. */ + int wParam; /* Event-specific "word" parameter. */ + int lParam; /* Event-specific "long" parameter. */ + int time; /* Event timestamp. */ + int x; /* Event location (where meaningful). */ int y; } MSG; @@ -233,8 +236,9 @@ typedef struct { extern void __stdcall CloseHandle(void *); extern void *__stdcall CreateEventW(void *, unsigned char, unsigned char, void *); -extern void * __stdcall CreateWindowExW(void *, const void *, const void *, - DWORD, int, int, int, int, void *, void *, void *, void *); +extern void *__stdcall CreateWindowExW(void *, const void *, const void *, + DWORD, int, int, int, int, void *, void *, void *, + void *); extern DWORD __stdcall DefWindowProcW(void *, int, void *, void *); extern unsigned char __stdcall DestroyWindow(void *); extern int __stdcall DispatchMessageW(const MSG *); @@ -336,7 +340,6 @@ Tcl_InitNotifier(void) #endif /* HAVE_PTHREAD_ATFORK */ notifierCount++; - pthread_mutex_unlock(¬ifierInitMutex); #endif /* TCL_THREADS */ @@ -381,28 +384,25 @@ Tcl_FinalizeNotifier( * pipe and wait for the background thread to terminate. */ - if (notifierCount == 0) { + if (notifierCount == 0 && triggerPipe != -1) { + if (write(triggerPipe, "q", 1) != 1) { + Tcl_Panic("Tcl_FinalizeNotifier: %s", + "unable to write 'q' to triggerPipe"); + } + close(triggerPipe); + pthread_mutex_lock(¬ifierMutex); + while(triggerPipe != -1) { + pthread_cond_wait(¬ifierCV, ¬ifierMutex); + } + pthread_mutex_unlock(¬ifierMutex); + if (notifierThreadRunning) { + int result = pthread_join((pthread_t) notifierThread, NULL); - if (triggerPipe != -1) { - if (write(triggerPipe, "q", 1) != 1) { + if (result) { Tcl_Panic("Tcl_FinalizeNotifier: %s", - "unable to write q to triggerPipe"); - } - close(triggerPipe); - pthread_mutex_lock(¬ifierMutex); - while(triggerPipe != -1) { - pthread_cond_wait(¬ifierCV, ¬ifierMutex); - } - pthread_mutex_unlock(¬ifierMutex); - if (notifierThreadRunning) { - int result = pthread_join((pthread_t) notifierThread, NULL); - - if (result) { - Tcl_Panic("Tcl_FinalizeNotifier: unable to join notifier " - "thread"); - } - notifierThreadRunning = 0; + "unable to join notifier thread"); } + notifierThreadRunning = 0; } } @@ -645,7 +645,7 @@ Tcl_WaitForEvent( # ifdef __CYGWIN__ MSG msg; # endif /* __CYGWIN__ */ -#else +#else /* !TCL_THREADS */ /* * Impl. notes: timeout & timeoutPtr are used if, and only if threads * are not enabled. They are the arguments for the regular select() @@ -771,18 +771,19 @@ Tcl_WaitForEvent( MsgWaitForMultipleObjects(1, &tsdPtr->event, 0, timeout, 1279); pthread_mutex_lock(¬ifierMutex); } -#else +#else /* !__CYGWIN__ */ if (timePtr != NULL) { - Tcl_Time now; - struct timespec ptime; + Tcl_Time now; + struct timespec ptime; - Tcl_GetTime(&now); - ptime.tv_sec = timePtr->sec + now.sec + (timePtr->usec + now.usec) / 1000000; - ptime.tv_nsec = 1000 * ((timePtr->usec + now.usec) % 1000000); + Tcl_GetTime(&now); + ptime.tv_sec = timePtr->sec + now.sec + + (timePtr->usec + now.usec) / 1000000; + ptime.tv_nsec = 1000 * ((timePtr->usec + now.usec) % 1000000); - pthread_cond_timedwait(&tsdPtr->waitCV, ¬ifierMutex, &ptime); + pthread_cond_timedwait(&tsdPtr->waitCV, ¬ifierMutex, &ptime); } else { - pthread_cond_wait(&tsdPtr->waitCV, ¬ifierMutex); + pthread_cond_wait(&tsdPtr->waitCV, ¬ifierMutex); } #endif /* __CYGWIN__ */ } @@ -830,8 +831,7 @@ Tcl_WaitForEvent( "unable to write to triggerPipe"); } } - -#else +#else /* !TCL_THREADS */ tsdPtr->readyMasks = tsdPtr->checkMasks; numFound = select(tsdPtr->numFdBits, &tsdPtr->readyMasks.readable, &tsdPtr->readyMasks.writable, &tsdPtr->readyMasks.exception, @@ -892,8 +892,6 @@ Tcl_WaitForEvent( } } -#if TCL_THREADS - /* *---------------------------------------------------------------------- * @@ -918,6 +916,7 @@ Tcl_WaitForEvent( *---------------------------------------------------------------------- */ +#if TCL_THREADS static TCL_NORETURN void NotifierThreadProc( ClientData clientData) /* Not used. */ @@ -1101,12 +1100,10 @@ NotifierThreadProc( TclpThreadExit(0); } - #endif /* TCL_THREADS */ - + +#endif /* (!NOTIFIER_EPOLL && !NOTIFIER_KQUEUE) || !TCL_THREADS */ #endif /* !HAVE_COREFOUNDATION */ - -#endif /* !NOTIFIER_EPOLL && !NOTIFIER_KQUEUE */ /* * Local Variables: diff --git a/unix/tclUnixNotfy.c b/unix/tclUnixNotfy.c index fb7e569..3817071 100644 --- a/unix/tclUnixNotfy.c +++ b/unix/tclUnixNotfy.c @@ -18,7 +18,7 @@ * Static routines defined in this file. */ -static int FileHandlerEventProc(Tcl_Event *evPtr, int flags); +static int FileHandlerEventProc(Tcl_Event *evPtr, int flags); #if !TCL_THREADS # undef NOTIFIER_EPOLL # undef NOTIFIER_KQUEUE @@ -27,7 +27,7 @@ static int FileHandlerEventProc(Tcl_Event *evPtr, int flags); # define NOTIFIER_SELECT static TCL_NORETURN void NotifierThreadProc(ClientData clientData); # if defined(HAVE_PTHREAD_ATFORK) -static void AtForkChild(void); +static void AtForkChild(void); # endif /* HAVE_PTHREAD_ATFORK */ /* @@ -120,7 +120,7 @@ Tcl_AlertNotifier( # endif /* __CYGWIN__ */ pthread_mutex_unlock(¬ifierMutex); #endif /* TCL_THREADS */ -#else +#else /* !NOTIFIER_SELECT */ ThreadSpecificData *tsdPtr = clientData; #if defined(NOTIFIER_EPOLL) && defined(HAVE_EVENTFD) uint64_t eventFdVal = 1; @@ -128,12 +128,13 @@ Tcl_AlertNotifier( sizeof(eventFdVal)) != sizeof(eventFdVal)) { Tcl_Panic("Tcl_AlertNotifier: unable to write to %p->triggerEventFd", (void *)tsdPtr); + } #else if (write(tsdPtr->triggerPipe[1], "", 1) != 1) { Tcl_Panic("Tcl_AlertNotifier: unable to write to %p->triggerPipe", (void *)tsdPtr); -#endif /* NOTIFIER_EPOLL && HAVE_EVENTFD */ } +#endif /* NOTIFIER_EPOLL && HAVE_EVENTFD */ #endif /* NOTIFIER_SELECT */ } } @@ -301,15 +302,15 @@ FileHandlerEventProc( static void AlertSingleThread( - ThreadSpecificData *tsdPtr) + ThreadSpecificData *tsdPtr) { tsdPtr->eventReady = 1; if (tsdPtr->onList) { /* - * Remove the ThreadSpecificData structure of this thread - * from the waiting list. This prevents us from - * continuously spinning on epoll_wait until the other - * threads runs and services the file event. + * Remove the ThreadSpecificData structure of this thread from the + * waiting list. This prevents us from continuously spinning on + * epoll_wait until the other threads runs and services the file + * event. */ if (tsdPtr->prevPtr) { @@ -326,7 +327,7 @@ AlertSingleThread( } #ifdef __CYGWIN__ PostMessageW(tsdPtr->hwnd, 1024, 0, 0); -#else /* __CYGWIN__ */ +#else /* !__CYGWIN__ */ pthread_cond_broadcast(&tsdPtr->waitCV); #endif /* __CYGWIN__ */ } @@ -359,9 +360,10 @@ AtForkChild(void) pthread_cond_init(¬ifierCV, NULL); /* - * notifierThreadRunning == 1: thread is running, (there might be data in notifier lists) + * notifierThreadRunning == 1: thread is running, (there might be data in + * notifier lists) * atForkInit == 0: InitNotifier was never called - * notifierCount != 0: unbalanced InitNotifier() / FinalizeNotifier calls + * notifierCount != 0: unbalanced InitNotifier() / FinalizeNotifier calls * waitingListPtr != 0: there are threads currently waiting for events. */ @@ -382,8 +384,8 @@ AtForkChild(void) waitingListPtr = NULL; /* - * The tsdPtr from before the fork is copied as well. But since - * we are paranoic, we don't trust its condvar and reset it. + * The tsdPtr from before the fork is copied as well. But since we + * are paranoic, we don't trust its condvar and reset it. */ #ifdef __CYGWIN__ DestroyWindow(tsdPtr->hwnd); @@ -391,10 +393,10 @@ AtForkChild(void) className, 0, 0, 0, 0, 0, NULL, NULL, TclWinGetTclInstance(), NULL); ResetEvent(tsdPtr->event); -#else +#else /* !__CYGWIN__ */ pthread_cond_destroy(&tsdPtr->waitCV); pthread_cond_init(&tsdPtr->waitCV, NULL); -#endif +#endif /* __CYGWIN__ */ /* * In case, we had multiple threads running before the fork, @@ -465,8 +467,8 @@ TclUnixWaitForFile( if (timeout > 0) { Tcl_GetTime(&now); - abortTime.sec = now.sec + timeout/1000; - abortTime.usec = now.usec + (timeout%1000)*1000; + abortTime.sec = now.sec + timeout / 1000; + abortTime.usec = now.usec + (timeout % 1000) * 1000; if (abortTime.usec >= 1000000) { abortTime.usec -= 1000000; abortTime.sec += 1; @@ -501,7 +503,7 @@ TclUnixWaitForFile( * become ready or a timeout to occur. */ - while (1) { + do { if (timeout > 0) { blockTime.tv_sec = abortTime.sec - now.sec; blockTime.tv_usec = abortTime.usec - now.usec; @@ -524,9 +526,9 @@ TclUnixWaitForFile( } else if (!timeoutPtr->tv_sec && !timeoutPtr->tv_usec) { pollTimeout = 0; } else { - pollTimeout = (int)timeoutPtr->tv_sec * 1000; + pollTimeout = (int) timeoutPtr->tv_sec * 1000; if (timeoutPtr->tv_usec) { - pollTimeout += ((int)timeoutPtr->tv_usec / 1000); + pollTimeout += (int) timeoutPtr->tv_usec / 1000; } } numFound = poll(pollFds, 1, pollTimeout); @@ -557,13 +559,11 @@ TclUnixWaitForFile( */ Tcl_GetTime(&now); - if ((abortTime.sec < now.sec) - || (abortTime.sec==now.sec && abortTime.usec<=now.usec)) { - break; - } - } + } while ((abortTime.sec > now.sec) + || (abortTime.sec == now.sec && abortTime.usec > now.usec)); return result; } + #endif /* !HAVE_COREFOUNDATION */ /* diff --git a/win/Makefile.in b/win/Makefile.in index 6a09343..24158f4 100644 --- a/win/Makefile.in +++ b/win/Makefile.in @@ -869,7 +869,7 @@ test-tcl: binaries $(TCLSH) $(CAT32) $(TEST_DLL_FILE) -load "package ifneeded Tcltest ${VERSION}@TCL_PATCH_LEVEL@ [list load [file normalize ${TEST_DLL_FILE}] Tcltest]; \ package ifneeded tcltests 0.1 \"[list source [file normalize $(ROOT_DIR_NATIVE)/tests/tcltests.tcl]];package provide tcltests 0.1\"; \ package ifneeded dde 1.4.0 [list load [file normalize ${DDE_DLL_FILE}] dde]; \ - package ifneeded registry 1.3.2 [list load [file normalize ${REG_DLL_FILE}] registry]" | $(WINE) ./$(CAT32) + package ifneeded registry 1.3.3 [list load [file normalize ${REG_DLL_FILE}] registry]" | $(WINE) ./$(CAT32) # Useful target to launch a built tclsh with the proper path,... runtest: binaries $(TCLSH) $(TEST_DLL_FILE) @@ -877,7 +877,7 @@ runtest: binaries $(TCLSH) $(TEST_DLL_FILE) $(WINE) ./$(TCLSH) $(TESTFLAGS) -load "package ifneeded Tcltest ${VERSION}@TCL_PATCH_LEVEL@ [list load [file normalize ${TEST_DLL_FILE}] Tcltest]; \ package ifneeded tcltests 0.1 \"[list source [file normalize $(ROOT_DIR_NATIVE)/tests/tcltests.tcl]];package provide tcltests 0.1\"; \ package ifneeded dde 1.4.0 [list load [file normalize ${DDE_DLL_FILE}] dde]; \ - package ifneeded registry 1.3.2 [list load [file normalize ${REG_DLL_FILE}] registry]" $(SCRIPT) + package ifneeded registry 1.3.3 [list load [file normalize ${REG_DLL_FILE}] registry]" $(SCRIPT) # This target can be used to run tclsh from the build directory via # `make shell SCRIPT=foo.tcl` diff --git a/win/makefile.vc b/win/makefile.vc index 824d8e3..8c5e93d 100644 --- a/win/makefile.vc +++ b/win/makefile.vc @@ -393,7 +393,7 @@ test-core: setup $(TCLTEST) dlls set TCL_LIBRARY=$(ROOT:\=/)/library
$(DEBUGGER) $(TCLTEST) "$(ROOT:\=/)/tests/all.tcl" $(TESTFLAGS) -loadfile <<
package ifneeded dde 1.4.0 [list load "$(TCLDDELIB:\=/)" dde]
- package ifneeded registry 1.3.2 [list load "$(TCLREGLIB:\=/)" registry]
+ package ifneeded registry 1.3.3 [list load "$(TCLREGLIB:\=/)" registry]
<<
runtest: setup $(TCLTEST) dlls
|