Fix threading problems on glibc-2.3.2 or later.  Note this is *not*
NPTL support.

The behaviour of weak vs strong symbols seems to have changed in
glibc-2.3.2.  This caused problems in coregrind/vg_intercept.c,
wherein strong symbols in vg_libpthread.c were intended to
override weak symbols in vg_intercept.c, in order to give alternative
thread-safe implementations of some functions, poll(), select(), etc.

The change involves moving the nonblocking implementations of poll, etc
into vg_intercept.c, renaming them to (eg)  VGR_(poll), and routing
all calls to poll to VGR_(poll) [dually for other such fns].  This
means even single-threaded programs now use these functions, but
that doesn't strike me as harmful.

MERGE TO STABLE, if it doesn't break anything


git-svn-id: svn://svn.valgrind.org/valgrind/trunk@1559 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/coregrind/arch/x86-linux/vg_libpthread.c b/coregrind/arch/x86-linux/vg_libpthread.c
index 400af5d..3db4db5 100644
--- a/coregrind/arch/x86-linux/vg_libpthread.c
+++ b/coregrind/arch/x86-linux/vg_libpthread.c
@@ -78,8 +78,8 @@
    Forwardses.
    ------------------------------------------------------------------ */
 
-static void wait_for_fd_to_be_readable_or_erring ( int fd );
-static void wait_for_fd_to_be_writable_or_erring ( int fd );
+#define WEAK	__attribute__((weak))
+
 
 static
 int my_do_syscall1 ( int syscallno, int arg1 );
@@ -350,7 +350,7 @@
    return 0;
 }
 
