summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordkf <donal.k.fellows@manchester.ac.uk>2016-05-26 11:12:46 (GMT)
committerdkf <donal.k.fellows@manchester.ac.uk>2016-05-26 11:12:46 (GMT)
commit016f2988dd6f27594cc32e01cb33bd9c786c570f (patch)
treeecde33bb27efa9f0fe0a06fec948f7e4dad495be
parentcbcbd348f992ab2ae52e313fe1bb8cb51e69027d (diff)
downloadtcl-dkf_wait_with_poll.zip
tcl-dkf_wait_with_poll.tar.gz
tcl-dkf_wait_with_poll.tar.bz2
Experimental branch on whether to use poll() instead of select().dkf_wait_with_poll
-rwxr-xr-xunix/configure32
-rw-r--r--unix/configure.ac7
-rw-r--r--unix/tclUnixChan.c83
3 files changed, 121 insertions, 1 deletions
diff --git a/unix/configure b/unix/configure
index e999455..a1ef43f 100755
--- a/unix/configure
+++ b/unix/configure
@@ -8442,6 +8442,38 @@ $as_echo "#define NO_FD_SET 1" >>confdefs.h
fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for struct pollfd in poll.h" >&5
+$as_echo_n "checking for struct pollfd in poll.h... " >&6; }
+if ${tcl_cv_type_struct_pollfd+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <poll.h>
+int
+main ()
+{
+struct pollfd fds[1];
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ tcl_cv_type_struct_pollfd=yes
+else
+ tcl_cv_type_struct_pollfd=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_type_struct_pollfd" >&5
+$as_echo "$tcl_cv_type_struct_pollfd" >&6; }
+if test $tcl_cv_type_struct_pollfd = yes; then
+
+$as_echo "#define HAVE_POLL_H 1" >>confdefs.h
+
+fi
+
#------------------------------------------------------------------------------
# Find out all about time handling differences.
#------------------------------------------------------------------------------
diff --git a/unix/configure.ac b/unix/configure.ac
index 41a1f62..060525d 100644
--- a/unix/configure.ac
+++ b/unix/configure.ac
@@ -301,6 +301,13 @@ if test $tcl_ok = no; then
AC_DEFINE(NO_FD_SET, 1, [Do we have fd_set?])
fi
+AC_CACHE_CHECK([for struct pollfd in poll.h], tcl_cv_type_struct_pollfd, [
+ AC_TRY_COMPILE([#include <poll.h>],[struct pollfd fds[1];],
+ tcl_cv_type_struct_pollfd=yes, tcl_cv_type_struct_pollfd=no)])
+if test $tcl_cv_type_struct_pollfd = yes; then
+ AC_DEFINE(HAVE_POLL_H, 1, [Can we use <poll.h>?])
+fi
+
#------------------------------------------------------------------------------
# Find out all about time handling differences.
#------------------------------------------------------------------------------
diff --git a/unix/tclUnixChan.c b/unix/tclUnixChan.c
index b4b2739..4afb44a 100644
--- a/unix/tclUnixChan.c
+++ b/unix/tclUnixChan.c
@@ -14,6 +14,12 @@
#include "tclInt.h" /* Internal definitions for Tcl. */
#include "tclIO.h" /* To get Channel type declaration. */
+#undef USE_POLL_FOR_SINGLE_FD_WAIT
+#ifdef HAVE_POLL_H
+# include <poll.h>
+# define USE_POLL_FOR_SINGLE_FD_WAIT
+#endif
+
#undef SUPPORTS_TTY
#if defined(HAVE_TERMIOS_H)
# define SUPPORTS_TTY 1
@@ -1764,8 +1770,82 @@ TclUnixWaitForFile(
* forever. */
{
Tcl_Time abortTime = {0, 0}, now; /* silence gcc 4 warning */
- struct timeval blockTime, *timeoutPtr;
int numFound, result = 0;
+#ifdef USE_POLL_FOR_SINGLE_FD_WAIT
+ struct pollfd pfd;
+ int timeRemaining;
+
+ pfd.fd = fd;
+ pfd.events = 0;
+ if (mask & TCL_READABLE) {
+ pfd.events |= POLLIN;
+ }
+ if (mask & TCL_WRITABLE) {
+ pfd.events |= POLLOUT;
+ }
+
+ /*
+ * Compute how much time remaining. With a positive timeout, we need to
+ * also track when we want to finish by as an absolute timestamp because
+ * otherwise we can't restart the system call correctly.
+ */
+
+ timeRemaining = timeout;
+ if (timeout > 0) {
+ Tcl_GetTime(&now);
+ abortTime.sec = now.sec + timeout/1000;
+ abortTime.usec = now.usec + (timeout%1000)*1000;
+ if (abortTime.usec >= 1000000) {
+ abortTime.usec -= 1000000;
+ abortTime.sec += 1;
+ }
+ }
+
+ /*
+ * Loop to allow restarting poll().
+ */
+
+ do {
+ pfd.revents = 0;
+ numFound = poll(&pfd, 1, timeRemaining);
+ if (result > 0) {
+ if (pfd.revents & POLLIN) {
+ SET_BITS(result, TCL_READABLE);
+ }
+ if (pfd.revents & POLLOUT) {
+ SET_BITS(result, TCL_WRITABLE);
+ }
+ if (pfd.revents & (POLLERR | POLLHUP | POLLNVAL)) {
+ SET_BITS(result, TCL_EXCEPTION);
+ }
+ } else if (result < 0) {
+ int e = errno;
+
+ /*
+ * Some errors just mean that we should restart the call. Model
+ * the rest as exception cases.
+ */
+
+ if (e != EINTR || e != EAGAIN || e != ENOMEM) {
+ SET_BITS(result, TCL_EXCEPTION);
+ }
+ }
+
+ if (timeout > 0) {
+ Tcl_GetTime(&now);
+ timeRemaining = 1000 * (abortTime.sec - now.sec)
+ + (abortTime.usec - now.usec) / 1000;
+ }
+ } while ((result & mask) == 0 && (timeout < 0 || timeRemaining > 0));
+
+ /*
+ * Only return bits that the caller asked for.
+ */
+
+ return result & mask;
+
+#else /* !USE_POLL_FOR_SINGLE_FD_WAIT */
+ struct timeval blockTime, *timeoutPtr;
fd_set readableMask;
fd_set writableMask;
fd_set exceptionMask;
@@ -1883,6 +1963,7 @@ TclUnixWaitForFile(
}
}
return result;
+#endif /* USE_POLL_FOR_SINGLE_FD_WAIT */
}
#endif /* HAVE_COREFOUNDATION */