Attachment "tcl8.6.6.patch" to
ticket [40eb6131cf]
added by
msaal
2017-03-09 18:02:40.
diff -Nuar tcl8.6.6.orig/unix/tclUnixChan.c tcl8.6.6/unix/tclUnixChan.c
--- tcl8.6.6.orig/unix/tclUnixChan.c 2016-02-25 15:12:38.000000000 -0500
+++ tcl8.6.6/unix/tclUnixChan.c 2017-03-01 13:09:36.545330731 -0500
@@ -48,6 +48,8 @@
#endif /* HAVE_TERMIOS_H */
+#include <poll.h>
+
/*
* Helper macros to make parts of this file clearer. The macros do exactly
* what they say on the tin. :-) They also only ever refer to their arguments
@@ -1764,22 +1766,9 @@
* forever. */
{
Tcl_Time abortTime = {0, 0}, now; /* silence gcc 4 warning */
- struct timeval blockTime, *timeoutPtr;
int numFound, result = 0;
- fd_set readableMask;
- fd_set writableMask;
- fd_set exceptionMask;
-
-#ifndef _DARWIN_C_SOURCE
- /*
- * Sanity check fd.
- */
-
- if (fd >= FD_SETSIZE) {
- Tcl_Panic("TclUnixWaitForFile can't handle file id %d", fd);
- /* must never get here, or select masks overrun will occur below */
- }
-#endif
+ int msec = 0;
+ struct pollfd pollfd;
/*
* If there is a non-zero finite timeout, compute the time when we give
@@ -1794,70 +1783,56 @@
abortTime.usec -= 1000000;
abortTime.sec += 1;
}
- timeoutPtr = &blockTime;
} else if (timeout == 0) {
- timeoutPtr = &blockTime;
- blockTime.tv_sec = 0;
- blockTime.tv_usec = 0;
+ msec = 0;
} else {
- timeoutPtr = NULL;
+ msec = -1;
}
/*
- * Initialize the select masks.
- */
-
- FD_ZERO(&readableMask);
- FD_ZERO(&writableMask);
- FD_ZERO(&exceptionMask);
-
- /*
* Loop in a mini-event loop of our own, waiting for either the file to
* become ready or a timeout to occur.
*/
while (1) {
if (timeout > 0) {
- blockTime.tv_sec = abortTime.sec - now.sec;
- blockTime.tv_usec = abortTime.usec - now.usec;
- if (blockTime.tv_usec < 0) {
- blockTime.tv_sec -= 1;
- blockTime.tv_usec += 1000000;
- }
- if (blockTime.tv_sec < 0) {
- blockTime.tv_sec = 0;
- blockTime.tv_usec = 0;
+ msec = (abortTime.sec - now.sec)*1000;
+ msec += (abortTime.usec - now.usec)/1000;
+ if (msec < 0) {
+ msec = 0;
}
}
/*
- * Setup the select masks for the fd.
+ * Setup poll for the fd.
*/
+ pollfd.fd = fd;
+ pollfd.events = 0;
if (mask & TCL_READABLE) {
- FD_SET(fd, &readableMask);
+ pollfd.events |= POLLIN | POLLHUP;
}
if (mask & TCL_WRITABLE) {
- FD_SET(fd, &writableMask);
+ pollfd.events |= POLLOUT;
}
if (mask & TCL_EXCEPTION) {
- FD_SET(fd, &exceptionMask);
+ pollfd.events |= POLLERR;
}
/*
* Wait for the event or a timeout.
*/
- numFound = select(fd + 1, &readableMask, &writableMask,
- &exceptionMask, timeoutPtr);
+ numFound = poll(&pollfd, 1, msec);
if (numFound == 1) {
- if (FD_ISSET(fd, &readableMask)) {
+ pollfd.revents &= pollfd.events;
+ if (pollfd.revents & (POLLIN | POLLHUP)) {
SET_BITS(result, TCL_READABLE);
}
- if (FD_ISSET(fd, &writableMask)) {
+ if (pollfd.revents & POLLOUT) {
SET_BITS(result, TCL_WRITABLE);
}
- if (FD_ISSET(fd, &exceptionMask)) {
+ if (pollfd.revents & POLLERR) {
SET_BITS(result, TCL_EXCEPTION);
}
result &= mask;
diff -Nuar tcl8.6.6.orig/unix/tclUnixNotfy.c tcl8.6.6/unix/tclUnixNotfy.c
--- tcl8.6.6.orig/unix/tclUnixNotfy.c 2016-03-23 07:43:13.000000000 -0400
+++ tcl8.6.6/unix/tclUnixNotfy.c 2017-03-01 13:12:43.580607804 -0500
@@ -16,6 +16,7 @@
#include "tclInt.h"
#ifndef HAVE_COREFOUNDATION /* Darwin/Mac OS X CoreFoundation notifier is
* in tclMacOSXNotify.c */
+#include <poll.h>
#include <signal.h>
/*
@@ -51,16 +52,8 @@
* the event is queued). */
} FileHandlerEvent;
-/*
- * The following structure contains a set of select() masks to track readable,
- * writable, and exception conditions.
- */
-
-typedef struct SelectMasks {
- fd_set readable;
- fd_set writable;
- fd_set exception;
-} SelectMasks;
+#define POLLFD_SIZE 4096
+#define NELEM(a) (sizeof (a)/sizeof *(a))
/*
* The following static structure contains the state information for the
@@ -71,17 +64,10 @@
typedef struct ThreadSpecificData {
FileHandler *firstFileHandlerPtr;
/* Pointer to head of file handler list. */
- SelectMasks checkMasks; /* This structure is used to build up the
- * masks to be used in the next call to
- * select. Bits are set in response to calls
- * to Tcl_CreateFileHandler. */
- SelectMasks readyMasks; /* This array reflects the readable/writable
- * conditions that were found to exist by the
- * last call to select. */
- int numFdBits; /* Number of valid bits in checkMasks (one
- * more than highest fd for which
- * Tcl_WatchFile has been called). */
+ int fds_size;
+ struct pollfd fds[POLLFD_SIZE];
#ifdef TCL_THREADS
+ int fds_offset; /* offset in notifier fds array */
int onList; /* True if it is in this list */
unsigned int pollState; /* pollState is used to implement a polling
* handshake between each thread and the
@@ -110,6 +96,39 @@
#endif /* TCL_THREADS */
} ThreadSpecificData;
+static inline int
+fds_index(
+ ThreadSpecificData *tsdPtr,
+ int fd)
+{
+ int min = 0;
+ int max = tsdPtr->fds_size - 1;
+ int ii;
+
+ while (max >= min) {
+ ii = (max + min)/2;
+ if (tsdPtr->fds[ii].fd == fd) {
+ return ii;
+ }
+ if (fd > tsdPtr->fds[ii].fd) {
+ min = ii + 1;
+ } else {
+ max = ii - 1;
+ }
+ }
+
+ return -1;
+}
+
+static inline struct pollfd *
+fds_pointer(
+ ThreadSpecificData *tsdPtr,
+ int fd)
+{
+ int ii = fds_index(tsdPtr, fd);
+ return ii != -1 ? &tsdPtr->fds[ii] : NULL;
+}
+
static Tcl_ThreadDataKey dataKey;
#ifdef TCL_THREADS
@@ -153,7 +172,7 @@
*/
pthread_mutex_t notifierInitMutex = PTHREAD_MUTEX_INITIALIZER;
-pthread_mutex_t notifierMutex = PTHREAD_MUTEX_INITIALIZER;
+pthread_mutex_t notifierMutex = PTHREAD_MUTEX_INITIALIZER;
/*
* The following static indicates if the notifier thread is running.
*
@@ -608,6 +627,8 @@
} else {
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
FileHandler *filePtr;
+ int ii;
+ struct pollfd *fdsp;
for (filePtr = tsdPtr->firstFileHandlerPtr; filePtr != NULL;
filePtr = filePtr->nextPtr) {
@@ -630,23 +651,32 @@
* Update the check masks for this file.
*/
+ fdsp = fds_pointer(tsdPtr, fd);
+ if (fdsp == NULL && tsdPtr->fds_size < NELEM(tsdPtr->fds)) {
+ for (ii = 0; ii < tsdPtr->fds_size; ii++) {
+ if (tsdPtr->fds[ii].fd > fd) {
+ break;
+ }
+ }
+ fdsp = &tsdPtr->fds[ii];
+ memmove(&tsdPtr->fds[ii+1], &tsdPtr->fds[ii],
+ sizeof tsdPtr->fds[ii] * (tsdPtr->fds_size - ii));
+ tsdPtr->fds_size++;
+ fdsp->fd = fd;
+ }
+ if (fdsp == NULL) {
+ Tcl_Panic("%s: out of file descriptor space", __FUNCTION__);
+ }
+
+ fdsp->events = 0;
if (mask & TCL_READABLE) {
- FD_SET(fd, &tsdPtr->checkMasks.readable);
- } else {
- FD_CLR(fd, &tsdPtr->checkMasks.readable);
+ fdsp->events |= POLLIN | POLLHUP;
}
if (mask & TCL_WRITABLE) {
- FD_SET(fd, &tsdPtr->checkMasks.writable);
- } else {
- FD_CLR(fd, &tsdPtr->checkMasks.writable);
+ fdsp->events |= POLLOUT;
}
if (mask & TCL_EXCEPTION) {
- FD_SET(fd, &tsdPtr->checkMasks.exception);
- } else {
- FD_CLR(fd, &tsdPtr->checkMasks.exception);
- }
- if (tsdPtr->numFdBits <= fd) {
- tsdPtr->numFdBits = fd+1;
+ fdsp->events |= POLLERR;
}
}
}
@@ -677,7 +707,7 @@
return;
} else {
FileHandler *filePtr, *prevPtr;
- int i;
+ int ii;
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
/*
@@ -698,32 +728,11 @@
* Update the check masks for this file.
*/
- if (filePtr->mask & TCL_READABLE) {
- FD_CLR(fd, &tsdPtr->checkMasks.readable);
- }
- if (filePtr->mask & TCL_WRITABLE) {
- FD_CLR(fd, &tsdPtr->checkMasks.writable);
- }
- if (filePtr->mask & TCL_EXCEPTION) {
- FD_CLR(fd, &tsdPtr->checkMasks.exception);
- }
-
- /*
- * Find current max fd.
- */
-
- if (fd+1 == tsdPtr->numFdBits) {
- int 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.exception)) {
- numFdBits = i+1;
- break;
- }
- }
- tsdPtr->numFdBits = numFdBits;
+ ii = fds_index(tsdPtr, fd);
+ if (ii != -1) {
+ tsdPtr->fds_size--;
+ memmove(&tsdPtr->fds[ii], &tsdPtr->fds[ii+1],
+ sizeof tsdPtr->fds[ii] * (tsdPtr->fds_size - ii));
}
/*
@@ -864,7 +873,7 @@
return tclNotifierHooks.waitForEventProc(timePtr);
} else {
FileHandler *filePtr;
- int mask;
+ int mask, ii;
Tcl_Time vTime;
#ifdef TCL_THREADS
int waitForFiles;
@@ -872,13 +881,6 @@
MSG msg;
# endif /* __CYGWIN__ */
#else
- /*
- * Impl. notes: timeout & timeoutPtr are used if, and only if threads
- * are not enabled. They are the arguments for the regular select()
- * used when the core is not thread-enabled.
- */
-
- struct timeval timeout, *timeoutPtr;
int numFound;
#endif /* TCL_THREADS */
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
@@ -902,10 +904,7 @@
timePtr = &vTime;
}
#ifndef TCL_THREADS
- timeout.tv_sec = timePtr->sec;
- timeout.tv_usec = timePtr->usec;
- timeoutPtr = &timeout;
- } else if (tsdPtr->numFdBits == 0) {
+ } else if (tsdPtr->fds_size == 0) {
/*
* If there are no threads, no timeout, and no fds registered,
* then there are no events possible and we must avoid deadlock.
@@ -915,8 +914,6 @@
*/
return -1;
- } else {
- timeoutPtr = NULL;
#endif /* !TCL_THREADS */
}
@@ -954,10 +951,16 @@
tsdPtr->pollState = POLL_WANT;
timePtr = NULL;
} else {
- waitForFiles = (tsdPtr->numFdBits > 0);
+ waitForFiles = (tsdPtr->fds_size > 0);
tsdPtr->pollState = 0;
}
+ /* initialize events */
+ tsdPtr->fds_offset = -1;
+ for (ii = 0; ii < tsdPtr->fds_size; ii++) {
+ tsdPtr->fds[ii].revents = 0;
+ }
+
if (waitForFiles) {
/*
* Add the ThreadSpecificData structure of this thread to the list
@@ -979,10 +982,6 @@
}
}
- FD_ZERO(&tsdPtr->readyMasks.readable);
- FD_ZERO(&tsdPtr->readyMasks.writable);
- FD_ZERO(&tsdPtr->readyMasks.exception);
-
if (!tsdPtr->eventReady) {
#ifdef __CYGWIN__
if (!PeekMessageW(&msg, NULL, 0, 0, 0)) {
@@ -1058,10 +1057,8 @@
}
#else
- tsdPtr->readyMasks = tsdPtr->checkMasks;
- numFound = select(tsdPtr->numFdBits, &tsdPtr->readyMasks.readable,
- &tsdPtr->readyMasks.writable, &tsdPtr->readyMasks.exception,
- timeoutPtr);
+ numFound = poll(tsdPtr->fds, tsdPtr->fds_size, timePtr == NULL
+ ? -1 : (timePtr->sec*1000)+(timePtr->usec/1000));
/*
* Some systems don't clear the masks after an error, so we have to do
@@ -1069,9 +1066,9 @@
*/
if (numFound == -1) {
- FD_ZERO(&tsdPtr->readyMasks.readable);
- FD_ZERO(&tsdPtr->readyMasks.writable);
- FD_ZERO(&tsdPtr->readyMasks.exception);
+ for (ii = 0; ii < tsdPtr->fds_size; ii++) {
+ tsdPtr->fds[ii].revents = 0;
+ }
}
#endif /* TCL_THREADS */
@@ -1081,14 +1078,28 @@
for (filePtr = tsdPtr->firstFileHandlerPtr; (filePtr != NULL);
filePtr = filePtr->nextPtr) {
+ struct pollfd *fdsp = fds_pointer(tsdPtr, filePtr->fd);
+ short revents;
+
+ if (fdsp == NULL) {
+ Tcl_Panic("%s: fd=%d not found", __FUNCTION__, filePtr->fd);
+ continue;
+ }
+
+ if (fdsp->revents & POLLNVAL) {
+ /* file descriptor is no longer valid, skip it */
+ continue;
+ }
+
mask = 0;
- if (FD_ISSET(filePtr->fd, &tsdPtr->readyMasks.readable)) {
+ revents = fdsp->revents & fdsp->events;
+ if (revents & (POLLIN | POLLHUP)) {
mask |= TCL_READABLE;
}
- if (FD_ISSET(filePtr->fd, &tsdPtr->readyMasks.writable)) {
+ if (revents & POLLOUT) {
mask |= TCL_WRITABLE;
}
- if (FD_ISSET(filePtr->fd, &tsdPtr->readyMasks.exception)) {
+ if (revents & POLLERR) {
mask |= TCL_EXCEPTION;
}
@@ -1148,13 +1159,12 @@
ClientData clientData) /* Not used. */
{
ThreadSpecificData *tsdPtr;
- fd_set readableMask;
- fd_set writableMask;
- fd_set exceptionMask;
+ struct pollfd * fdsp;
+ int fds_size, fds_num;
int fds[2];
- int i, numFdBits = 0, receivePipe;
+ int ii, receivePipe;
long found;
- struct timeval poll = {0., 0.}, *timePtr;
+ int timeout;
char buf[2];
if (pipe(fds) != 0) {
@@ -1195,59 +1205,70 @@
pthread_mutex_unlock(¬ifierMutex);
/*
+ * Allocate initial poll mask.
+ */
+
+ fds_size = POLLFD_SIZE;
+ fdsp = ckalloc((sizeof *fdsp) * fds_size);
+
+ /*
* Look for file events and report them to interested threads.
*/
while (1) {
- FD_ZERO(&readableMask);
- FD_ZERO(&writableMask);
- FD_ZERO(&exceptionMask);
-
/*
* Compute the logical OR of the select masks from all the waiting
* notifiers.
*/
+ timeout = -1;
+
pthread_mutex_lock(¬ifierMutex);
- timePtr = NULL;
+
+ /*
+ * Make sure we haved enough space in the poll mask for receive pipe
+ * and file descriptors.
+ */
+
+ fds_num = 1;
for (tsdPtr = waitingListPtr; tsdPtr; tsdPtr = tsdPtr->nextPtr) {
- for (i = tsdPtr->numFdBits-1; i >= 0; --i) {
- if (FD_ISSET(i, &tsdPtr->checkMasks.readable)) {
- FD_SET(i, &readableMask);
- }
- if (FD_ISSET(i, &tsdPtr->checkMasks.writable)) {
- FD_SET(i, &writableMask);
- }
- if (FD_ISSET(i, &tsdPtr->checkMasks.exception)) {
- FD_SET(i, &exceptionMask);
- }
+ fds_num += tsdPtr->fds_size;
+ }
+ if (fds_num > fds_size) {
+ while (fds_num > fds_size) {
+ fds_size += POLLFD_SIZE;
}
- if (tsdPtr->numFdBits > numFdBits) {
- numFdBits = tsdPtr->numFdBits;
+ fdsp = ckrealloc(fdsp, (sizeof *fdsp) * fds_size);
+ }
+
+ /*
+ * Add receive pipe and file descriptors to poll mask.
+ */
+
+ fdsp[0].fd = receivePipe;
+ fdsp[0].events = POLLIN | POLLHUP;
+ fds_num = 1;
+ for (tsdPtr = waitingListPtr; tsdPtr; tsdPtr = tsdPtr->nextPtr) {
+ tsdPtr->fds_offset = fds_num;
+ for (ii = 0; ii < tsdPtr->fds_size; ii++) {
+ fdsp[fds_num].fd = tsdPtr->fds[ii].fd;
+ fdsp[fds_num].events = tsdPtr->fds[ii].events;
+ fds_num++;
}
if (tsdPtr->pollState & POLL_WANT) {
/*
- * Here we make sure we go through select() with the same mask
+ * Here we make sure we go through poll() with the same mask
* bits that were present when the thread tried to poll.
*/
tsdPtr->pollState |= POLL_DONE;
- timePtr = &poll;
+ timeout = 0;
}
}
- pthread_mutex_unlock(¬ifierMutex);
-
- /*
- * Set up the select mask to include the receive pipe.
- */
- if (receivePipe >= numFdBits) {
- numFdBits = receivePipe + 1;
- }
- FD_SET(receivePipe, &readableMask);
+ pthread_mutex_unlock(¬ifierMutex);
- if (select(numFdBits, &readableMask, &writableMask, &exceptionMask,
- timePtr) == -1) {
+ if (poll(fdsp, fds_num, timeout) == -1) {
/*
* Try again immediately on an error.
*/
@@ -1261,22 +1282,14 @@
pthread_mutex_lock(¬ifierMutex);
for (tsdPtr = waitingListPtr; tsdPtr; tsdPtr = tsdPtr->nextPtr) {
- found = 0;
+ if (tsdPtr->fds_offset < 0) {
+ continue;
+ }
- for (i = tsdPtr->numFdBits-1; i >= 0; --i) {
- if (FD_ISSET(i, &tsdPtr->checkMasks.readable)
- && FD_ISSET(i, &readableMask)) {
- FD_SET(i, &tsdPtr->readyMasks.readable);
- found = 1;
- }
- if (FD_ISSET(i, &tsdPtr->checkMasks.writable)
- && FD_ISSET(i, &writableMask)) {
- FD_SET(i, &tsdPtr->readyMasks.writable);
- found = 1;
- }
- if (FD_ISSET(i, &tsdPtr->checkMasks.exception)
- && FD_ISSET(i, &exceptionMask)) {
- FD_SET(i, &tsdPtr->readyMasks.exception);
+ found = 0;
+ for (ii = 0; ii < tsdPtr->fds_size; ii++) {
+ tsdPtr->fds[ii].revents = fdsp[tsdPtr->fds_offset + ii].revents;
+ if (tsdPtr->fds[ii].revents & tsdPtr->fds[ii].events) {
found = 1;
}
}
@@ -1318,10 +1331,10 @@
* avoid a race condition we only read one at a time.
*/
- if (FD_ISSET(receivePipe, &readableMask)) {
- i = read(receivePipe, buf, 1);
+ if (fdsp[0].revents & (POLLIN | POLLHUP)) {
+ ii = read(receivePipe, buf, 1);
- if ((i == 0) || ((i == 1) && (buf[0] == 'q'))) {
+ if ((ii == 0) || ((ii == 1) && (buf[0] == 'q'))) {
/*
* Someone closed the write end of the pipe or sent us a Quit
* message [Bug: 4139] and then closed the write end of the
@@ -1343,6 +1356,7 @@
triggerPipe = -1;
pthread_cond_broadcast(¬ifierCV);
pthread_mutex_unlock(¬ifierMutex);
+ ckfree(fdsp);
TclpThreadExit(0);
}