-__attribute__((weak))
+WEAK
 int pthread_attr_setstacksize (pthread_attr_t *__attr,
                                size_t __stacksize)
 {
@@ -452,7 +452,7 @@
 
 
 /* Bogus ... */
-__attribute__((weak))
+WEAK
 int pthread_attr_getstackaddr ( const pthread_attr_t * attr,
                                 void ** stackaddr )
 {
@@ -464,7 +464,7 @@
 }
 
 /* Not bogus (!) */
-__attribute__((weak))
+WEAK
 int pthread_attr_getstacksize ( const pthread_attr_t * _attr, 
                                 size_t * __stacksize )
 {
@@ -495,7 +495,7 @@
 /* This is completely bogus.  We reject all attempts to change it from
    VKI_BYTES_PER_PAGE.  I don't have a clue what it's for so it seems
    safest to be paranoid. */
-__attribute__((weak)) 
+WEAK 
 int pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize)
 {
    static int moans = N_MOANS;
@@ -510,7 +510,7 @@
 }
 
 /* A straight copy of the LinuxThreads code. */
-__attribute__((weak)) 
+WEAK 
 int pthread_attr_getguardsize(const pthread_attr_t *attr, size_t *guardsize)
 {
    *guardsize = attr->__guardsize;
@@ -521,7 +521,7 @@
 
 static int concurrency_current_level = 0;
 
-__attribute__((weak)) 
+WEAK 
 int pthread_setconcurrency(int new_level)
 {
    if (new_level < 0)
@@ -532,7 +532,7 @@
    }
 }
 
-__attribute__((weak)) 
+WEAK 
 int pthread_getconcurrency(void)
 {
    return concurrency_current_level;
@@ -678,7 +678,7 @@
    THREADs
    ------------------------------------------------ */
 
-__attribute__((weak))
+WEAK
 int pthread_yield ( void )
 {
    int res;
@@ -1566,7 +1566,7 @@
 }
 
 
-__attribute__((weak)) 
+WEAK 
 void __pthread_initialize ( void )
 {
    ensure_valgrind("__pthread_initialize");
@@ -1775,10 +1775,6 @@
    to the corresponding thread-unaware (?) libc routine.
    ------------------------------------------------------------------ */
 
-#include <stdlib.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-
 #ifdef GLIBC_2_1
 extern
 int __sigaction
@@ -1809,7 +1805,7 @@
 int  __libc_connect(int  sockfd,  
                     const  struct  sockaddr  *serv_addr, 
                     socklen_t addrlen);
-__attribute__((weak))
+WEAK
 int  connect(int  sockfd,  
              const  struct  sockaddr  *serv_addr, 
              socklen_t addrlen)
@@ -1821,7 +1817,7 @@
 
 extern
 int __libc_fcntl(int fd, int cmd, long arg);
-__attribute__((weak))
+WEAK
 int fcntl(int fd, int cmd, long arg)
 {
    __my_pthread_testcancel();
@@ -1831,7 +1827,7 @@
 
 extern 
 ssize_t __libc_write(int fd, const void *buf, size_t count);
-__attribute__((weak))
+WEAK
 ssize_t write(int fd, const void *buf, size_t count)
 {
    __my_pthread_testcancel();
@@ -1841,7 +1837,7 @@
 
 extern 
 ssize_t __libc_read(int fd, void *buf, size_t count);
-__attribute__((weak))
+WEAK
 ssize_t read(int fd, void *buf, size_t count)
 {
    __my_pthread_testcancel();
@@ -1987,7 +1983,7 @@
 
 extern
 int __libc_open64(const char *pathname, int flags, mode_t mode);
-/* __attribute__((weak)) */
+/* WEAK */
 int open64(const char *pathname, int flags, mode_t mode)
 {
    return _open(pathname, flags, mode, __libc_open64);
@@ -1995,7 +1991,7 @@
 
 extern
 int __libc_open(const char *pathname, int flags, mode_t mode);
-/* __attribute__((weak)) */
+/* WEAK */
 int open(const char *pathname, int flags, mode_t mode)
 {
    return _open(pathname, flags, mode, __libc_open);
@@ -2003,7 +1999,7 @@
 
 extern
 int __libc_close(int fd);
-__attribute__((weak))
+WEAK
 int close(int fd)
 {
    __my_pthread_testcancel();
@@ -2011,63 +2007,33 @@
 }
 
 
-extern
-int __libc_accept(int s, struct sockaddr *addr, socklen_t *addrlen);
-
-int VGL_(accept)(int s, struct sockaddr *addr, socklen_t *addrlen)
+WEAK
+int accept(int s, struct sockaddr *addr, socklen_t *addrlen)
 {
-   __my_pthread_testcancel();
-   wait_for_fd_to_be_readable_or_erring(s);
-   __my_pthread_testcancel();
-   return __libc_accept(s, addr, addrlen);
+   return VGR_(accept)(s, addr, addrlen);
 }
 
-extern
-int __libc_recv(int s, void *buf, size_t len, int flags);
-
-int VGL_(recv)(int s, void *buf, size_t len, int flags)
+WEAK
+int recv(int s, void *buf, size_t len, int flags)
 {
-   __my_pthread_testcancel();
-   wait_for_fd_to_be_readable_or_erring(s);
-   __my_pthread_testcancel();
-   return __libc_recv(s, buf, len, flags);
+   return VGR_(recv)(s, buf, len, flags);
 }
 
-int VGL_(readv)(int fd, const struct iovec *iov, int count)
+WEAK
+int readv(int fd, const struct iovec *iov, int count)
 {
-   int res;
-
-   __my_pthread_testcancel();
-   wait_for_fd_to_be_readable_or_erring(fd);
-   __my_pthread_testcancel();
-   res = my_do_syscall3(__NR_readv, fd, (unsigned)iov, count);
-
-   if (is_kerror(res)) {
-      *(__errno_location()) = -res;
-      return -1;
-   }
-   return res;
+  return VGR_(readv)(fd, iov, count);
 }
 
-int VGL_(writev)(int fd, struct iovec *iov, int count)
+WEAK
+int writev(int fd, const struct iovec *iov, int count)
 {
-   int res;
-
-   __my_pthread_testcancel();
-   wait_for_fd_to_be_writable_or_erring(fd);
-   __my_pthread_testcancel();
-   res = my_do_syscall3(__NR_writev, fd, (unsigned)iov, count);
-
-   if (is_kerror(res)) {
-      *(__errno_location()) = -res;
-      return -1;
-   }
-   return res;
+  return VGR_(writev)(fd, iov, count);
 }
 
 extern
 pid_t __libc_waitpid(pid_t pid, int *status, int options);
-__attribute__((weak))
+WEAK
 pid_t waitpid(pid_t pid, int *status, int options)
 {
    __my_pthread_testcancel();
@@ -2077,7 +2043,7 @@
 
 extern
 int __libc_nanosleep(const struct timespec *req, struct timespec *rem);
-__attribute__((weak))
+WEAK
 int nanosleep(const struct timespec *req, struct timespec *rem)
 {
    __my_pthread_testcancel();
@@ -2087,7 +2053,7 @@
 
 extern
 int __libc_fsync(int fd);
-__attribute__((weak))
+WEAK
 int fsync(int fd)
 {
    __my_pthread_testcancel();
@@ -2097,7 +2063,7 @@
 
 extern
 off_t __libc_lseek(int fildes, off_t offset, int whence);
-__attribute__((weak))
+WEAK
 off_t lseek(int fildes, off_t offset, int whence)
 {
    __my_pthread_testcancel();
@@ -2107,7 +2073,7 @@
 
 extern
 __off64_t __libc_lseek64(int fildes, __off64_t offset, int whence);
-__attribute__((weak))
+WEAK
 __off64_t lseek64(int fildes, __off64_t offset, int whence)
 {
    __my_pthread_testcancel();
@@ -2139,7 +2105,7 @@
 
 extern 
 ssize_t __libc_pwrite(int fd, const void *buf, size_t count, off_t offset);
-__attribute__((weak))
+WEAK
 ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset)
 {
    __my_pthread_testcancel();
@@ -2149,7 +2115,7 @@
 
 extern 
 ssize_t __libc_pread(int fd, void *buf, size_t count, off_t offset);
-__attribute__((weak))
+WEAK
 ssize_t pread(int fd, void *buf, size_t count, off_t offset)
 {
    __my_pthread_testcancel();
@@ -2159,7 +2125,7 @@
 
 extern  
 void __libc_longjmp(jmp_buf env, int val) __attribute((noreturn));
-/* not weak: __attribute__((weak)) */
+/* not weak: WEAK */
 void longjmp(jmp_buf env, int val)
 {
    __libc_longjmp(env, val);
@@ -2177,7 +2143,7 @@
 
 extern
 int __libc_send(int s, const void *msg, size_t len, int flags);
-__attribute__((weak))
+WEAK
 int send(int s, const void *msg, size_t len, int flags)
 {
    __my_pthread_testcancel();
@@ -2185,21 +2151,9 @@
 }
 
 
-extern
-int __libc_recv(int s, void *buf, size_t len, int flags);
-__attribute__((weak))
-int recv(int s, void *buf, size_t len, int flags)
-{
-   __my_pthread_testcancel();
-   wait_for_fd_to_be_readable_or_erring(s);
-   __my_pthread_testcancel();
-   return __libc_recv(s, buf, len, flags);
-}
-
-
 extern 
 int __libc_sendmsg(int s, const struct msghdr *msg, int flags);
-__attribute__((weak))
+WEAK
 int sendmsg(int s, const struct msghdr *msg, int flags)
 {
    __my_pthread_testcancel();
@@ -2209,7 +2163,7 @@
 
 extern
 int __libc_recvmsg(int s, struct msghdr *msg, int flags);
-__attribute__((weak))
+WEAK
 int recvmsg(int s, struct msghdr *msg, int flags)
 {
    __my_pthread_testcancel();
@@ -2220,12 +2174,12 @@
 extern
 int __libc_recvfrom(int s, void *buf, size_t len, int flags,
                     struct sockaddr *from, socklen_t *fromlen);
-__attribute__((weak))
+WEAK
 int recvfrom(int s, void *buf, size_t len, int flags,
              struct sockaddr *from, socklen_t *fromlen)
 {
    __my_pthread_testcancel();
-   wait_for_fd_to_be_readable_or_erring(s);
+   VGR_(wait_for_fd_to_be_readable_or_erring)(s);
    __my_pthread_testcancel();
    return __libc_recvfrom(s, buf, len, flags, from, fromlen);
 }
@@ -2234,7 +2188,7 @@
 extern
 int __libc_sendto(int s, const void *msg, size_t len, int flags, 
                   const struct sockaddr *to, socklen_t tolen);
-__attribute__((weak))
+WEAK
 int sendto(int s, const void *msg, size_t len, int flags, 
            const struct sockaddr *to, socklen_t tolen)
 {
@@ -2245,7 +2199,7 @@
 
 extern 
 int __libc_system(const char* str);
-__attribute__((weak))
+WEAK
 int system(const char* str)
 {
    __my_pthread_testcancel();
@@ -2255,7 +2209,7 @@
 
 extern
 pid_t __libc_wait(int *status);
-__attribute__((weak))
+WEAK
 pid_t wait(int *status)
 {
    __my_pthread_testcancel();
@@ -2265,7 +2219,7 @@
 
 extern
 int __libc_msync(const void *start, size_t length, int flags);
-__attribute__((weak))
+WEAK
 int msync(const void *start, size_t length, int flags)
 {
    __my_pthread_testcancel();
@@ -2352,15 +2306,6 @@
 }
 
 
-/* ---------------------------------------------------------------------
-   Nonblocking implementations of select() and poll().  This stuff will
-   surely rot your mind.
-   ------------------------------------------------------------------ */
-
-/*--------------------------------------------------*/
-
-#include "vg_kerneliface.h"
-
 static
 int my_do_syscall1 ( int syscallno, int arg1 )
 { 
@@ -2415,342 +2360,18 @@
    return __res;
 }
 
-static
-int do_syscall_select( int n, 
-                       vki_fd_set* readfds, 
-                       vki_fd_set* writefds, 
-                       vki_fd_set* exceptfds, 
-                       struct vki_timeval * timeout )
+
+WEAK
+int select ( int n, 
+             fd_set *rfds, 
+             fd_set *wfds, 
+             fd_set *xfds, 
+             struct timeval *timeout )
 {
-   int res;
-   int args[5];
-   args[0] = n;
-   args[1] = (int)readfds;
-   args[2] = (int)writefds;
-   args[3] = (int)exceptfds;
-   args[4] = (int)timeout;
-   res = my_do_syscall1(__NR_select, (int)(&(args[0])) );
-   return res;
+   return VGR_(select)(n, rfds, wfds, xfds, timeout);
 }
 
 
-/* This is a wrapper round select(), which makes it thread-safe,
-   meaning that only this thread will block, rather than the entire
-   process.  This wrapper in turn depends on nanosleep() not to block
-   the entire process, but I think (hope? suspect?) that POSIX
-   pthreads guarantees that to be the case.
-
-   Basic idea is: modify the timeout parameter to select so that it
-   returns immediately.  Poll like this until select returns non-zero,
-   indicating something interesting happened, or until our time is up.
-   Space out the polls with nanosleeps of say 11 milliseconds, which
-   is required to be nonblocking; this allows other threads to run.  
-
-   Assumes:
-   * (checked via my_assert) types fd_set and vki_fd_set are identical.
-   * (checked via my_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).
-*/
-
-int VGL_(select) ( int n, 
-		   fd_set *rfds, 
-		   fd_set *wfds, 
-		   fd_set *xfds, 
-		   struct timeval *timeout )
-{
-   unsigned int ms_now, ms_end;
-   int    res;
-   fd_set rfds_copy;
-   fd_set wfds_copy;
-   fd_set xfds_copy;
-   struct vki_timeval  t_now;
-   struct vki_timeval  zero_timeout;
-   struct vki_timespec nanosleep_interval;
-
-   __my_pthread_testcancel();
-
-   /* gcc's complains about ms_end being used uninitialised -- classic
-      case it can't understand, where ms_end is both defined and used
-      only if timeout != NULL.  Hence ... */
-   ms_end = 0;
-
-   /* We assume that the kernel and libc data layouts are identical
-      for the following types.  These asserts provide a crude
-      check. */
-   if (sizeof(fd_set) != sizeof(vki_fd_set)
-       || sizeof(struct timeval) != sizeof(struct vki_timeval))
-      barf("valgrind's hacky non-blocking select(): data sizes error");
-
-   /* Detect the current time and simultaneously find out if we are
-      running on Valgrind. */
-   VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
-                           VG_USERREQ__READ_MILLISECOND_TIMER,
-                           0, 0, 0, 0);
-
-   /* If a zero timeout specified, this call is harmless.  Also go
-      this route if we're not running on Valgrind, for whatever
-      reason. */
-   if ( (timeout && timeout->tv_sec == 0 && timeout->tv_usec == 0)
-        || (ms_now == 0xFFFFFFFF) ) {
-      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 ms_end to be the end millisecond
-      counter [wallclock] time. */
-   if (timeout) {
-      res = my_do_syscall2(__NR_gettimeofday, (int)&t_now, (int)NULL);
-      my_assert(res == 0);
-      ms_end = ms_now;
-      ms_end += (timeout->tv_usec / 1000);
-      ms_end += (timeout->tv_sec * 1000);
-      /* Stay sane ... */
-      my_assert (ms_end >= ms_now);
-   }
-
-   /* fprintf(stderr, "MY_SELECT: before loop\n"); */
-
-   /* Either timeout == NULL, meaning wait indefinitely, or timeout !=
-      NULL, in which case ms_end holds the end time. */
-
-   while (1) {
-
-      /* First, do a return-immediately select(). */
-
-      /* These could be trashed each time round the loop, so restore
-         them each time. */
-      if (rfds) rfds_copy = *rfds;
-      if (wfds) wfds_copy = *wfds;
-      if (xfds) xfds_copy = *xfds;
-
-      zero_timeout.tv_sec = zero_timeout.tv_usec = 0;
-
-      res = do_syscall_select( n, 
-                               rfds ? (vki_fd_set*)(&rfds_copy) : NULL,
-                               wfds ? (vki_fd_set*)(&wfds_copy) : NULL,
-                               xfds ? (vki_fd_set*)(&xfds_copy) : NULL,
-                               & zero_timeout );
-      if (is_kerror(res)) {
-         /* Some kind of error (including EINTR).  Set errno and
-            return.  The sets are unspecified in this case. */
-         * (__errno_location()) = -res;
-         return -1;
-      }
-      if (res > 0) {
-         /* one or more fds is ready.  Copy out resulting sets and
-            return. */
-         if (rfds) *rfds = rfds_copy;
-         if (wfds) *wfds = wfds_copy;
-         if (xfds) *xfds = xfds_copy;
-         return res;
-      }
-
-      /* Nothing interesting happened, so we go to sleep for a
-         while. */
-
-      /* fprintf(stderr, "MY_SELECT: nanosleep\n"); */
-      /* nanosleep and go round again */
-      nanosleep_interval.tv_sec  = 0;
-      nanosleep_interval.tv_nsec = 11 * 1000 * 1000; /* 11 milliseconds */
-      /* It's critical here that valgrind's nanosleep implementation
-         is nonblocking. */
-      res = my_do_syscall2(__NR_nanosleep, 
-                           (int)(&nanosleep_interval), (int)NULL);
-      if (res == -VKI_EINTR) {
-         /* The nanosleep was interrupted by a signal.  So we do the
-            same. */
-         * (__errno_location()) = EINTR;
-         return -1;
-      }
-
-      /* Sleeping finished.  If a finite timeout, check to see if it
-         has expired yet. */
-      if (timeout) {
-         VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
-                                 VG_USERREQ__READ_MILLISECOND_TIMER,
-                                 0, 0, 0, 0);
-         my_assert(ms_now != 0xFFFFFFFF);
-         if (ms_now >= ms_end) {
-            /* timeout; nothing interesting happened. */
-            if (rfds) FD_ZERO(rfds);
-            if (wfds) FD_ZERO(wfds);
-            if (xfds) FD_ZERO(xfds);
-            return 0;
-         }
-      }
-
-   }
-}
-
-
-
-
-#include <sys/poll.h>
-
-#ifndef HAVE_NFDS_T
-typedef unsigned long int nfds_t;
-#endif
-
-
-int VGL_(poll) (struct pollfd *__fds, nfds_t __nfds, int __timeout)
-{
-   unsigned int        ms_now, ms_end;
-   int                 res, i;
-   struct vki_timespec nanosleep_interval;
-
-   __my_pthread_testcancel();
-   ensure_valgrind("poll");
-
-   /* Detect the current time and simultaneously find out if we are
-      running on Valgrind. */
-   VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
-                           VG_USERREQ__READ_MILLISECOND_TIMER,
-                           0, 0, 0, 0);
-
-   if (/* CHECK SIZES FOR struct pollfd */
-       sizeof(struct timeval) != sizeof(struct vki_timeval))
-      barf("valgrind's hacky non-blocking poll(): data sizes error");
-
-   /* dummy initialisation to keep gcc -Wall happy */
-   ms_end = 0;
-
-   /* If a zero timeout specified, this call is harmless.  Also do
-      this if not running on Valgrind. */
-   if (__timeout == 0 || ms_now == 0xFFFFFFFF) {
-      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 ms_end to be the end wallclock
-      time.  Easy considering that __timeout is in milliseconds. */
-   if (__timeout > 0) {
-      ms_end = ms_now + (unsigned int)__timeout;
-   }
-
-   /* 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. */
-
-   my_assert(__timeout != 0);
-
-   while (1) {
-
-      /* Do a return-immediately poll. */
-
-      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;
-      }
-
-      /* Nothing interesting happened, so we go to sleep for a
-         while. */
-
-      /* fprintf(stderr, "MY_POLL: nanosleep\n"); */
-      /* nanosleep and go round again */
-      nanosleep_interval.tv_sec  = 0;
-      nanosleep_interval.tv_nsec = 13 * 1000 * 1000; /* 13 milliseconds */
-      /* It's critical here that valgrind's nanosleep implementation
-         is nonblocking. */
-      res = my_do_syscall2(__NR_nanosleep, 
-                           (int)(&nanosleep_interval), (int)NULL);
-      if (res == -VKI_EINTR) {
-         /* The nanosleep was interrupted by a signal.  So we do the
-            same. */
-         * (__errno_location()) = EINTR;
-         return -1;
-      }
-
-      /* Sleeping finished.  If a finite timeout, check to see if it
-         has expired yet. */
-      if (__timeout > 0) {
-         VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
-                                 VG_USERREQ__READ_MILLISECOND_TIMER,
-                                 0, 0, 0, 0);
-         my_assert(ms_now != 0xFFFFFFFF);
-         if (ms_now >= ms_end) {
-            /* timeout; nothing interesting happened. */
-            for (i = 0; i < __nfds; i++) 
-               __fds[i].revents = 0;
-            return 0;
-         }
-      }
-
-   }
-}
-
-
-/* Helper function used to make accept() non-blocking.  Idea is to use
-   the above nonblocking poll() to make this thread ONLY wait for the
-   specified fd to become ready, and then return. */
-
-/* Sigh -- a hack.  We're not supposed to include this file directly;
-   should do it via /usr/include/fcntl.h, but that introduces a
-   varargs prototype for fcntl itself, which we can't mimic. */
-#define _FCNTL_H
-#include <bits/fcntl.h>
-
-static void wait_for_fd_to_be_readable_or_erring ( int fd )
-{
-   struct pollfd pfd;
-   int           res;
-
-   /* fprintf(stderr, "wait_for_fd_to_be_readable_or_erring %d\n", fd); */
-
-   /* First check to see if the fd is nonblocking, and/or invalid.  In
-      either case return immediately. */
-   res = __libc_fcntl(fd, F_GETFL, 0);
-   if (res == -1) return; /* fd is invalid somehow */
-   if (res & O_NONBLOCK) return; /* fd is nonblocking */
-
-   /* Ok, we'd better wait with poll. */
-   pfd.fd = fd;
-   pfd.events = POLLIN | POLLPRI | POLLERR | POLLHUP | POLLNVAL;
-   /* ... but not POLLOUT, you may notice. */
-   pfd.revents = 0;
-   (void)poll(&pfd, 1, -1 /* forever */);
-}
-
-static void wait_for_fd_to_be_writable_or_erring ( int fd )
-{
-   struct pollfd pfd;
-   int           res;
-
-   /* fprintf(stderr, "wait_for_fd_to_be_readable_or_erring %d\n", fd); */
-
-   /* First check to see if the fd is nonblocking, and/or invalid.  In
-      either case return immediately. */
-   res = __libc_fcntl(fd, F_GETFL, 0);
-   if (res == -1) return; /* fd is invalid somehow */
-   if (res & O_NONBLOCK) return; /* fd is nonblocking */
-
-   /* Ok, we'd better wait with poll. */
-   pfd.fd = fd;
-   pfd.events = POLLOUT | POLLERR | POLLHUP | POLLNVAL;
-   pfd.revents = 0;
-   (void)poll(&pfd, 1, -1 /* forever */);
-}
-
 /* ---------------------------------------------------------------------
    Hacky implementation of semaphores.
    ------------------------------------------------------------------ */
@@ -3302,95 +2923,22 @@
 
 
 /* ---------------------------------------------------------------------
-   Make SYSV IPC not block everything
+   Make SYSV IPC not block everything -- pass to vg_intercept.c.
    ------------------------------------------------------------------ */
 
-#include <sys/ipc.h>
-#include <sys/msg.h>
-#include <asm/ipc.h>		/* for ipc_kludge */
-
-static inline int sys_ipc(unsigned call, int first, int second, int third, void *ptr)
+WEAK
+int msgsnd(int msgid, const void *msgp, size_t msgsz, int msgflg)
 {
-   return my_do_syscall5(__NR_ipc, call, first, second, third, (int)ptr);
+   return VGR_(msgsnd)(msgid, msgp, msgsz, msgflg);
 }
 
-/* Turn a blocking msgsnd() into a polling non-blocking one, so that
-   other threads make progress */
-int VGL_(msgsnd)(int msgid, const void *msgp, size_t msgsz, int msgflg)
+WEAK
+int msgrcv(int msqid, void* msgp, size_t msgsz, 
+           long msgtyp, int msgflg )
 {
-   struct vki_timespec nanosleep_interval;
-   int err;
-
-   ensure_valgrind("msgsnd");
-
-   nanosleep_interval.tv_sec  = 0;
-   nanosleep_interval.tv_nsec = 13 * 1000 * 1000; /* 13 milliseconds */
-
-   if (msgflg & IPC_NOWAIT) {
-      /* If we aren't blocking anyway, just do it */
-      err = sys_ipc(11, msgid, msgsz, msgflg, (void *)msgp);
-   } else {
-      /* Otherwise poll on the queue to let other things run */
-      for(;;) {
-	 err = sys_ipc(11, msgid, msgsz, msgflg | IPC_NOWAIT, (void *)msgp);
-
-	 if (err != -EAGAIN)
-	    break;
-
-	 (void)my_do_syscall2(__NR_nanosleep, 
-			      (int)(&nanosleep_interval), (int)NULL);
-      }  
-   }
-
-   if (is_kerror(err)) {
-      *(__errno_location()) = -err;
-      return -1;
-   }
-   return 0;
+   return VGR_(msgrcv)(msqid, msgp, msgsz, msgtyp, msgflg );
 }
 
-/* Turn a blocking msgrcv() into a polling non-blocking one, so that
-   other threads make progress */
-int VGL_(msgrcv)( int msqid, void  *msgp,  size_t msgsz, long msgtyp, int msgflg )
-{
-   struct vki_timespec nanosleep_interval;
-   int err;
-   struct ipc_kludge tmp;
-
-   ensure_valgrind("msgrcv");
-
-   nanosleep_interval.tv_sec  = 0;
-   nanosleep_interval.tv_nsec = 13 * 1000 * 1000; /* 13 milliseconds */
-
-   tmp.msgp = msgp;
-   tmp.msgtyp = msgtyp;
-
-   if (msgflg & IPC_NOWAIT) {
-      /* If we aren't blocking anyway, just do it */
-      err = sys_ipc(12, msqid, msgsz, msgflg, &tmp );
-   } else {
-      /* Otherwise poll on the queue to let other things run */
-      for(;;) {
-	 err = sys_ipc(12, msqid, msgsz, msgflg | IPC_NOWAIT, &tmp );
-
-	 if (err != -ENOMSG)
-	    break;
-
-	 (void)my_do_syscall2(__NR_nanosleep, 
-			      (int)(&nanosleep_interval), (int)NULL);
-      }  
-   }
-   
-   if (is_kerror(err)) {
-      *(__errno_location()) = -err;
-      return -1;
-   }
-
-   return err;
-}
-
-
-
 /* ---------------------------------------------------------------------
    B'stard.
    ------------------------------------------------------------------ */
diff --git a/coregrind/vg_include.h b/coregrind/vg_include.h
index 6ce4689..522adfc 100644
--- a/coregrind/vg_include.h
+++ b/coregrind/vg_include.h
@@ -535,6 +535,40 @@
    called at program exit. */
 extern void VG_(__libc_freeres_wrapper)( void );
 
+extern void VGR_(wait_for_fd_to_be_readable_or_erring) ( int fd );
+extern void VGR_(wait_for_fd_to_be_writable_or_erring) ( int fd );
+
+extern int VGR_(recv)(int s, void *buf, unsigned int/*size_t*/ len, 
+                                        int flags);
+
+extern int VGR_(accept)(int s, /*struct sockaddr*/ void *addr, 
+                               /*socklen_t*/ void *addrlen);
+
+
+extern int VGR_(select) ( int n, 
+                          /*fd_set*/ void *rfds, 
+                          /*fd_set*/ void *wfds, 
+                          /*fd_set*/ void *xfds, 
+                          /*struct timeval*/ void *timeout );
+
+extern int VGR_(msgsnd)(int msgid, 
+                        const void *msgp, 
+                        /*size_t*/ unsigned int msgsz, 
+                        int msgflg);
+
+extern int VGR_(msgrcv)( int msqid, 
+                         void* msgp,  
+                         /*size_t*/ unsigned int msgsz, 
+                         long msgtyp, 
+                         int msgflg );
+
+extern int VGR_(readv)(int fd, 
+                       const /*struct iovec*/ void *iovV, 
+                       int count);
+
+extern int VGR_(writev)(int fd, 
+                        const /*struct iovec*/ void *iovV, 
+                        int count);
 
 /* ---------------------------------------------------------------------
    Constants pertaining to the simulated CPU state, VG_(baseBlock),
@@ -1579,8 +1613,6 @@
 extern Addr VG_(noncompact_helper_addrs)  [];
 extern Int  VG_(noncompact_helper_offsets)[];
 
-#define VGL_(x)		vgIntercept_##x
-
 #endif /* ndef __VG_INCLUDE_H */
 
 
diff --git a/coregrind/vg_intercept.c b/coregrind/vg_intercept.c
index ca4c30f..ca7c9ab 100644
--- a/coregrind/vg_intercept.c
+++ b/coregrind/vg_intercept.c
@@ -31,17 +31,20 @@
 
 
 /* ---------------------------------------------------------------------
-   All the code in this file runs on the SIMULATED CPU.  It is
+   ALL THE CODE IN THIS FILE RUNS ON THE SIMULATED CPU.  It is
    intended for various reasons as drop-in replacements for libc
    functions.  These functions have global visibility (obviously) and
    have no prototypes in vg_include.h, since they are not intended to
    be called from within Valgrind.
    ------------------------------------------------------------------ */
 
-/* This has some nasty duplication of stuff from vg_libpthread.c */
-
-#include <errno.h>
-#include <sys/types.h>
+/* General idea (2003-Apr-26) is that master implementations of
+   selected functions are done as VGR_(fnname).  Then we route
+   all calls to the master, both here and in vg_libpthread.c.
+   This means we no longer have to rely on the semantics of weak
+   symbols, which seems to have changed in glibc >= 2.3.2 in such
+   a way as to make the previous interception scheme stop working.
+*/
 
 /* Sidestep the normal check which disallows using valgrind.h
    directly. */
@@ -49,29 +52,69 @@
 #include "valgrind.h"
 
 #include "vg_include.h"
+#include "vg_kerneliface.h"
+
+/* This has some nasty duplication of stuff from vg_libpthread.c */
+
+#include <errno.h>
+#include <sys/types.h>
+#include <stdio.h>
+#include <sys/ipc.h>
+#include <sys/msg.h>
+#include <asm/ipc.h>		/* for ipc_kludge */
+#include <sys/poll.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+
+
+/* --------------------------------------------------------------- */
 
 # define strong_alias(name, aliasname) \
   extern __typeof (name) aliasname __attribute__ ((alias (#name)));
 
-# define weak_alias(name, aliasname) \
-  extern __typeof (name) aliasname __attribute__ ((weak, alias (#name)));
-
 #define WEAK	__attribute__((weak))
 
-#include "vg_kerneliface.h"
+/* --------------------------------------------------------------- */
 
-static
-__inline__
-int is_kerror ( int res )
-{
-   if (res >= -4095 && res <= -1)
-      return 1;
-   else
-      return 0;
+static __inline__
+int my_do_syscall1 ( int syscallno, int arg1 )
+{ 
+   int __res;
+   __asm__ volatile ("pushl %%ebx; movl %%edx,%%ebx ; int $0x80 ; popl %%ebx"
+                     : "=a" (__res)
+                     : "0" (syscallno),
+                       "d" (arg1) );
+   return __res;
 }
 
+static __inline__
+int my_do_syscall2 ( int syscallno, 
+                     int arg1, int arg2 )
+{ 
+   int __res;
+   __asm__ volatile ("pushl %%ebx; movl %%edx,%%ebx ; int $0x80 ; popl %%ebx"
+                     : "=a" (__res)
+                     : "0" (syscallno),
+                       "d" (arg1),
+                       "c" (arg2) );
+   return __res;
+}
 
-static inline
+static __inline__
+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 __inline__
 int my_do_syscall5 ( int syscallno, 
                      int arg1, int arg2, int arg3, int arg4, int arg5 )
 { 
@@ -87,148 +130,12 @@
    return __res;
 }
 
-/* -------------------------------- msgsnd -------------------------------- */
-#include <asm/ipc.h>		/* for ipc_kludge */
-
-static inline int sys_ipc(unsigned call, int first, int second, int third, void *ptr)
-{
-   return my_do_syscall5(__NR_ipc, call, first, second, third, (int)ptr);
-}
-
-WEAK int VGL_(msgsnd)(int msgid, const void *msgp, size_t msgsz, int msgflg)
-{
-   int err = sys_ipc(11, msgid, msgsz, msgflg, (void *)msgp);
-   if (is_kerror(err)) {
-      *(__errno_location()) = -err;
-      return -1;
-   }
-   return 0;
-}
-
-int msgsnd(int msgid, const void *msgp, size_t msgsz, int msgflg)
-{
-   return VGL_(msgsnd)(msgid, msgp, msgsz, msgflg);
-}
-
-/* -------------------------------- msgrcv -------------------------------- */
-
-WEAK int VGL_(msgrcv)( int msqid, void  *msgp,  size_t msgsz, long msgtyp, int msgflg )
-{
-   struct ipc_kludge tmp;
-   int err;
-
-   tmp.msgp = msgp;
-   tmp.msgtyp = msgtyp;
-
-   err = sys_ipc(12, msqid, msgsz, msgflg, &tmp );
-
-   if (is_kerror(err)) {
-      *(__errno_location()) = -err;
-      return -1;
-   }
-   return err;
-}
-
-int msgrcv( int msqid, void  *msgp,  size_t msgsz, long msgtyp, int msgflg )
-{
-   return VGL_(msgrcv)( msqid, msgp,  msgsz, msgtyp, msgflg );
-}
-
-/* -------------------------------- accept -------------------------------- */
-
-#include <sys/socket.h>
-
-extern
-int __libc_accept(int s, struct sockaddr *addr, socklen_t *addrlen);
-WEAK int VGL_(accept)(int s, struct sockaddr *addr, socklen_t *addrlen)
-{
-   return __libc_accept(s, addr, addrlen);
-}
-
-int accept(int s, struct sockaddr *addr, socklen_t *addrlen)
-{
-   return VGL_(accept)(s, addr, addrlen);
-}
-
-/* -------------------------------- recv -------------------------------- */
-
-extern
-int __libc_recv(int s, void *buf, size_t len, int flags);
-
-WEAK int VGL_(recv)(int s, void *buf, size_t len, int flags)
-{
-   return __libc_recv(s, buf, len, flags);
-}
-
-int recv(int s, void *buf, size_t len, int flags)
-{
-   return VGL_(recv)(s, buf, len, flags);
-}
-
-strong_alias(recv, __recv)
-
-/* -------------------------------- poll -------------------------------- */
-
-static inline
-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;
-}
-
-#include <sys/poll.h>
-
-#ifndef HAVE_NFDS_T
-typedef unsigned long int nfds_t;
-#endif
-
-
-WEAK int VGL_(poll)(struct pollfd *__fds, nfds_t __nfds, int __timeout)
-{
-   int res = my_do_syscall3(__NR_poll, (int)__fds, __nfds, __timeout);
-
-   if (is_kerror(res)) {
-      * (__errno_location()) = -res;
-      return -1;
-   }
-   return res;
-}
-
-int poll(struct pollfd *__fds, nfds_t __nfds, int __timeout)
-{
-   return VGL_(poll)(__fds, __nfds, __timeout);
-}
-
-strong_alias(poll, __poll)
-
-
-/* -------------------------------- select -------------------------------- */
-
-
-static inline
-int my_do_syscall1 ( int syscallno, int arg1 )
-{ 
-   int __res;
-   __asm__ volatile ("pushl %%ebx; movl %%edx,%%ebx ; int $0x80 ; popl %%ebx"
-                     : "=a" (__res)
-                     : "0" (syscallno),
-                       "d" (arg1) );
-   return __res;
-}
-
-
-WEAK int VGL_(select)( int n, 
-		       fd_set* readfds, 
-		       fd_set* writefds, 
-		       fd_set* exceptfds, 
-		       struct timeval * timeout )
+static __inline__
+int do_syscall_select( int n, 
+                       vki_fd_set* readfds, 
+                       vki_fd_set* writefds, 
+                       vki_fd_set* exceptfds, 
+                       struct vki_timeval * timeout )
 {
    int res;
    int args[5];
@@ -238,12 +145,525 @@
    args[3] = (int)exceptfds;
    args[4] = (int)timeout;
    res = my_do_syscall1(__NR_select, (int)(&(args[0])) );
+   return res;
+}
 
-   if (is_kerror(res)) {
-      *(__errno_location()) = -res;
+
+static __inline__
+int do_syscall_ipc( unsigned call, 
+                    int first, int second, int third, 
+                    void *ptr)
+{
+   return my_do_syscall5(__NR_ipc, call, first, second, third, (int)ptr);
+}
+
+
+/* --------------------------------------------------------------- */
+
+/* Just start up Valgrind if it's not already going.  VG_(startup)()
+   detects and ignores second and subsequent calls. */
+
+/* We need this guy -- it's in valgrind.so. */
+extern void VG_(startup) ( void );
+
+static __inline__
+void ensure_valgrind ( char* caller )
+{
+   VG_(startup)();
+}
+
+static __inline__
+int is_kerror ( int res )
+{
+   if (res >= -4095 && res <= -1)
+      return 1;
+   else
+      return 0;
+}
+
+/* --------------------------------------------------------------- */
+
+/* Extract from Valgrind the value of VG_(clo_trace_pthread_level).
+   Returns 0 (none) if not running on Valgrind. */
+static
+int get_pt_trace_level ( void )
+{
+   int res;
+   VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
+                           VG_USERREQ__GET_PTHREAD_TRACE_LEVEL,
+                           0, 0, 0, 0);
+   return res;
+}
+
+static 
+void cat_n_send ( char* pre, char* msg )
+{
+   char  buf[1000];
+   int   res;
+   if (get_pt_trace_level() >= 0) {
+      snprintf(buf, sizeof(buf), "%s%s", pre, msg );
+      buf[sizeof(buf)-1] = '\0';
+      VALGRIND_MAGIC_SEQUENCE(res, 0, /* irrelevant default */
+                              VG_USERREQ__LOGMESSAGE, buf, 0, 0, 0);
+   }
+}
+
+static
+void my_exit ( int arg )
+{
+   my_do_syscall1(__NR_exit, arg);
+   /*NOTREACHED*/
+}
+
+static
+void my_assert_fail ( Char* expr, Char* file, Int line, Char* fn )
+{
+   char buf[1000];
+   static Bool entered = False;
+   if (entered) 
+      my_exit(2);
+   entered = True;
+   sprintf(buf, "\n%s: %s:%d (%s): Assertion `%s' failed.\n",
+                "valgrind", file, line, fn, expr );
+   cat_n_send ( "", buf );
+   sprintf(buf, "Please report this bug to me at: %s\n\n", 
+                 VG_EMAIL_ADDR);
+   cat_n_send ( "", buf );
+   my_exit(1);
+}
+
+#define MY__STRING(__str)  #__str
+
+#define my_assert(expr)                                               \
+  ((void) ((expr) ? 0 :						      \
+	   (my_assert_fail  (MY__STRING(expr),			      \
+			      __FILE__, __LINE__,                     \
+                              __PRETTY_FUNCTION__), 0)))
+
+/* --------------------------------------------------------------- */
+
+static __inline__
+void __my_pthread_testcancel(void)
+{
+   int res;
+   ensure_valgrind("__my_pthread_testcancel");
+   VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
+                           VG_USERREQ__TESTCANCEL,
+                           0, 0, 0, 0);
+   my_assert(res == 0);
+}
+
+/* ================================ poll ================================ */
+
+/* This is the master implementation of poll().  It blocks only the
+   calling thread.  All roads lead here.
+*/
+
+#ifndef HAVE_NFDS_T
+typedef unsigned long int nfds_t;
+#endif
+
+
+int VGR_(poll) (struct pollfd *__fds, nfds_t __nfds, int __timeout)
+{
+   unsigned int        ms_now, ms_end;
+   int                 res, i;
+   struct vki_timespec nanosleep_interval;
+
+   __my_pthread_testcancel();
+   ensure_valgrind("poll");
+
+   /* Detect the current time and simultaneously find out if we are
+      running on Valgrind. */
+   VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
+                           VG_USERREQ__READ_MILLISECOND_TIMER,
+                           0, 0, 0, 0);
+
+   /* CHECK SIZES FOR struct pollfd */
+   my_assert(sizeof(struct timeval) == sizeof(struct vki_timeval));
+
+   /* dummy initialisation to keep gcc -Wall happy */
+   ms_end = 0;
+
+   /* If a zero timeout specified, this call is harmless.  Also do
+      this if not running on Valgrind. */
+   if (__timeout == 0 || ms_now == 0xFFFFFFFF) {
+      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 ms_end to be the end wallclock
+      time.  Easy considering that __timeout is in milliseconds. */
+   if (__timeout > 0) {
+      ms_end = ms_now + (unsigned int)__timeout;
+   }
+
+   /* 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. */
+
+   my_assert(__timeout != 0);
+
+   while (1) {
+
+      /* Do a return-immediately poll. */
+
+      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;
+      }
+
+      /* Nothing interesting happened, so we go to sleep for a
+         while. */
+
+      /* fprintf(stderr, "MY_POLL: nanosleep\n"); */
+      /* nanosleep and go round again */
+      nanosleep_interval.tv_sec  = 0;
+      nanosleep_interval.tv_nsec = 13 * 1000 * 1000; /* 13 milliseconds */
+      /* It's critical here that valgrind's nanosleep implementation
+         is nonblocking. */
+      res = my_do_syscall2(__NR_nanosleep, 
+                           (int)(&nanosleep_interval), (int)NULL);
+      if (res == -VKI_EINTR) {
+         /* The nanosleep was interrupted by a signal.  So we do the
+            same. */
+         * (__errno_location()) = EINTR;
+         return -1;
+      }
+
+      /* Sleeping finished.  If a finite timeout, check to see if it
+         has expired yet. */
+      if (__timeout > 0) {
+         VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
+                                 VG_USERREQ__READ_MILLISECOND_TIMER,
+                                 0, 0, 0, 0);
+         my_assert(ms_now != 0xFFFFFFFF);
+         if (ms_now >= ms_end) {
+            /* timeout; nothing interesting happened. */
+            for (i = 0; i < __nfds; i++) 
+               __fds[i].revents = 0;
+            return 0;
+         }
+      }
+
+   }
+}
+
+int poll(struct pollfd *__fds, nfds_t __nfds, int __timeout)
+{
+   return VGR_(poll)(__fds, __nfds, __timeout);
+}
+
+strong_alias(poll, __poll)
+
+/* ================================ msgsnd ================================ */
+
+/* Turn a blocking msgsnd() into a polling non-blocking one, so that
+   other threads make progress */
+int VGR_(msgsnd)(int msgid, 
+                 const void *msgp, 
+                 /*size_t*/ unsigned int msgsz, 
+                 int msgflg)
+{
+   struct vki_timespec nanosleep_interval;
+   int err;
+
+   ensure_valgrind("msgsnd");
+
+   nanosleep_interval.tv_sec  = 0;
+   nanosleep_interval.tv_nsec = 13 * 1000 * 1000; /* 13 milliseconds */
+
+   if (msgflg & IPC_NOWAIT) {
+      /* If we aren't blocking anyway, just do it */
+      err = do_syscall_ipc(11, msgid, msgsz, msgflg, (void *)msgp);
+   } else {
+      /* Otherwise poll on the queue to let other things run */
+      for(;;) {
+	 err = do_syscall_ipc(11, msgid, msgsz, msgflg | IPC_NOWAIT, 
+                                  (void *)msgp);
+
+	 if (err != -EAGAIN)
+	    break;
+
+	 (void)my_do_syscall2(__NR_nanosleep, 
+			      (int)(&nanosleep_interval), (int)NULL);
+      }  
+   }
+
+   if (is_kerror(err)) {
+      *(__errno_location()) = -err;
       return -1;
    }
-   return res;
+   return 0;
+}
+
+int msgsnd(int msgid, const void *msgp, size_t msgsz, int msgflg)
+{
+   return VGR_(msgsnd)(msgid, msgp, msgsz, msgflg);
+}
+
+/* ================================ msgrcv ================================ */
+
+/* Turn a blocking msgrcv() into a polling non-blocking one, so that
+   other threads make progress */
+int VGR_(msgrcv)( int msqid, 
+                  void* msgp,  
+                  /*size_t*/ unsigned int msgsz, 
+                  long msgtyp, 
+                  int msgflg )
+{
+   struct vki_timespec nanosleep_interval;
+   int err;
+   struct ipc_kludge tmp;
+
+   ensure_valgrind("msgrcv");
+
+   nanosleep_interval.tv_sec  = 0;
+   nanosleep_interval.tv_nsec = 13 * 1000 * 1000; /* 13 milliseconds */
+
+   tmp.msgp = msgp;
+   tmp.msgtyp = msgtyp;
+
+   if (msgflg & IPC_NOWAIT) {
+      /* If we aren't blocking anyway, just do it */
+      err = do_syscall_ipc(12, msqid, msgsz, msgflg, &tmp );
+   } else {
+      /* Otherwise poll on the queue to let other things run */
+      for(;;) {
+	 err = do_syscall_ipc(12, msqid, msgsz, msgflg | IPC_NOWAIT, &tmp );
+
+	 if (err != -ENOMSG)
+	    break;
+
+	 (void)my_do_syscall2(__NR_nanosleep, 
+			      (int)(&nanosleep_interval), (int)NULL);
+      }  
+   }
+   
+   if (is_kerror(err)) {
+      *(__errno_location()) = -err;
+      return -1;
+   }
+
+   return err;
+}
+
+int msgrcv( int msqid, void  *msgp,  size_t msgsz, long msgtyp, int msgflg )
+{
+   return VGR_(msgrcv)( msqid, msgp,  msgsz, msgtyp, msgflg );
+}
+
+/* ================================ accept ================================ */
+
+extern
+int __libc_accept(int s, struct sockaddr *addr, socklen_t *addrlen);
+
+int VGR_(accept)(int s, /*struct sockaddr*/ void *addr, 
+                        /*socklen_t*/ void *addrlen)
+{
+   __my_pthread_testcancel();
+   VGR_(wait_for_fd_to_be_readable_or_erring)(s);
+   __my_pthread_testcancel();
+   return __libc_accept(s, addr, addrlen);
+}
+
+int accept(int s, struct sockaddr *addr, socklen_t *addrlen)
+{
+   return VGR_(accept)(s, addr, addrlen);
+}
+
+/* ================================ recv ================================ */
+
+extern
+int __libc_recv(int s, void *buf, size_t len, int flags);
+
+int VGR_(recv)(int s, void *buf, size_t len, int flags)
+{
+   __my_pthread_testcancel();
+   VGR_(wait_for_fd_to_be_readable_or_erring)(s);
+   __my_pthread_testcancel();
+   return __libc_recv(s, buf, len, flags);
+}
+
+int recv(int s, void *buf, size_t len, int flags)
+{
+   return VGR_(recv)(s, buf, len, flags);
+}
+
+strong_alias(recv, __recv)
+
+/* ================================ select ================================ */
+
+/* This is a wrapper round select(), which makes it thread-safe,
+   meaning that only this thread will block, rather than the entire
+   process.  This wrapper in turn depends on nanosleep() not to block
+   the entire process, but I think (hope? suspect?) that POSIX
+   pthreads guarantees that to be the case.
+
+   Basic idea is: modify the timeout parameter to select so that it
+   returns immediately.  Poll like this until select returns non-zero,
+   indicating something interesting happened, or until our time is up.
+   Space out the polls with nanosleeps of say 11 milliseconds, which
+   is required to be nonblocking; this allows other threads to run.  
+
+   Assumes:
+   * (checked via my_assert) types fd_set and vki_fd_set are identical.
+   * (checked via my_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).
+*/
+
+int VGR_(select) ( int n, 
+                   /*fd_set*/ void *rfdsV, 
+                   /*fd_set*/ void *wfdsV, 
+                   /*fd_set*/ void *xfdsV, 
+                   /*struct timeval*/ void *timeoutV )
+{
+   unsigned int ms_now, ms_end;
+   int    res;
+   fd_set rfds_copy;
+   fd_set wfds_copy;
+   fd_set xfds_copy;
+   struct vki_timeval  t_now;
+   struct vki_timeval  zero_timeout;
+   struct vki_timespec nanosleep_interval;
+
+   struct timeval* timeout = (struct timeval*)timeoutV;
+   fd_set* rfds = (fd_set*)rfdsV;
+   fd_set* wfds = (fd_set*)wfdsV;
+   fd_set* xfds = (fd_set*)xfdsV;
+
+   __my_pthread_testcancel();
+
+   /* gcc's complains about ms_end being used uninitialised -- classic
+      case it can't understand, where ms_end is both defined and used
+      only if timeout != NULL.  Hence ... */
+   ms_end = 0;
+
+   /* We assume that the kernel and libc data layouts are identical
+      for the following types.  These asserts provide a crude
+      check. */
+   my_assert(sizeof(struct timeval) == sizeof(struct vki_timeval));
+
+   /* Detect the current time and simultaneously find out if we are
+      running on Valgrind. */
+   VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
+                           VG_USERREQ__READ_MILLISECOND_TIMER,
+                           0, 0, 0, 0);
+
+   /* If a zero timeout specified, this call is harmless.  Also go
+      this route if we're not running on Valgrind, for whatever
+      reason. */
+   if ( (timeout && timeout->tv_sec == 0 && timeout->tv_usec == 0)
+        || (ms_now == 0xFFFFFFFF) ) {
+      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 ms_end to be the end millisecond
+      counter [wallclock] time. */
+   if (timeout) {
+      res = my_do_syscall2(__NR_gettimeofday, (int)&t_now, (int)NULL);
+      my_assert(res == 0);
+      ms_end = ms_now;
+      ms_end += (timeout->tv_usec / 1000);
+      ms_end += (timeout->tv_sec * 1000);
+      /* Stay sane ... */
+      my_assert (ms_end >= ms_now);
+   }
+
+   /* fprintf(stderr, "MY_SELECT: before loop\n"); */
+
+   /* Either timeout == NULL, meaning wait indefinitely, or timeout !=
+      NULL, in which case ms_end holds the end time. */
+
+   while (1) {
+
+      /* First, do a return-immediately select(). */
+
+      /* These could be trashed each time round the loop, so restore
+         them each time. */
+      if (rfds) rfds_copy = *rfds;
+      if (wfds) wfds_copy = *wfds;
+      if (xfds) xfds_copy = *xfds;
+
+      zero_timeout.tv_sec = zero_timeout.tv_usec = 0;
+
+      res = do_syscall_select( n, 
+                               rfds ? (vki_fd_set*)(&rfds_copy) : NULL,
+                               wfds ? (vki_fd_set*)(&wfds_copy) : NULL,
+                               xfds ? (vki_fd_set*)(&xfds_copy) : NULL,
+                               & zero_timeout );
+      if (is_kerror(res)) {
+         /* Some kind of error (including EINTR).  Set errno and
+            return.  The sets are unspecified in this case. */
+         * (__errno_location()) = -res;
+         return -1;
+      }
+      if (res > 0) {
+         /* one or more fds is ready.  Copy out resulting sets and
+            return. */
+         if (rfds) *rfds = rfds_copy;
+         if (wfds) *wfds = wfds_copy;
+         if (xfds) *xfds = xfds_copy;
+         return res;
+      }
+
+      /* Nothing interesting happened, so we go to sleep for a
+         while. */
+
+      /* fprintf(stderr, "MY_SELECT: nanosleep\n"); */
+      /* nanosleep and go round again */
+      nanosleep_interval.tv_sec  = 0;
+      nanosleep_interval.tv_nsec = 11 * 1000 * 1000; /* 11 milliseconds */
+      /* It's critical here that valgrind's nanosleep implementation
+         is nonblocking. */
+      res = my_do_syscall2(__NR_nanosleep, 
+                           (int)(&nanosleep_interval), (int)NULL);
+      if (res == -VKI_EINTR) {
+         /* The nanosleep was interrupted by a signal.  So we do the
+            same. */
+         * (__errno_location()) = EINTR;
+         return -1;
+      }
+
+      /* Sleeping finished.  If a finite timeout, check to see if it
+         has expired yet. */
+      if (timeout) {
+         VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
+                                 VG_USERREQ__READ_MILLISECOND_TIMER,
+                                 0, 0, 0, 0);
+         my_assert(ms_now != 0xFFFFFFFF);
+         if (ms_now >= ms_end) {
+            /* timeout; nothing interesting happened. */
+            if (rfds) FD_ZERO(rfds);
+            if (wfds) FD_ZERO(wfds);
+            if (xfds) FD_ZERO(xfds);
+            return 0;
+         }
+      }
+
+   }
 }
 
 int select ( int n, 
@@ -252,55 +672,65 @@
              fd_set *xfds, 
              struct timeval *timeout )
 {
-   return VGL_(select)(n, rfds, wfds, xfds, timeout);
+   return VGR_(select)(n, rfds, wfds, xfds, timeout);
 }
 
 strong_alias(select, __select)
 
-/* -------------------------------- readv -------------------------------- */
+/* ================================ readv ================================ */
 
-#include <sys/uio.h>
-
-WEAK int VGL_(readv)(int fd, const struct iovec *iov, int count)
+int VGR_(readv)(int fd, const /*struct iovec*/ void *iovV, int count)
 {
-   int res = my_do_syscall3(__NR_readv, fd, (unsigned)iov, count);
+   int res;
+   const struct iovec* iov = (const struct iovec*)iovV;
+
+   __my_pthread_testcancel();
+   VGR_(wait_for_fd_to_be_readable_or_erring)(fd);
+   __my_pthread_testcancel();
+   res = my_do_syscall3(__NR_readv, fd, (unsigned)iov, count);
 
    if (is_kerror(res)) {
       *(__errno_location()) = -res;
       return -1;
    }
-
    return res;
 }
 
 int readv (int fd, const struct iovec *iov, int count)
 {
-   return VGL_(readv)(fd, iov, count);
+   return VGR_(readv)(fd, iov, count);
 }
 
 strong_alias(readv, __readv)
 
-/* -------------------------------- writev -------------------------------- */
+/* ================================ writev ================================ */
 
-WEAK int VGL_(writev)(int fd, const struct iovec *iov, int count)
+int VGR_(writev)(int fd, const /*struct iovec*/ void *iovV, int count)
 {
-   int res = my_do_syscall3(__NR_writev, fd, (unsigned)iov, count);
+   int res;
+   struct iovec* iov = (struct iovec*)iovV;
+
+   __my_pthread_testcancel();
+   VGR_(wait_for_fd_to_be_writable_or_erring)(fd);
+   __my_pthread_testcancel();
+   res = my_do_syscall3(__NR_writev, fd, (unsigned)iov, count);
 
    if (is_kerror(res)) {
       *(__errno_location()) = -res;
       return -1;
    }
-
    return res;
 }
 
 int writev (int fd, const struct iovec *iov, int count)
 {
-   return VGL_(writev)(fd, iov, count);
+   return VGR_(writev)(fd, iov, count);
 }
 
 strong_alias(writev, __writev)
 
+/* ================================ sigsuspend ============================ */
+
 /* ---------------------------------------------------------------------
    Horrible hack to make sigsuspend() sort-of work OK.  Same trick as
    for pause() in vg_libpthread.so.
@@ -378,6 +808,65 @@
    return VG_(running_on_simd_CPU);
 }
 
+
+/* ---------------------------------------------------------------------
+   Helpers for safely (nonblockingly) detecting when a file descriptor
+   is safe to use.
+   ------------------------------------------------------------------ */
+
+/* Helper function used to make accept() non-blocking.  Idea is to use
+   the above nonblocking poll() to make this thread ONLY wait for the
+   specified fd to become ready, and then return. */
+
+/* Sigh -- a hack.  We're not supposed to include this file directly;
+   should do it via /usr/include/fcntl.h, but that introduces a
+   varargs prototype for fcntl itself, which we can't mimic. */
+#define _FCNTL_H
+#include <bits/fcntl.h>
+
+extern int __libc_fcntl(int fd, int cmd, long arg);
+
+void VGR_(wait_for_fd_to_be_readable_or_erring) ( int fd )
+{
+   struct pollfd pfd;
+   int           res;
+
+   /* fprintf(stderr, "wait_for_fd_to_be_readable_or_erring %d\n", fd); */
+
+   /* First check to see if the fd is nonblocking, and/or invalid.  In
+      either case return immediately. */
+   res = __libc_fcntl(fd, F_GETFL, 0);
+   if (res == -1) return; /* fd is invalid somehow */
+   if (res & O_NONBLOCK) return; /* fd is nonblocking */
+
+   /* Ok, we'd better wait with poll. */
+   pfd.fd = fd;
+   pfd.events = POLLIN | POLLPRI | POLLERR | POLLHUP | POLLNVAL;
+   /* ... but not POLLOUT, you may notice. */
+   pfd.revents = 0;
+   (void)poll(&pfd, 1, -1 /* forever */);
+}
+
+void VGR_(wait_for_fd_to_be_writable_or_erring) ( int fd )
+{
+   struct pollfd pfd;
+   int           res;
+
+   /* fprintf(stderr, "wait_for_fd_to_be_readable_or_erring %d\n", fd); */
+
+   /* First check to see if the fd is nonblocking, and/or invalid.  In
+      either case return immediately. */
+   res = __libc_fcntl(fd, F_GETFL, 0);
+   if (res == -1) return; /* fd is invalid somehow */
+   if (res & O_NONBLOCK) return; /* fd is nonblocking */
+
+   /* Ok, we'd better wait with poll. */
+   pfd.fd = fd;
+   pfd.events = POLLOUT | POLLERR | POLLHUP | POLLNVAL;
+   pfd.revents = 0;
+   (void)poll(&pfd, 1, -1 /* forever */);
+}
+
 /*--------------------------------------------------------------------*/
 /*--- end                                           vg_intercept.c ---*/
 /*--------------------------------------------------------------------*/
diff --git a/coregrind/vg_libpthread.c b/coregrind/vg_libpthread.c
index 400af5d..3db4db5 100644
--- a/coregrind/vg_libpthread.c
+++ b/coregrind/vg_libpthread.c
@@ -78,8 +78,8 @@
    Forwardses.
    ------------------------------------------------------------------ */
 
-static void wait_for_fd_to_be_readable_or_erring ( int fd );
-static void wait_for_fd_to_be_writable_or_erring ( int fd );
+#define WEAK	__attribute__((weak))
+
 
 static
 int my_do_syscall1 ( int syscallno, int arg1 );
@@ -350,7 +350,7 @@
    return 0;
 }
 
-__attribute__((weak))
+WEAK
 int pthread_attr_setstacksize (pthread_attr_t *__attr,
                                size_t __stacksize)
 {
@@ -452,7 +452,7 @@
 
 
 /* Bogus ... */
-__attribute__((weak))
+WEAK
 int pthread_attr_getstackaddr ( const pthread_attr_t * attr,
                                 void ** stackaddr )
 {
@@ -464,7 +464,7 @@
 }
 
 /* Not bogus (!) */
-__attribute__((weak))
+WEAK
 int pthread_attr_getstacksize ( const pthread_attr_t * _attr, 
                                 size_t * __stacksize )
 {
@@ -495,7 +495,7 @@
 /* This is completely bogus.  We reject all attempts to change it from
    VKI_BYTES_PER_PAGE.  I don't have a clue what it's for so it seems
    safest to be paranoid. */
-__attribute__((weak)) 
+WEAK 
 int pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize)
 {
    static int moans = N_MOANS;
@@ -510,7 +510,7 @@
 }
 
 /* A straight copy of the LinuxThreads code. */
-__attribute__((weak)) 
+WEAK 
 int pthread_attr_getguardsize(const pthread_attr_t *attr, size_t *guardsize)
 {
    *guardsize = attr->__guardsize;
@@ -521,7 +521,7 @@
 
 static int concurrency_current_level = 0;
 
-__attribute__((weak)) 
+WEAK 
 int pthread_setconcurrency(int new_level)
 {
    if (new_level < 0)
@@ -532,7 +532,7 @@
    }
 }
 
-__attribute__((weak)) 
+WEAK 
 int pthread_getconcurrency(void)
 {
    return concurrency_current_level;
@@ -678,7 +678,7 @@
    THREADs
    ------------------------------------------------ */
 
-__attribute__((weak))
+WEAK
 int pthread_yield ( void )
 {
    int res;
@@ -1566,7 +1566,7 @@
 }
 
 
-__attribute__((weak)) 
+WEAK 
 void __pthread_initialize ( void )
 {
    ensure_valgrind("__pthread_initialize");
@@ -1775,10 +1775,6 @@
    to the corresponding thread-unaware (?) libc routine.
    ------------------------------------------------------------------ */
 
-#include <stdlib.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-
 #ifdef GLIBC_2_1
 extern
 int __sigaction
@@ -1809,7 +1805,7 @@
 int  __libc_connect(int  sockfd,  
                     const  struct  sockaddr  *serv_addr, 
                     socklen_t addrlen);
-__attribute__((weak))
+WEAK
 int  connect(int  sockfd,  
              const  struct  sockaddr  *serv_addr, 
              socklen_t addrlen)
@@ -1821,7 +1817,7 @@
 
 extern
 int __libc_fcntl(int fd, int cmd, long arg);
-__attribute__((weak))
+WEAK
 int fcntl(int fd, int cmd, long arg)
 {
    __my_pthread_testcancel();
@@ -1831,7 +1827,7 @@
 
 extern 
 ssize_t __libc_write(int fd, const void *buf, size_t count);
-__attribute__((weak))
+WEAK
 ssize_t write(int fd, const void *buf, size_t count)
 {
    __my_pthread_testcancel();
@@ -1841,7 +1837,7 @@
 
 extern 
 ssize_t __libc_read(int fd, void *buf, size_t count);
-__attribute__((weak))
+WEAK
 ssize_t read(int fd, void *buf, size_t count)
 {
    __my_pthread_testcancel();
@@ -1987,7 +1983,7 @@
 
 extern
 int __libc_open64(const char *pathname, int flags, mode_t mode);
-/* __attribute__((weak)) */
+/* WEAK */
 int open64(const char *pathname, int flags, mode_t mode)
 {
    return _open(pathname, flags, mode, __libc_open64);
@@ -1995,7 +1991,7 @@
 
 extern
 int __libc_open(const char *pathname, int flags, mode_t mode);
-/* __attribute__((weak)) */
+/* WEAK */
 int open(const char *pathname, int flags, mode_t mode)
 {
    return _open(pathname, flags, mode, __libc_open);
@@ -2003,7 +1999,7 @@
 
 extern
 int __libc_close(int fd);
-__attribute__((weak))
+WEAK
 int close(int fd)
 {
    __my_pthread_testcancel();
@@ -2011,63 +2007,33 @@
 }
 
 
-extern
-int __libc_accept(int s, struct sockaddr *addr, socklen_t *addrlen);
-
-int VGL_(accept)(int s, struct sockaddr *addr, socklen_t *addrlen)
+WEAK
+int accept(int s, struct sockaddr *addr, socklen_t *addrlen)
 {
-   __my_pthread_testcancel();
-   wait_for_fd_to_be_readable_or_erring(s);
-   __my_pthread_testcancel();
-   return __libc_accept(s, addr, addrlen);
+   return VGR_(accept)(s, addr, addrlen);
 }
 
-extern
-int __libc_recv(int s, void *buf, size_t len, int flags);
-
-int VGL_(recv)(int s, void *buf, size_t len, int flags)
+WEAK
+int recv(int s, void *buf, size_t len, int flags)
 {
-   __my_pthread_testcancel();
-   wait_for_fd_to_be_readable_or_erring(s);
-   __my_pthread_testcancel();
-   return __libc_recv(s, buf, len, flags);
+   return VGR_(recv)(s, buf, len, flags);
 }
 
-int VGL_(readv)(int fd, const struct iovec *iov, int count)
+WEAK
+int readv(int fd, const struct iovec *iov, int count)
 {
-   int res;
-
-   __my_pthread_testcancel();
-   wait_for_fd_to_be_readable_or_erring(fd);
-   __my_pthread_testcancel();
-   res = my_do_syscall3(__NR_readv, fd, (unsigned)iov, count);
-
-   if (is_kerror(res)) {
-      *(__errno_location()) = -res;
-      return -1;
-   }
-   return res;
+  return VGR_(readv)(fd, iov, count);
 }
 
-int VGL_(writev)(int fd, struct iovec *iov, int count)
+WEAK
+int writev(int fd, const struct iovec *iov, int count)
 {
-   int res;
-
-   __my_pthread_testcancel();
-   wait_for_fd_to_be_writable_or_erring(fd);
-   __my_pthread_testcancel();
-   res = my_do_syscall3(__NR_writev, fd, (unsigned)iov, count);
-
-   if (is_kerror(res)) {
-      *(__errno_location()) = -res;
-      return -1;
-   }
-   return res;
+  return VGR_(writev)(fd, iov, count);
 }
 
 extern
 pid_t __libc_waitpid(pid_t pid, int *status, int options);
-__attribute__((weak))
+WEAK
 pid_t waitpid(pid_t pid, int *status, int options)
 {
    __my_pthread_testcancel();
@@ -2077,7 +2043,7 @@
 
 extern
 int __libc_nanosleep(const struct timespec *req, struct timespec *rem);
-__attribute__((weak))
+WEAK
 int nanosleep(const struct timespec *req, struct timespec *rem)
 {
    __my_pthread_testcancel();
@@ -2087,7 +2053,7 @@
 
 extern
 int __libc_fsync(int fd);
-__attribute__((weak))
+WEAK
 int fsync(int fd)
 {
    __my_pthread_testcancel();
@@ -2097,7 +2063,7 @@
 
 extern
 off_t __libc_lseek(int fildes, off_t offset, int whence);
-__attribute__((weak))
+WEAK
 off_t lseek(int fildes, off_t offset, int whence)
 {
    __my_pthread_testcancel();
@@ -2107,7 +2073,7 @@
 
 extern
 __off64_t __libc_lseek64(int fildes, __off64_t offset, int whence);
-__attribute__((weak))
+WEAK
 __off64_t lseek64(int fildes, __off64_t offset, int whence)
 {
    __my_pthread_testcancel();
@@ -2139,7 +2105,7 @@
 
 extern 
 ssize_t __libc_pwrite(int fd, const void *buf, size_t count, off_t offset);
-__attribute__((weak))
+WEAK
 ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset)
 {
    __my_pthread_testcancel();
@@ -2149,7 +2115,7 @@
 
 extern 
 ssize_t __libc_pread(int fd, void *buf, size_t count, off_t offset);
-__attribute__((weak))
+WEAK
 ssize_t pread(int fd, void *buf, size_t count, off_t offset)
 {
    __my_pthread_testcancel();
@@ -2159,7 +2125,7 @@
 
 extern  
 void __libc_longjmp(jmp_buf env, int val) __attribute((noreturn));
-/* not weak: __attribute__((weak)) */
+/* not weak: WEAK */
 void longjmp(jmp_buf env, int val)
 {
    __libc_longjmp(env, val);
@@ -2177,7 +2143,7 @@
 
 extern
 int __libc_send(int s, const void *msg, size_t len, int flags);
-__attribute__((weak))
+WEAK
 int send(int s, const void *msg, size_t len, int flags)
 {
    __my_pthread_testcancel();
@@ -2185,21 +2151,9 @@
 }
 
 
-extern
-int __libc_recv(int s, void *buf, size_t len, int flags);
-__attribute__((weak))
-int recv(int s, void *buf, size_t len, int flags)
-{
-   __my_pthread_testcancel();
-   wait_for_fd_to_be_readable_or_erring(s);
-   __my_pthread_testcancel();
-   return __libc_recv(s, buf, len, flags);
-}
-
-
 extern 
 int __libc_sendmsg(int s, const struct msghdr *msg, int flags);
-__attribute__((weak))
+WEAK
 int sendmsg(int s, const struct msghdr *msg, int flags)
 {
    __my_pthread_testcancel();
@@ -2209,7 +2163,7 @@
 
 extern
 int __libc_recvmsg(int s, struct msghdr *msg, int flags);
-__attribute__((weak))
+WEAK
 int recvmsg(int s, struct msghdr *msg, int flags)
 {
    __my_pthread_testcancel();
@@ -2220,12 +2174,12 @@
 extern
 int __libc_recvfrom(int s, void *buf, size_t len, int flags,
                     struct sockaddr *from, socklen_t *fromlen);
-__attribute__((weak))
+WEAK
 int recvfrom(int s, void *buf, size_t len, int flags,
              struct sockaddr *from, socklen_t *fromlen)
 {
    __my_pthread_testcancel();
-   wait_for_fd_to_be_readable_or_erring(s);
+   VGR_(wait_for_fd_to_be_readable_or_erring)(s);
    __my_pthread_testcancel();
    return __libc_recvfrom(s, buf, len, flags, from, fromlen);
 }
@@ -2234,7 +2188,7 @@
 extern
 int __libc_sendto(int s, const void *msg, size_t len, int flags, 
                   const struct sockaddr *to, socklen_t tolen);
-__attribute__((weak))
+WEAK
 int sendto(int s, const void *msg, size_t len, int flags, 
            const struct sockaddr *to, socklen_t tolen)
 {
@@ -2245,7 +2199,7 @@
 
 extern 
 int __libc_system(const char* str);
-__attribute__((weak))
+WEAK
 int system(const char* str)
 {
    __my_pthread_testcancel();
@@ -2255,7 +2209,7 @@
 
 extern
 pid_t __libc_wait(int *status);
-__attribute__((weak))
+WEAK
 pid_t wait(int *status)
 {
    __my_pthread_testcancel();
@@ -2265,7 +2219,7 @@
 
 extern
 int __libc_msync(const void *start, size_t length, int flags);
-__attribute__((weak))
+WEAK
 int msync(const void *start, size_t length, int flags)
 {
    __my_pthread_testcancel();
@@ -2352,15 +2306,6 @@
 }
 
 
-/* ---------------------------------------------------------------------
-   Nonblocking implementations of select() and poll().  This stuff will
-   surely rot your mind.
-   ------------------------------------------------------------------ */
-
-/*--------------------------------------------------*/
-
-#include "vg_kerneliface.h"
-
 static
 int my_do_syscall1 ( int syscallno, int arg1 )
 { 
@@ -2415,342 +2360,18 @@
    return __res;
 }
 
-static
-int do_syscall_select( int n, 
-                       vki_fd_set* readfds, 
-                       vki_fd_set* writefds, 
-                       vki_fd_set* exceptfds, 
-                       struct vki_timeval * timeout )
+
+WEAK
+int select ( int n, 
+             fd_set *rfds, 
+             fd_set *wfds, 
+             fd_set *xfds, 
+             struct timeval *timeout )
 {
-   int res;
-   int args[5];
-   args[0] = n;
-   args[1] = (int)readfds;
-   args[2] = (int)writefds;
-   args[3] = (int)exceptfds;
-   args[4] = (int)timeout;
-   res = my_do_syscall1(__NR_select, (int)(&(args[0])) );
-   return res;
+   return VGR_(select)(n, rfds, wfds, xfds, timeout);
 }
 
 
-/* This is a wrapper round select(), which makes it thread-safe,
-   meaning that only this thread will block, rather than the entire
-   process.  This wrapper in turn depends on nanosleep() not to block
-   the entire process, but I think (hope? suspect?) that POSIX
-   pthreads guarantees that to be the case.
-
-   Basic idea is: modify the timeout parameter to select so that it
-   returns immediately.  Poll like this until select returns non-zero,
-   indicating something interesting happened, or until our time is up.
-   Space out the polls with nanosleeps of say 11 milliseconds, which
-   is required to be nonblocking; this allows other threads to run.  
-
-   Assumes:
-   * (checked via my_assert) types fd_set and vki_fd_set are identical.
-   * (checked via my_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).
-*/
-
-int VGL_(select) ( int n, 
-		   fd_set *rfds, 
-		   fd_set *wfds, 
-		   fd_set *xfds, 
-		   struct timeval *timeout )
-{
-   unsigned int ms_now, ms_end;
-   int    res;
-   fd_set rfds_copy;
-   fd_set wfds_copy;
-   fd_set xfds_copy;
-   struct vki_timeval  t_now;
-   struct vki_timeval  zero_timeout;
-   struct vki_timespec nanosleep_interval;
-
-   __my_pthread_testcancel();
-
-   /* gcc's complains about ms_end being used uninitialised -- classic
-      case it can't understand, where ms_end is both defined and used
-      only if timeout != NULL.  Hence ... */
-   ms_end = 0;
-
-   /* We assume that the kernel and libc data layouts are identical
-      for the following types.  These asserts provide a crude
-      check. */
-   if (sizeof(fd_set) != sizeof(vki_fd_set)
-       || sizeof(struct timeval) != sizeof(struct vki_timeval))
-      barf("valgrind's hacky non-blocking select(): data sizes error");
-
-   /* Detect the current time and simultaneously find out if we are
-      running on Valgrind. */
-   VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
-                           VG_USERREQ__READ_MILLISECOND_TIMER,
-                           0, 0, 0, 0);
-
-   /* If a zero timeout specified, this call is harmless.  Also go
-      this route if we're not running on Valgrind, for whatever
-      reason. */
-   if ( (timeout && timeout->tv_sec == 0 && timeout->tv_usec == 0)
-        || (ms_now == 0xFFFFFFFF) ) {
-      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 ms_end to be the end millisecond
-      counter [wallclock] time. */
-   if (timeout) {
-      res = my_do_syscall2(__NR_gettimeofday, (int)&t_now, (int)NULL);
-      my_assert(res == 0);
-      ms_end = ms_now;
-      ms_end += (timeout->tv_usec / 1000);
-      ms_end += (timeout->tv_sec * 1000);
-      /* Stay sane ... */
-      my_assert (ms_end >= ms_now);
-   }
-
-   /* fprintf(stderr, "MY_SELECT: before loop\n"); */
-
-   /* Either timeout == NULL, meaning wait indefinitely, or timeout !=
-      NULL, in which case ms_end holds the end time. */
-
-   while (1) {
-
-      /* First, do a return-immediately select(). */
-
-      /* These could be trashed each time round the loop, so restore
-         them each time. */
-      if (rfds) rfds_copy = *rfds;
-      if (wfds) wfds_copy = *wfds;
-      if (xfds) xfds_copy = *xfds;
-
-      zero_timeout.tv_sec = zero_timeout.tv_usec = 0;
-
-      res = do_syscall_select( n, 
-                               rfds ? (vki_fd_set*)(&rfds_copy) : NULL,
-                               wfds ? (vki_fd_set*)(&wfds_copy) : NULL,
-                               xfds ? (vki_fd_set*)(&xfds_copy) : NULL,
-                               & zero_timeout );
-      if (is_kerror(res)) {
-         /* Some kind of error (including EINTR).  Set errno and
-            return.  The sets are unspecified in this case. */
-         * (__errno_location()) = -res;
-         return -1;
-      }
-      if (res > 0) {
-         /* one or more fds is ready.  Copy out resulting sets and
-            return. */
-         if (rfds) *rfds = rfds_copy;
-         if (wfds) *wfds = wfds_copy;
-         if (xfds) *xfds = xfds_copy;
-         return res;
-      }
-
-      /* Nothing interesting happened, so we go to sleep for a
-         while. */
-
-      /* fprintf(stderr, "MY_SELECT: nanosleep\n"); */
-      /* nanosleep and go round again */
-      nanosleep_interval.tv_sec  = 0;
-      nanosleep_interval.tv_nsec = 11 * 1000 * 1000; /* 11 milliseconds */
-      /* It's critical here that valgrind's nanosleep implementation
-         is nonblocking. */
-      res = my_do_syscall2(__NR_nanosleep, 
-                           (int)(&nanosleep_interval), (int)NULL);
-      if (res == -VKI_EINTR) {
-         /* The nanosleep was interrupted by a signal.  So we do the
-            same. */
-         * (__errno_location()) = EINTR;
-         return -1;
-      }
-
-      /* Sleeping finished.  If a finite timeout, check to see if it
-         has expired yet. */
-      if (timeout) {
-         VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
-                                 VG_USERREQ__READ_MILLISECOND_TIMER,
-                                 0, 0, 0, 0);
-         my_assert(ms_now != 0xFFFFFFFF);
-         if (ms_now >= ms_end) {
-            /* timeout; nothing interesting happened. */
-            if (rfds) FD_ZERO(rfds);
-            if (wfds) FD_ZERO(wfds);
-            if (xfds) FD_ZERO(xfds);
-            return 0;
-         }
-      }
-
-   }
-}
-
-
-
-
-#include <sys/poll.h>
-
-#ifndef HAVE_NFDS_T
-typedef unsigned long int nfds_t;
-#endif
-
-
-int VGL_(poll) (struct pollfd *__fds, nfds_t __nfds, int __timeout)
-{
-   unsigned int        ms_now, ms_end;
-   int                 res, i;
-   struct vki_timespec nanosleep_interval;
-
-   __my_pthread_testcancel();
-   ensure_valgrind("poll");
-
-   /* Detect the current time and simultaneously find out if we are
-      running on Valgrind. */
-   VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
-                           VG_USERREQ__READ_MILLISECOND_TIMER,
-                           0, 0, 0, 0);
-
-   if (/* CHECK SIZES FOR struct pollfd */
-       sizeof(struct timeval) != sizeof(struct vki_timeval))
-      barf("valgrind's hacky non-blocking poll(): data sizes error");
-
-   /* dummy initialisation to keep gcc -Wall happy */
-   ms_end = 0;
-
-   /* If a zero timeout specified, this call is harmless.  Also do
-      this if not running on Valgrind. */
-   if (__timeout == 0 || ms_now == 0xFFFFFFFF) {
-      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 ms_end to be the end wallclock
-      time.  Easy considering that __timeout is in milliseconds. */
-   if (__timeout > 0) {
-      ms_end = ms_now + (unsigned int)__timeout;
-   }
-
-   /* 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. */
-
-   my_assert(__timeout != 0);
-
-   while (1) {
-
-      /* Do a return-immediately poll. */
-
-      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;
-      }
-
-      /* Nothing interesting happened, so we go to sleep for a
-         while. */
-
-      /* fprintf(stderr, "MY_POLL: nanosleep\n"); */
-      /* nanosleep and go round again */
-      nanosleep_interval.tv_sec  = 0;
-      nanosleep_interval.tv_nsec = 13 * 1000 * 1000; /* 13 milliseconds */
-      /* It's critical here that valgrind's nanosleep implementation
-         is nonblocking. */
-      res = my_do_syscall2(__NR_nanosleep, 
-                           (int)(&nanosleep_interval), (int)NULL);
-      if (res == -VKI_EINTR) {
-         /* The nanosleep was interrupted by a signal.  So we do the
-            same. */
-         * (__errno_location()) = EINTR;
-         return -1;
-      }
-
-      /* Sleeping finished.  If a finite timeout, check to see if it
-         has expired yet. */
-      if (__timeout > 0) {
-         VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
-                                 VG_USERREQ__READ_MILLISECOND_TIMER,
-                                 0, 0, 0, 0);
-         my_assert(ms_now != 0xFFFFFFFF);
-         if (ms_now >= ms_end) {
-            /* timeout; nothing interesting happened. */
-            for (i = 0; i < __nfds; i++) 
-               __fds[i].revents = 0;
-            return 0;
-         }
-      }
-
-   }
-}
-
-
-/* Helper function used to make accept() non-blocking.  Idea is to use
-   the above nonblocking poll() to make this thread ONLY wait for the
-   specified fd to become ready, and then return. */
-
-/* Sigh -- a hack.  We're not supposed to include this file directly;
-   should do it via /usr/include/fcntl.h, but that introduces a
-   varargs prototype for fcntl itself, which we can't mimic. */
-#define _FCNTL_H
-#include <bits/fcntl.h>
-
-static void wait_for_fd_to_be_readable_or_erring ( int fd )
-{
-   struct pollfd pfd;
-   int           res;
-
-   /* fprintf(stderr, "wait_for_fd_to_be_readable_or_erring %d\n", fd); */
-
-   /* First check to see if the fd is nonblocking, and/or invalid.  In
-      either case return immediately. */
-   res = __libc_fcntl(fd, F_GETFL, 0);
-   if (res == -1) return; /* fd is invalid somehow */
-   if (res & O_NONBLOCK) return; /* fd is nonblocking */
-
-   /* Ok, we'd better wait with poll. */
-   pfd.fd = fd;
-   pfd.events = POLLIN | POLLPRI | POLLERR | POLLHUP | POLLNVAL;
-   /* ... but not POLLOUT, you may notice. */
-   pfd.revents = 0;
-   (void)poll(&pfd, 1, -1 /* forever */);
-}
-
-static void wait_for_fd_to_be_writable_or_erring ( int fd )
-{
-   struct pollfd pfd;
-   int           res;
-
-   /* fprintf(stderr, "wait_for_fd_to_be_readable_or_erring %d\n", fd); */
-
-   /* First check to see if the fd is nonblocking, and/or invalid.  In
-      either case return immediately. */
-   res = __libc_fcntl(fd, F_GETFL, 0);
-   if (res == -1) return; /* fd is invalid somehow */
-   if (res & O_NONBLOCK) return; /* fd is nonblocking */
-
-   /* Ok, we'd better wait with poll. */
-   pfd.fd = fd;
-   pfd.events = POLLOUT | POLLERR | POLLHUP | POLLNVAL;
-   pfd.revents = 0;
-   (void)poll(&pfd, 1, -1 /* forever */);
-}
-
 /* ---------------------------------------------------------------------
    Hacky implementation of semaphores.
    ------------------------------------------------------------------ */
@@ -3302,95 +2923,22 @@
 
 
 /* ---------------------------------------------------------------------
-   Make SYSV IPC not block everything
+   Make SYSV IPC not block everything -- pass to vg_intercept.c.
    ------------------------------------------------------------------ */
 
-#include <sys/ipc.h>
-#include <sys/msg.h>
-#include <asm/ipc.h>		/* for ipc_kludge */
-
-static inline int sys_ipc(unsigned call, int first, int second, int third, void *ptr)
+WEAK
+int msgsnd(int msgid, const void *msgp, size_t msgsz, int msgflg)
 {
-   return my_do_syscall5(__NR_ipc, call, first, second, third, (int)ptr);
+   return VGR_(msgsnd)(msgid, msgp, msgsz, msgflg);
 }
 
-/* Turn a blocking msgsnd() into a polling non-blocking one, so that
-   other threads make progress */
-int VGL_(msgsnd)(int msgid, const void *msgp, size_t msgsz, int msgflg)
+WEAK
+int msgrcv(int msqid, void* msgp, size_t msgsz, 
+           long msgtyp, int msgflg )
 {
-   struct vki_timespec nanosleep_interval;
-   int err;
-
-   ensure_valgrind("msgsnd");
-
-   nanosleep_interval.tv_sec  = 0;
-   nanosleep_interval.tv_nsec = 13 * 1000 * 1000; /* 13 milliseconds */
-
-   if (msgflg & IPC_NOWAIT) {
-      /* If we aren't blocking anyway, just do it */
-      err = sys_ipc(11, msgid, msgsz, msgflg, (void *)msgp);
-   } else {
-      /* Otherwise poll on the queue to let other things run */
-      for(;;) {
-	 err = sys_ipc(11, msgid, msgsz, msgflg | IPC_NOWAIT, (void *)msgp);
-
-	 if (err != -EAGAIN)
-	    break;
-
-	 (void)my_do_syscall2(__NR_nanosleep, 
-			      (int)(&nanosleep_interval), (int)NULL);
-      }  
-   }
-
-   if (is_kerror(err)) {
-      *(__errno_location()) = -err;
-      return -1;
-   }
-   return 0;
+   return VGR_(msgrcv)(msqid, msgp, msgsz, msgtyp, msgflg );
 }
 
-/* Turn a blocking msgrcv() into a polling non-blocking one, so that
-   other threads make progress */
-int VGL_(msgrcv)( int msqid, void  *msgp,  size_t msgsz, long msgtyp, int msgflg )
-{
-   struct vki_timespec nanosleep_interval;
-   int err;
-   struct ipc_kludge tmp;
-
-   ensure_valgrind("msgrcv");
-
-   nanosleep_interval.tv_sec  = 0;
-   nanosleep_interval.tv_nsec = 13 * 1000 * 1000; /* 13 milliseconds */
-
-   tmp.msgp = msgp;
-   tmp.msgtyp = msgtyp;
-
-   if (msgflg & IPC_NOWAIT) {
-      /* If we aren't blocking anyway, just do it */
-      err = sys_ipc(12, msqid, msgsz, msgflg, &tmp );
-   } else {
-      /* Otherwise poll on the queue to let other things run */
-      for(;;) {
-	 err = sys_ipc(12, msqid, msgsz, msgflg | IPC_NOWAIT, &tmp );
-
-	 if (err != -ENOMSG)
-	    break;
-
-	 (void)my_do_syscall2(__NR_nanosleep, 
-			      (int)(&nanosleep_interval), (int)NULL);
-      }  
-   }
-   
-   if (is_kerror(err)) {
-      *(__errno_location()) = -err;
-      return -1;
-   }
-
-   return err;
-}
-
-
-
 /* ---------------------------------------------------------------------
    B'stard.
    ------------------------------------------------------------------ */
diff --git a/include/vg_constants_skin.h b/include/vg_constants_skin.h
index 2b3fc8d..5347821 100644
--- a/include/vg_constants_skin.h
+++ b/include/vg_constants_skin.h
@@ -44,6 +44,7 @@
 #define VG_(str)    VGAPPEND(vgPlain_,str)
 #define VGP_(str)   VGAPPEND(vgProf_,str)
 #define VGOFF_(str) VGAPPEND(vgOff_,str)
+#define VGR_(str)   VGAPPEND(vgAllRoadsLeadToRome_,str)
 
 /* Skin specific ones.  Note that final name still starts with "vg". */
 #define SK_(str)    VGAPPEND(vgSkin_,str)