Minor tweaks to the nonblocking select() implementation.


git-svn-id: svn://svn.valgrind.org/valgrind/trunk@108 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/coregrind/vg_libpthread.c b/coregrind/vg_libpthread.c
index 6bdf09a..065db51 100644
--- a/coregrind/vg_libpthread.c
+++ b/coregrind/vg_libpthread.c
@@ -730,12 +730,7 @@
    args[3] = (int)exceptfds;
    args[4] = (int)timeout;
    res = my_do_syscall1(__NR_select, (int)(&(args[0])) );
-   if (is_kerror(res)) {
-      * (__errno_location()) = -res;
-      return -1;
-   } else {
-      return res;
-   }
+   return res;
 }
 
 
@@ -750,6 +745,12 @@
    indicating something interesting happened, or until our time is up.
    Space out the polls with nanosleeps of say 20 milliseconds, which
    is required to be nonblocking; this allows other threads to run.  
+
+   Assumes:
+   * (checked via assert) types fd_set and vki_fd_set are identical.
+   * (checked via assert) types timeval and vki_timeval are identical.
+   * (unchecked) libc error numbers (EINTR etc) are the negation of the
+     kernel's error numbers (VKI_EINTR etc).
 */
 #include <assert.h>
 
@@ -768,6 +769,7 @@
    struct vki_timeval  t_end;
    struct vki_timeval  zero_timeout;
    struct vki_timespec nanosleep_interval;
+   int                 nanosleep_usec;
 
    ensure_valgrind("select");
 
@@ -779,14 +781,27 @@
       barf("valgrind's hacky non-blocking select(): data sizes error");
 
    /* If a zero timeout specified, this call is harmless. */
-   if (timeout && timeout->tv_sec == 0 && timeout->tv_usec == 0)
-      return do_syscall_select( n, (vki_fd_set*)rfds, 
+   if (timeout && timeout->tv_sec == 0 && timeout->tv_usec == 0) {
+      res = do_syscall_select( n, (vki_fd_set*)rfds, 
                                    (vki_fd_set*)wfds, 
                                    (vki_fd_set*)xfds, 
                                    (struct vki_timeval*)timeout);
+      if (is_kerror(res)) {
+         * (__errno_location()) = -res;
+         return -1;
+      } else {
+         return res;
+      }
+   }
 
    /* If a timeout was specified, set t_end to be the end wallclock
       time. */
+
+   /* Sleep in 50 millisecond intervals, unless the total duration is
+      one second or less, in which case sleep in 20 millisecond
+      intervals. */
+   nanosleep_usec = 50 * 1000;
+
    if (timeout) {
       res = my_do_syscall2(__NR_gettimeofday, (int)&t_now, (int)NULL);
       assert(res == 0);
@@ -801,6 +816,8 @@
       assert (t_end.tv_sec > t_now.tv_sec
               || (t_end.tv_sec == t_now.tv_sec 
                   && t_end.tv_usec >= t_now.tv_usec));
+      if (timeout->tv_sec == 0)
+         nanosleep_usec = 20 * 1000;
    }
 
    /* fprintf(stderr, "MY_SELECT: before loop\n"); */
@@ -835,10 +852,11 @@
                                wfds ? (vki_fd_set*)(&wfds_copy) : NULL,
                                xfds ? (vki_fd_set*)(&xfds_copy) : NULL,
                                & zero_timeout );
-      if (res < 0) {
-         /* some kind of error (including EINTR); errno is set, so just
+      if (is_kerror(res)) {
+         /* Some kind of error (including EINTR).  Set errno and
             return.  The sets are unspecified in this case. */
-         return res;
+         * (__errno_location()) = -res;
+         return -1;
       }
       if (res > 0) {
          /* one or more fds is ready.  Copy out resulting sets and
@@ -850,8 +868,8 @@
       }
       /* fprintf(stderr, "MY_SELECT: nanosleep\n"); */
       /* nanosleep and go round again */
-      nanosleep_interval.tv_sec = 0;
-      nanosleep_interval.tv_nsec = 20 * 1000 * 1000; /* 20 milliseconds */
+      nanosleep_interval.tv_sec  = 0;
+      nanosleep_interval.tv_nsec = 1000 * nanosleep_usec;
       /* It's critical here that valgrind's nanosleep implementation
          is nonblocking. */
       (void)my_do_syscall2(__NR_nanosleep,