From 016f2988dd6f27594cc32e01cb33bd9c786c570f Mon Sep 17 00:00:00 2001 From: dkf Date: Thu, 26 May 2016 11:12:46 +0000 Subject: Experimental branch on whether to use poll() instead of select(). --- unix/configure | 32 +++++++++++++++++++++ unix/configure.ac | 7 +++++ unix/tclUnixChan.c | 83 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 121 insertions(+), 1 deletion(-) 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 +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 ],[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 ?]) +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 +# 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 */ -- cgit v0.12