Add a nonblocking poll() -- same trick as nonblocking select().
Add pthread_cond_destroy().


git-svn-id: svn://svn.valgrind.org/valgrind/trunk@110 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/coregrind/arch/x86-linux/vg_libpthread.c b/coregrind/arch/x86-linux/vg_libpthread.c
index 065db51..f5c5361 100644
--- a/coregrind/arch/x86-linux/vg_libpthread.c
+++ b/coregrind/arch/x86-linux/vg_libpthread.c
@@ -373,6 +373,12 @@
    return 0;
 }
 
+int pthread_cond_destroy(pthread_cond_t *cond)
+{
+   /* should check that no threads are waiting on this CV */
+   kludged("pthread_cond_destroy");
+   return 0;
+}
 
 /* ---------------------------------------------------
    SCHEDULING
@@ -704,7 +710,7 @@
 
 static
 int my_do_syscall2 ( int syscallno, 
-                      int arg1, int arg2 )
+                     int arg1, int arg2 )
 { 
    int __res;
    __asm__ volatile ("pushl %%ebx; movl %%edx,%%ebx ; int $0x80 ; popl %%ebx"
@@ -716,6 +722,20 @@
 }
 
 static
+int my_do_syscall3 ( int syscallno, 
+                     int arg1, int arg2, int arg3 )
+{ 
+   int __res;
+   __asm__ volatile ("pushl %%ebx; movl %%esi,%%ebx ; int $0x80 ; popl %%ebx"
+                     : "=a" (__res)
+                     : "0" (syscallno),
+                       "S" (arg1),
+                       "c" (arg2),
+                       "d" (arg3) );
+   return __res;
+}
+
+static
 int do_syscall_select( int n, 
                        vki_fd_set* readfds, 
                        vki_fd_set* writefds, 
@@ -769,7 +789,6 @@
    struct vki_timeval  t_end;
    struct vki_timeval  zero_timeout;
    struct vki_timespec nanosleep_interval;
-   int                 nanosleep_usec;
 
    ensure_valgrind("select");
 
@@ -796,12 +815,6 @@
 
    /* 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);
@@ -816,8 +829,6 @@
       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"); */
@@ -869,7 +880,96 @@
       /* fprintf(stderr, "MY_SELECT: nanosleep\n"); */
       /* nanosleep and go round again */
       nanosleep_interval.tv_sec  = 0;
