Attachment "tcl_poll.patch" to
ticket [1960647fff]
added by
stwo
2008-05-09 08:08:09.
diff -urN ot/tcl8.5.2/unix/configure.in nt/tcl8.5.2/unix/configure.in
--- ot/tcl8.5.2/unix/configure.in Fri Mar 28 14:41:53 2008
+++ nt/tcl8.5.2/unix/configure.in Thu May 8 20:51:20 2008
@@ -492,6 +492,12 @@
AC_CHECK_FUNCS(chflags)
#--------------------------------------------------------------------
+# Check for support of poll function
+#--------------------------------------------------------------------
+
+AC_CHECK_FUNCS(poll)
+
+#--------------------------------------------------------------------
# Darwin specific API checks and defines
#--------------------------------------------------------------------
diff -urN ot/tcl8.5.2/unix/tclUnixChan.c nt/tcl8.5.2/unix/tclUnixChan.c
--- ot/tcl8.5.2/unix/tclUnixChan.c Mon Mar 3 09:54:43 2008
+++ nt/tcl8.5.2/unix/tclUnixChan.c Thu May 8 20:51:20 2008
@@ -16,6 +16,10 @@
#include "tclInt.h" /* Internal definitions for Tcl. */
#include "tclIO.h" /* To get Channel type declaration. */
+#ifdef HAVE_POLL
+# include <poll.h>
+#endif
+
#define SUPPORTS_TTY
#undef DIRECT_BAUD
@@ -3021,16 +3025,128 @@
* at all, and a value of -1 means wait
* forever. */
{
+#ifdef HAVE_POLL
+ int numFound, pollTimeout = 0, result = 0;
+ Tcl_Time start, delta;
+ struct pollfd pfd;
+
+ /*
+ * If there is a non-zero finite timeout, compute the time when we give
+ * up.
+ */
+
+ if (timeout < 0) {
+ timeout = INFTIM;
+ } else {
+ pollTimeout = timeout;
+ if (timeout > 0) {
+ Tcl_GetTime(&start);
+ }
+ }
+
+ /*
+ * Initialize the poll file descriptor structure.
+ */
+
+# define TCL_POLL_READ_EVENTS (POLLIN | POLLPRI | POLLRDNORM | POLLRDBAND)
+# define TCL_POLL_WRITE_EVENTS (POLLOUT | POLLWRBAND)
+# define TCL_POLL_EXCEPT_EVENTS_SET POLLERR
+# define TCL_POLL_EXCEPT_EVENTS_GET (POLLERR | POLLHUP)
+# define TCL_POLL_ERR_EVENTS POLLNVAL
+
+ pfd.fd = fd;
+ pfd.events = 0;
+ if (mask & TCL_READABLE) {
+ SET_BITS(pfd.events, TCL_POLL_READ_EVENTS);
+ }
+ if (mask & TCL_WRITABLE) {
+ SET_BITS(pfd.events, TCL_POLL_WRITE_EVENTS);
+ }
+ if (mask & TCL_EXCEPTION) {
+ SET_BITS(pfd.events, TCL_POLL_EXCEPT_EVENTS_SET);
+ }
+
+ /*
+ * Loop in a mini-event loop of our own, waiting for either the
+ * file to become ready or a timeout to occur.
+ */
+
+ while (1) {
+
+ /*
+ * Wait for the event or a timeout.
+ */
+
+ numFound = poll(&pfd, (nfds_t) 1, timeout);
+ if (numFound == 1) {
+ if (pfd.revents & TCL_POLL_ERR_EVENTS) {
+ Tcl_Panic("TclWaitForFile can't handle file id %d", fd);
+ }
+ if (pfd.revents & TCL_POLL_READ_EVENTS) {
+ SET_BITS(result, TCL_READABLE);
+ }
+ if (pfd.revents & TCL_POLL_WRITE_EVENTS) {
+ SET_BITS(result, TCL_WRITABLE);
+ }
+ if (pfd.revents & TCL_POLL_EXCEPT_EVENTS_GET) {
+ SET_BITS(result, TCL_EXCEPTION);
+ }
+ result &= mask;
+ if (result) {
+ break;
+ }
+ } else if (numFound == -1 && errno != EINTR) {
+ Tcl_Panic("TclWaitForFile poll error %d", errno);
+ }
+ if (timeout == 0) {
+ break;
+ }
+ if (timeout == INFTIM) {
+ continue;
+ }
+
+ /*
+ * The poll returned early, so we need to recompute the timeout.
+ */
+
+ Tcl_GetTime(&delta);
+ delta.usec -= start.usec;
+ delta.sec -= start.sec;
+ if (delta.usec < 0) {
+ delta.sec -= 1;
+ delta.usec += 1000000;
+ }
+ timeout = pollTimeout;
+ if (delta.sec > 0) {
+ timeout -= (delta.sec * 1000);
+ }
+ if (delta.usec >= 1000) {
+ timeout -= (delta.usec / 1000);
+ }
+ if (timeout < 0) {
+ break;
+ }
+ }
+ return result;
+#else
Tcl_Time abortTime = {0, 0}, now; /* silence gcc 4 warning */
struct timeval blockTime, *timeoutPtr;
- int index, numFound, result = 0;
- fd_mask bit;
- fd_mask readyMasks[3*MASK_SIZE];
- fd_mask *maskp[3]; /* This array reflects the readable/writable
- * conditions that were found to exist by the
- * last call to select. */
+ int numFound, result = 0;
+ fd_set readableMask;
+ fd_set writableMask;
+ fd_set exceptionalMask;
+
/*
+ * Sanity check fd.
+ */
+
+ if (fd >= FD_SETSIZE) {
+ Tcl_Panic("TclWaitForFile can't handle file id %d", fd);
+ /* must never get here, or select masks overrun will occur below */
+ }
+
+ /*
* If there is a non-zero finite timeout, compute the time when we give
* up.
*/
@@ -3053,16 +3169,12 @@
}
/*
- * Initialize the ready masks and compute the mask offsets.
+ * Initialize the select masks.
*/
- if (fd >= FD_SETSIZE) {
- Tcl_Panic("TclWaitForFile can't handle file id %d", fd);
- /* must never get here, or readyMasks overrun will occur below */
- }
- memset(readyMasks, 0, 3*MASK_SIZE*sizeof(fd_mask));
- index = fd / (NBBY*sizeof(fd_mask));
- bit = ((fd_mask)1) << (fd % (NBBY*sizeof(fd_mask)));
+ FD_ZERO(&readableMask);
+ FD_ZERO(&writableMask);
+ FD_ZERO(&exceptionalMask);
/*
* Loop in a mini-event loop of our own, waiting for either the file to
@@ -3084,41 +3196,32 @@
}
/*
- * Set the appropriate bit in the ready masks for the fd.
+ * Compute the logical OR of the select masks for the fd.
*/
- if (mask & TCL_READABLE) {
- readyMasks[index] |= bit;
+ if (mask & TCL_READABLE) {
+ FD_SET(fd, &readableMask);
}
- if (mask & TCL_WRITABLE) {
- (readyMasks+MASK_SIZE)[index] |= bit;
+ if (mask & TCL_WRITABLE) {
+ FD_SET(fd, &writableMask);
}
if (mask & TCL_EXCEPTION) {
- (readyMasks+2*(MASK_SIZE))[index] |= bit;
+ FD_SET(fd, &exceptionalMask);
}
/*
* Wait for the event or a timeout.
*/
- /*
- * This is needed to satisfy GCC 3.3's strict aliasing rules.
- */
-
- maskp[0] = &readyMasks[0];
- maskp[1] = &readyMasks[MASK_SIZE];
- maskp[2] = &readyMasks[2*MASK_SIZE];
- numFound = select(fd+1, (SELECT_MASK *) maskp[0],
- (SELECT_MASK *) maskp[1],
- (SELECT_MASK *) maskp[2], timeoutPtr);
+ numFound = select(fd + 1, &readableMask, &writableMask, &exceptionalMask, timeoutPtr);
if (numFound == 1) {
- if (readyMasks[index] & bit) {
+ if (FD_ISSET(fd, &readableMask)) {
SET_BITS(result, TCL_READABLE);
}
- if ((readyMasks+MASK_SIZE)[index] & bit) {
+ if (FD_ISSET(fd, &writableMask)) {
SET_BITS(result, TCL_WRITABLE);
}
- if ((readyMasks+2*(MASK_SIZE))[index] & bit) {
+ if (FD_ISSET(fd, &exceptionalMask)) {
SET_BITS(result, TCL_EXCEPTION);
}
result &= mask;
@@ -3144,6 +3247,7 @@
}
}
return result;
+#endif
}
/*