diff options
-rw-r--r-- | unix/tclUnixChan.c | 48 | ||||
-rw-r--r-- | unix/tclUnixNotfy.c | 233 |
2 files changed, 118 insertions, 163 deletions
diff --git a/unix/tclUnixChan.c b/unix/tclUnixChan.c index a1fe090..c99dcdc 100644 --- a/unix/tclUnixChan.c +++ b/unix/tclUnixChan.c @@ -14,6 +14,8 @@ #include "tclInt.h" /* Internal definitions for Tcl. */ #include "tclIO.h" /* To get Channel type declaration. */ +#include <poll.h> + #undef SUPPORTS_TTY #if defined(HAVE_TERMIOS_H) # define SUPPORTS_TTY 1 @@ -1731,21 +1733,15 @@ TclUnixWaitForFile( * forever. */ { Tcl_Time abortTime = {0, 0}, now; /* silence gcc 4 warning */ - struct timeval blockTime, *timeoutPtr; + struct timeval blockTime = {0, 0}; int numFound, result = 0; - fd_set readableMask; - fd_set writableMask; - fd_set exceptionMask; + struct pollfd pfd; #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 /* @@ -1761,24 +1757,9 @@ TclUnixWaitForFile( abortTime.usec -= 1000000; abortTime.sec += 1; } - timeoutPtr = &blockTime; - } else if (timeout == 0) { - timeoutPtr = &blockTime; - blockTime.tv_sec = 0; - blockTime.tv_usec = 0; - } else { - timeoutPtr = NULL; } /* - * 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. */ @@ -1797,34 +1778,35 @@ TclUnixWaitForFile( } } + pfd.fd=fd; + pfd.events=0; + pfd.revents=0; + /* * Setup the select masks for the fd. */ if (mask & TCL_READABLE) { - FD_SET(fd, &readableMask); + pfd.events |= POLLIN; } if (mask & TCL_WRITABLE) { - FD_SET(fd, &writableMask); - } - if (mask & TCL_EXCEPTION) { - FD_SET(fd, &exceptionMask); + pfd.events |= POLLOUT; } /* * Wait for the event or a timeout. */ - numFound = select(fd + 1, &readableMask, &writableMask, - &exceptionMask, timeoutPtr); + numFound = poll(&pfd, 1, + (blockTime.tv_sec * 1000 + blockTime.tv_usec / 1000)); if (numFound == 1) { - if (FD_ISSET(fd, &readableMask)) { + if (pfd.revents & (POLLIN|POLLHUP)) { SET_BITS(result, TCL_READABLE); } - if (FD_ISSET(fd, &writableMask)) { + if (pfd.revents & POLLOUT) { SET_BITS(result, TCL_WRITABLE); } - if (FD_ISSET(fd, &exceptionMask)) { + if (pfd.revents & POLLERR) { SET_BITS(result, TCL_EXCEPTION); } result &= mask; diff --git a/unix/tclUnixNotfy.c b/unix/tclUnixNotfy.c index b2bea45..0a84e73 100644 --- a/unix/tclUnixNotfy.c +++ b/unix/tclUnixNotfy.c @@ -16,6 +16,9 @@ * in tclMacOSXNotify.c */ #include <signal.h> +#include <poll.h> +#include <assert.h> + /* * This structure is used to keep track of the notifier info for a registered * file. @@ -32,6 +35,7 @@ typedef struct FileHandler { * Tcl_CreateFileHandler. */ ClientData clientData; /* Argument to pass to proc. */ struct FileHandler *nextPtr;/* Next in list of all files we care about. */ + struct pollfd pfd; /* for poll() call */ } FileHandler; /* @@ -69,16 +73,6 @@ typedef struct SelectMasks { 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). */ #ifdef TCL_THREADS int onList; /* True if it is in this list */ unsigned int pollState; /* pollState is used to implement a polling @@ -587,24 +581,17 @@ Tcl_CreateFileHandler( * Update the check masks for this file. */ + filePtr->pfd.fd=fd; + filePtr->pfd.events=0; + filePtr->pfd.revents=0; + if (mask & TCL_READABLE) { - FD_SET(fd, &tsdPtr->checkMasks.readable); - } else { - FD_CLR(fd, &tsdPtr->checkMasks.readable); + filePtr->pfd.events |= POLLIN; } if (mask & TCL_WRITABLE) { - FD_SET(fd, &tsdPtr->checkMasks.writable); - } else { - FD_CLR(fd, &tsdPtr->checkMasks.writable); - } - 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; + filePtr->pfd.events |= POLLOUT; } + /* poll always watches for exceptions */ } } @@ -634,7 +621,6 @@ Tcl_DeleteFileHandler( return; } else { FileHandler *filePtr, *prevPtr; - int i; ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); /* @@ -652,38 +638,6 @@ Tcl_DeleteFileHandler( } /* - * 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; - } - - /* * Clean up information in the callback record. */ @@ -834,8 +788,9 @@ Tcl_WaitForEvent( * used when the core is not thread-enabled. */ - struct timeval timeout, *timeoutPtr; - int numFound; + struct timeval timeout; + struct pollfd *pfd; + int numfds,i,msto,numFound; #endif /* TCL_THREADS */ ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); @@ -860,8 +815,7 @@ Tcl_WaitForEvent( #ifndef TCL_THREADS timeout.tv_sec = timePtr->sec; timeout.tv_usec = timePtr->usec; - timeoutPtr = &timeout; - } else if (tsdPtr->numFdBits == 0) { + } else if (tsdPtr->firstFileHandlerPtr == NULL) { /* * If there are no threads, no timeout, and no fds registered, * then there are no events possible and we must avoid deadlock. @@ -871,8 +825,6 @@ Tcl_WaitForEvent( */ return -1; - } else { - timeoutPtr = NULL; #endif /* !TCL_THREADS */ } @@ -932,7 +884,7 @@ Tcl_WaitForEvent( tsdPtr->pollState = POLL_WANT; timePtr = NULL; } else { - waitForFiles = (tsdPtr->numFdBits > 0); + waitForFiles = (tsdPtr->firstFileHandlerPtr != NULL); tsdPtr->pollState = 0; } @@ -957,10 +909,6 @@ Tcl_WaitForEvent( } } - 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)) { @@ -1025,21 +973,27 @@ Tcl_WaitForEvent( } #else - tsdPtr->readyMasks = tsdPtr->checkMasks; - numFound = select(tsdPtr->numFdBits, &tsdPtr->readyMasks.readable, - &tsdPtr->readyMasks.writable, &tsdPtr->readyMasks.exception, - timeoutPtr); + numfds=0; + for (filePtr = tsdPtr->firstFileHandlerPtr; filePtr != NULL; + filePtr = filePtr->nextPtr) { + numfds++; + } + pfd=ckalloc(numfds * sizeof(struct pollfd)); - /* - * Some systems don't clear the masks after an error, so we have to do - * it here. - */ + for (i=0, filePtr = tsdPtr->firstFileHandlerPtr; filePtr != NULL; + i++, filePtr = filePtr->nextPtr) { + memcpy(&pfd[i],&filePtr->pfd, sizeof(struct pollfd)); + } + + msto=timeout.tv_sec * 1000 + timeout.tv_usec / 1000; + numFound = poll(pfd, numfds, msto); - if (numFound == -1) { - FD_ZERO(&tsdPtr->readyMasks.readable); - FD_ZERO(&tsdPtr->readyMasks.writable); - FD_ZERO(&tsdPtr->readyMasks.exception); + for (i=0, filePtr = tsdPtr->firstFileHandlerPtr; filePtr != NULL; + i++, filePtr = filePtr->nextPtr) { + memcpy(&filePtr->pfd, &pfd[i], sizeof(struct pollfd)); } + + #endif /* TCL_THREADS */ /* @@ -1048,14 +1002,15 @@ Tcl_WaitForEvent( for (filePtr = tsdPtr->firstFileHandlerPtr; (filePtr != NULL); filePtr = filePtr->nextPtr) { - mask = 0; - if (FD_ISSET(filePtr->fd, &tsdPtr->readyMasks.readable)) { + + mask=0; + if (filePtr->pfd.revents & (POLLIN|POLLHUP)) { mask |= TCL_READABLE; } - if (FD_ISSET(filePtr->fd, &tsdPtr->readyMasks.writable)) { + if (filePtr->pfd.revents & POLLOUT) { mask |= TCL_WRITABLE; } - if (FD_ISSET(filePtr->fd, &tsdPtr->readyMasks.exception)) { + if (filePtr->pfd.revents & POLLERR) { mask |= TCL_EXCEPTION; } @@ -1080,6 +1035,8 @@ Tcl_WaitForEvent( } #ifdef TCL_THREADS Tcl_MutexUnlock(¬ifierMutex); +#else + ckfree(pfd); #endif /* TCL_THREADS */ return 0; } @@ -1115,15 +1072,15 @@ NotifierThreadProc( ClientData clientData) /* Not used. */ { ThreadSpecificData *tsdPtr; - fd_set readableMask; - fd_set writableMask; - fd_set exceptionMask; int fds[2]; - int i, numFdBits = 0, receivePipe; + int i, receivePipe; long found; - struct timeval poll = {0., 0.}, *timePtr; + struct timeval tpoll = {0., 0.}, *timePtr; char buf[2]; + struct pollfd *pfds=NULL; + int numfds,allocfds=0; + if (pipe(fds) != 0) { Tcl_Panic("NotifierThreadProc: %s", "could not create trigger pipe"); } @@ -1166,32 +1123,47 @@ NotifierThreadProc( */ while (1) { - FD_ZERO(&readableMask); - FD_ZERO(&writableMask); - FD_ZERO(&exceptionMask); + int pfdi, timeout; + timePtr = NULL; /* - * Compute the logical OR of the select masks from all the waiting - * notifiers. + * get total fd count */ - + numfds=1; /* include receive pipe */ Tcl_MutexLock(¬ifierMutex); - timePtr = NULL; 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); - } + FileHandler *filePtr; + + for (filePtr = tsdPtr->firstFileHandlerPtr; filePtr != NULL; + filePtr = filePtr->nextPtr) { + numfds++; + } + } + + Tcl_MutexUnlock(¬ifierMutex); + + if (allocfds<numfds) { + if (allocfds == 0) { + allocfds=4; } - if (tsdPtr->numFdBits > numFdBits) { - numFdBits = tsdPtr->numFdBits; + while (allocfds<numfds) { + allocfds*=2; } + pfds=ckrealloc(pfds, sizeof(struct pollfd)*allocfds); + } + + pfdi=0; + Tcl_MutexLock(¬ifierMutex); + for (tsdPtr = waitingListPtr; tsdPtr; tsdPtr = tsdPtr->nextPtr) { + FileHandler *filePtr; + + for (filePtr = tsdPtr->firstFileHandlerPtr; filePtr != NULL; + filePtr = filePtr->nextPtr) { + filePtr->pfd.revents=0; + memcpy(&pfds[pfdi], &filePtr->pfd, sizeof(struct pollfd)); + pfdi++; + } + if (tsdPtr->pollState & POLL_WANT) { /* * Here we make sure we go through select() with the same mask @@ -1199,22 +1171,27 @@ NotifierThreadProc( */ tsdPtr->pollState |= POLL_DONE; - timePtr = &poll; + timePtr = &tpoll; } } Tcl_MutexUnlock(¬ifierMutex); + assert(pfdi == numfds-1); + /* * Set up the select mask to include the receive pipe. */ + pfds[pfdi].fd=receivePipe; + pfds[pfdi].events=POLLIN; + pfds[pfdi].revents=0; - if (receivePipe >= numFdBits) { - numFdBits = receivePipe + 1; + if (timePtr != NULL) { + timeout=0; + } else { + timeout=-1; } - FD_SET(receivePipe, &readableMask); - if (select(numFdBits, &readableMask, &writableMask, &exceptionMask, - timePtr) == -1) { + if (poll(pfds, numfds, timeout) == -1) { /* * Try again immediately on an error. */ @@ -1230,21 +1207,17 @@ NotifierThreadProc( for (tsdPtr = waitingListPtr; tsdPtr; tsdPtr = tsdPtr->nextPtr) { found = 0; - 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 = 1; + for (i = 0; i < numfds; i++) { + if (pfds[i].revents) { + FileHandler *filePtr; + for (filePtr = tsdPtr->firstFileHandlerPtr; filePtr != NULL; + filePtr = filePtr->nextPtr) { + if (filePtr->pfd.fd == pfds[i].fd) { + filePtr->pfd.revents=pfds[i].revents; + found=1; + break; + } + } } } @@ -1285,7 +1258,7 @@ NotifierThreadProc( * avoid a race condition we only read one at a time. */ - if (FD_ISSET(receivePipe, &readableMask)) { + if (pfds[pfdi].revents & (POLLIN|POLLHUP)) { i = read(receivePipe, buf, 1); if ((i == 0) || ((i == 1) && (buf[0] == 'q'))) { |