Tcl Source Code

Artifact [91c44d2af1]
Login

Artifact 91c44d2af1f36fcf5779d7f5da13802e45912fec:

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
 }
 
 /*