-      nanosleep_interval.tv_nsec = 1000 * nanosleep_usec;
+      nanosleep_interval.tv_nsec = 75 * 1000 * 1000; /* 75 milliseconds */
+      /* It's critical here that valgrind's nanosleep implementation
+         is nonblocking. */
+      (void)my_do_syscall2(__NR_nanosleep, 
+                           (int)(&nanosleep_interval), (int)NULL);
+   }
+}
+
+
+
+
+#include <sys/poll.h>
+
+int poll (struct pollfd *__fds, nfds_t __nfds, int __timeout)
+{
+   int                 res, i;
+   struct vki_timeval  t_now;
+   struct vki_timeval  t_end;
+   struct vki_timespec nanosleep_interval;
+
+   ensure_valgrind("poll");
+
+   if (/* CHECK SIZES FOR struct pollfd */
+       sizeof(struct timeval) != sizeof(struct vki_timeval))
+      barf("valgrind's hacky non-blocking poll(): data sizes error");
+
+   /* If a zero timeout specified, this call is harmless. */
+   if (__timeout == 0) {
+      res = my_do_syscall3(__NR_poll, (int)__fds, __nfds, __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. */
+   if (__timeout > 0) {
+      res = my_do_syscall2(__NR_gettimeofday, (int)&t_now, (int)NULL);
+      assert(res == 0);
+      t_end = t_now;
+      t_end.tv_usec += 1000 * (__timeout % 1000);
+      t_end.tv_sec  += (__timeout / 1000);
+      if (t_end.tv_usec >= 1000000) {
+         t_end.tv_usec -= 1000000;
+         t_end.tv_sec += 1;
+      }
+      /* Stay sane ... */
+      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));
+   }
+
+   /* fprintf(stderr, "MY_POLL: before loop\n"); */
+
+   /* Either timeout < 0, meaning wait indefinitely, or timeout > 0,
+      in which case t_end holds the end time. */
+   while (1) {
+      assert(__timeout != 0);
+      if (__timeout > 0) {
+         res = my_do_syscall2(__NR_gettimeofday, (int)&t_now, (int)NULL);
+         assert(res == 0);
+         if (t_now.tv_sec > t_end.tv_sec
+             || (t_now.tv_sec == t_end.tv_sec 
+                 && t_now.tv_usec > t_end.tv_usec)) {
+            /* timeout; nothing interesting happened. */
+            for (i = 0; i < __nfds; i++) 
+               __fds[i].revents = 0;
+            return 0;
+         }
+      }
+
+      /* These could be trashed each time round the loop, so restore
+         them each time. */
+      res = my_do_syscall3(__NR_poll, (int)__fds, __nfds, 0 );
+      if (is_kerror(res)) {
+         /* Some kind of error.  Set errno and return.  */
+         * (__errno_location()) = -res;
+         return -1;
+      }
+      if (res > 0) {
+         /* One or more fds is ready.  Return now. */
+         return res;
+      }
+      /* fprintf(stderr, "MY_POLL: nanosleep\n"); */
+      /* nanosleep and go round again */
+      nanosleep_interval.tv_sec  = 0;
+      nanosleep_interval.tv_nsec = 100 * 1000 * 1000; /* 100 milliseconds */
       /* It's critical here that valgrind's nanosleep implementation
          is nonblocking. */
       (void)my_do_syscall2(__NR_nanosleep, 
diff --git a/coregrind/vg_libpthread.c b/coregrind/vg_libpthread.c
index 065db51..f5c5361 100644
--- a/coregrind/vg_libpthread.c
+++ b/coregrind/vg_libpthread.c
@@ -373,6 +373,12 @@
    return 0;
 }
 
+int pthread_cond_destroy(pthread_cond_t *cond)
+{
+   /* should check that no threads are waiting on this CV */
+   kludged("pthread_cond_destroy");
+   return 0;
+}
 
 /* ---------------------------------------------------
    SCHEDULING
@@ -704,7 +710,7 @@
 
 static
 int my_do_syscall2 ( int syscallno, 
-                      int arg1, int arg2 )
+                     int arg1, int arg2 )
 { 
    int __res;
    __asm__ volatile ("pushl %%ebx; movl %%edx,%%ebx ; int $0x80 ; popl %%ebx"
@@ -716,6 +722,20 @@
 }
 
 static
+int my_do_syscall3 ( int syscallno, 
+                     int arg1, int arg2, int arg3 )
+{ 
+   int __res;
+   __asm__ volatile ("pushl %%ebx; movl %%esi,%%ebx ; int $0x80 ; popl %%ebx"
+                     : "=a" (__res)
+                     : "0" (syscallno),
+                       "S" (arg1),
+                       "c" (arg2),
+                       "d" (arg3) );
+   return __res;
+}
+
+static
 int do_syscall_select( int n, 
                        vki_fd_set* readfds, 
                        vki_fd_set* writefds, 
@@ -769,7 +789,6 @@
    struct vki_timeval  t_end;
    struct vki_timeval  zero_timeout;
    struct vki_timespec nanosleep_interval;
-   int                 nanosleep_usec;
 
    ensure_valgrind("select");
 
@@ -796,12 +815,6 @@
 
    /* 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);
@@ -816,8 +829,6 @@
       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"); */
@@ -869,7 +880,96 @@
       /* fprintf(stderr, "MY_SELECT: nanosleep\n"); */
       /* nanosleep and go round again */
       nanosleep_interval.tv_sec  = 0;
-      nanosleep_interval.tv_nsec = 1000 * nanosleep_usec;
+      nanosleep_interval.tv_nsec = 75 * 1000 * 1000; /* 75 milliseconds */
+      /* It's critical here that valgrind's nanosleep implementation
+         is nonblocking. */
+      (void)my_do_syscall2(__NR_nanosleep, 
+                           (int)(&nanosleep_interval), (int)NULL);
+   }
+}
+
+
+
+
+#include <sys/poll.h>
+
+int poll (struct pollfd *__fds, nfds_t __nfds, int __timeout)
+{
+   int                 res, i;
+   struct vki_timeval  t_now;
+   struct vki_timeval  t_end;
+   struct vki_timespec nanosleep_interval;
+
+   ensure_valgrind("poll");
+
+   if (/* CHECK SIZES FOR struct pollfd */
+       sizeof(struct timeval) != sizeof(struct vki_timeval))
+      barf("valgrind's hacky non-blocking poll(): data sizes error");
+
+   /* If a zero timeout specified, this call is harmless. */
+   if (__timeout == 0) {
+      res = my_do_syscall3(__NR_poll, (int)__fds, __nfds, __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. */
+   if (__timeout > 0) {
+      res = my_do_syscall2(__NR_gettimeofday, (int)&t_now, (int)NULL);
+      assert(res == 0);
+      t_end = t_now;
+      t_end.tv_usec += 1000 * (__timeout % 1000);
+      t_end.tv_sec  += (__timeout / 1000);
+      if (t_end.tv_usec >= 1000000) {
+         t_end.tv_usec -= 1000000;
+         t_end.tv_sec += 1;
+      }
+      /* Stay sane ... */
+      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));
+   }
+
+   /* fprintf(stderr, "MY_POLL: before loop\n"); */
+
+   /* Either timeout < 0, meaning wait indefinitely, or timeout > 0,
+      in which case t_end holds the end time. */
+   while (1) {
+      assert(__timeout != 0);
+      if (__timeout > 0) {
+         res = my_do_syscall2(__NR_gettimeofday, (int)&t_now, (int)NULL);
+         assert(res == 0);
+         if (t_now.tv_sec > t_end.tv_sec
+             || (t_now.tv_sec == t_end.tv_sec 
+                 && t_now.tv_usec > t_end.tv_usec)) {
+            /* timeout; nothing interesting happened. */
+            for (i = 0; i < __nfds; i++) 
+               __fds[i].revents = 0;
+            return 0;
+         }
+      }
+
+      /* These could be trashed each time round the loop, so restore
+         them each time. */
+      res = my_do_syscall3(__NR_poll, (int)__fds, __nfds, 0 );
+      if (is_kerror(res)) {
+         /* Some kind of error.  Set errno and return.  */
+         * (__errno_location()) = -res;
+         return -1;
+      }
+      if (res > 0) {
+         /* One or more fds is ready.  Return now. */
+         return res;
+      }
+      /* fprintf(stderr, "MY_POLL: nanosleep\n"); */
+      /* nanosleep and go round again */
+      nanosleep_interval.tv_sec  = 0;
+      nanosleep_interval.tv_nsec = 100 * 1000 * 1000; /* 100 milliseconds */
       /* It's critical here that valgrind's nanosleep implementation
          is nonblocking. */
       (void)my_do_syscall2(__NR_nanosleep,