Added support for epoll_pwait(), utimensat(), eventfd(), timerfd() and signalfd(). Fixes bug 160907.

git-svn-id: svn://svn.valgrind.org/valgrind/trunk@7917 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/configure.in b/configure.in
index c3fd234..97d2980 100644
--- a/configure.in
+++ b/configure.in
@@ -953,7 +953,15 @@
 
 # Checks for header files.
 AC_HEADER_STDC
-AC_CHECK_HEADERS([sys/endian.h endian.h mqueue.h])
+AC_CHECK_HEADERS([       \
+        endian.h         \
+        mqueue.h         \
+        sys/endian.h     \
+        sys/epoll.h      \
+        sys/eventfd.h    \
+        sys/poll.h       \
+        sys/signalfd.h   \
+        ])
 
 
 # Checks for typedefs, structures, and compiler characteristics.
@@ -968,8 +976,27 @@
 AC_FUNC_MMAP
 AC_TYPE_SIGNAL
 
-AC_CHECK_FUNCS([floor memchr memset mkdir strchr strdup strpbrk strrchr strstr semtimedop])
-AC_CHECK_FUNCS([mallinfo])
+AC_CHECK_FUNCS([     \
+        epoll_create \
+        epoll_pwait  \
+        eventfd      \
+        eventfd_read \
+        floor        \
+        mallinfo     \
+        memchr       \
+        memset       \
+        mkdir        \
+        ppoll        \
+        semtimedop   \
+        signalfd     \
+        strchr       \
+        strdup       \
+        strpbrk      \
+        strrchr      \
+        strstr       \
+        timerfd      \
+        utimensat    \
+        ])
 
 
 # Do we have a useable MPI setup on the primary and/or secondary targets?
diff --git a/coregrind/m_syswrap/priv_syswrap-linux.h b/coregrind/m_syswrap/priv_syswrap-linux.h
index 115c436..0033494 100644
--- a/coregrind/m_syswrap/priv_syswrap-linux.h
+++ b/coregrind/m_syswrap/priv_syswrap-linux.h
@@ -82,6 +82,8 @@
 DECL_TEMPLATE(linux, sys_epoll_create);
 DECL_TEMPLATE(linux, sys_epoll_ctl);
 DECL_TEMPLATE(linux, sys_epoll_wait);
+DECL_TEMPLATE(linux, sys_epoll_pwait);
+DECL_TEMPLATE(linux, sys_eventfd);
 
 DECL_TEMPLATE(linux, sys_gettid);
 DECL_TEMPLATE(linux, sys_set_tid_address);
@@ -124,6 +126,9 @@
 DECL_TEMPLATE(linux, sys_timer_gettime);
 DECL_TEMPLATE(linux, sys_timer_getoverrun);
 DECL_TEMPLATE(linux, sys_timer_delete);
+DECL_TEMPLATE(linux, sys_timerfd);
+
+DECL_TEMPLATE(linux, sys_signalfd);
 
 DECL_TEMPLATE(linux, sys_capget);
 DECL_TEMPLATE(linux, sys_capset);
diff --git a/coregrind/m_syswrap/syswrap-amd64-linux.c b/coregrind/m_syswrap/syswrap-amd64-linux.c
index b49c27d..24c1a53 100644
--- a/coregrind/m_syswrap/syswrap-amd64-linux.c
+++ b/coregrind/m_syswrap/syswrap-amd64-linux.c
@@ -1370,7 +1370,7 @@
    LINX_(__NR_faccessat,	 sys_faccessat),        // 269
 
    LINX_(__NR_pselect6,		 sys_pselect6),         // 270
-//   LINXY(__NR_ppoll,		 sys_ni_syscall),       // 271
+   LINXY(__NR_ppoll,		 sys_ppoll),            // 271
 //   LINX_(__NR_unshare,		 sys_unshare),          // 272
    LINX_(__NR_set_robust_list,	 sys_set_robust_list),  // 273
    LINXY(__NR_get_robust_list,	 sys_get_robust_list),  // 274
@@ -1380,6 +1380,12 @@
    LINX_(__NR_sync_file_range,   sys_sync_file_range),  // 277
 //   LINX_(__NR_vmsplice,          sys_ni_syscall),       // 278
 //   LINX_(__NR_move_pages,        sys_ni_syscall),       // 279
+   LINX_(__NR_utimensat,         sys_utimensat),        // 280
+   LINXY(__NR_epoll_pwait,       sys_epoll_pwait),      // 281
+   LINXY(__NR_signalfd,          sys_signalfd),         // 282
+   LINXY(__NR_timerfd,           sys_timerfd),          // 283
+   LINX_(__NR_eventfd,           sys_eventfd),          // 284
+//   LINX_(__NR_fallocate,        sys_ni_syscall),        // 285
 };
 
 const UInt ML_(syscall_table_size) = 
diff --git a/coregrind/m_syswrap/syswrap-generic.c b/coregrind/m_syswrap/syswrap-generic.c
index 4820713..d7e0755 100644
--- a/coregrind/m_syswrap/syswrap-generic.c
+++ b/coregrind/m_syswrap/syswrap-generic.c
@@ -5638,7 +5638,7 @@
    PRE_REG_READ2(long, "utimes", char *, filename, struct timeval *, tvp);
    PRE_MEM_RASCIIZ( "utimes(filename)", ARG1 );
    if (ARG2 != 0)
-      PRE_MEM_READ( "utimes(tvp)", ARG2, sizeof(struct vki_timeval) );
+      PRE_MEM_READ( "utimes(tvp)", ARG2, 2 * sizeof(struct vki_timeval) );
 }
 
 PRE(sys_acct)
diff --git a/coregrind/m_syswrap/syswrap-linux.c b/coregrind/m_syswrap/syswrap-linux.c
index 0f4b8f3..a0cabc3 100644
--- a/coregrind/m_syswrap/syswrap-linux.c
+++ b/coregrind/m_syswrap/syswrap-linux.c
@@ -988,7 +988,7 @@
    UInt i;
    struct vki_pollfd* ufds = (struct vki_pollfd *)ARG1;
    *flags |= SfMayBlock;
-   PRINT("sys_ppoll ( %p, %d, %p, %p, %llu )\n", ARG1,ARG2,ARG3,ARG4,ARG5);
+   PRINT("sys_ppoll ( %p, %d, %p, %p, %llu )\n", ARG1,ARG2,ARG3,ARG4,(ULong)ARG5);
    PRE_REG_READ5(long, "ppoll",
                  struct vki_pollfd *, ufds, unsigned int, nfds,
                  struct vki_timespec *, tsp, vki_sigset_t *, sigmask,
@@ -1072,6 +1072,41 @@
       POST_MEM_WRITE( ARG2, sizeof(struct vki_epoll_event)*RES ) ;
 }
 
+PRE(sys_epoll_pwait)
+{
+   *flags |= SfMayBlock;
+   PRINT("sys_epoll_pwait ( %d, %p, %d, %d, %p, %llu )", ARG1,ARG2,ARG3,ARG4,ARG5,(ULong)ARG6);
+   PRE_REG_READ6(long, "epoll_pwait",
+                 int, epfd, struct vki_epoll_event *, events,
+                 int, maxevents, int, timeout, vki_sigset_t *, sigmask,
+                 vki_size_t, sigsetsize);
+   PRE_MEM_WRITE( "epoll_pwait(events)", ARG2, sizeof(struct vki_epoll_event)*ARG3);
+   if (ARG4)
+      PRE_MEM_READ( "epoll_pwait(sigmask)", ARG5, sizeof(vki_sigset_t) );
+}
+POST(sys_epoll_pwait)
+{
+   vg_assert(SUCCESS);
+   if (RES > 0)
+      POST_MEM_WRITE( ARG2, sizeof(struct vki_epoll_event)*RES ) ;
+}
+
+PRE(sys_eventfd)
+{
+   PRINT("sys_eventfd ( %u )", ARG1);
+   PRE_REG_READ1(long, "sys_eventfd", unsigned int, count);
+}
+POST(sys_eventfd)
+{
+   if (!ML_(fd_allowed)(RES, "eventfd", tid, True)) {
+      VG_(close)(RES);
+      SET_STATUS_Failure( VKI_EMFILE );
+   } else {
+      if (VG_(clo_track_fds))
+         ML_(record_fd_open_nameless) (tid, RES);
+   }
+}
+
 /* ---------------------------------------------------------------------
    tid-related wrappers
    ------------------------------------------------------------------ */
@@ -1672,6 +1707,27 @@
    PRE_REG_READ1(long, "timer_delete", vki_timer_t, timerid);
 }
 
+PRE(sys_timerfd)
+{
+   PRINT("sys_timerfd ( %d, %d, %p )", ARG1, ARG2, ARG3);
+   PRE_REG_READ3(long, "sys_timerfd",
+                 int, fd, int, clockid, const struct itimerspec *, tmr);
+   PRE_MEM_READ( "timerfd(tmr)", ARG3,
+                  sizeof(struct vki_itimerspec) );
+   if (ARG1 != -1 && !ML_(fd_allowed)(ARG1, "timerfd", tid, False))
+      SET_STATUS_Failure( VKI_EBADF );
+}
+POST(sys_timerfd)
+{
+   if (!ML_(fd_allowed)(RES, "timerfd", tid, True)) {
+      VG_(close)(RES);
+      SET_STATUS_Failure( VKI_EMFILE );
+   } else {
+      if (VG_(clo_track_fds))
+         ML_(record_fd_open_nameless) (tid, RES);
+   }
+}
+
 /* ---------------------------------------------------------------------
    capabilities wrappers
    ------------------------------------------------------------------ */
@@ -2220,6 +2276,27 @@
 }
 #endif
 
+PRE(sys_signalfd)
+{
+   PRINT("sys_signalfd ( %d, %p, %llu )", ARG1, ARG2, (ULong) ARG3);
+   PRE_REG_READ3(long, "sys_signalfd",
+                 int, fd, vki_sigset_t *, sigmask, vki_size_t, sigsetsize);
+   PRE_MEM_READ( "signalfd(sigmask)", ARG2, sizeof(vki_sigset_t) );
+   if (ARG1 != -1 && !ML_(fd_allowed)(ARG1, "signalfd", tid, False))
+      SET_STATUS_Failure( VKI_EBADF );
+}
+POST(sys_signalfd)
+{
+   if (!ML_(fd_allowed)(RES, "signalfd", tid, True)) {
+      VG_(close)(RES);
+      SET_STATUS_Failure( VKI_EMFILE );
+   } else {
+      if (VG_(clo_track_fds))
+         ML_(record_fd_open_nameless) (tid, RES);
+   }
+}
+
+
 /* ---------------------------------------------------------------------
    rt_sig* wrappers
    ------------------------------------------------------------------ */
@@ -2542,7 +2619,17 @@
                  int, dfd, char *, filename, struct timeval *, tvp);
    PRE_MEM_RASCIIZ( "futimesat(filename)", ARG2 );
    if (ARG3 != 0)
-      PRE_MEM_READ( "futimesat(tvp)", ARG3, sizeof(struct vki_timeval) );
+      PRE_MEM_READ( "futimesat(tvp)", ARG3, 2 * sizeof(struct vki_timeval) );
+}
+
+PRE(sys_utimensat)
+{
+   PRINT("sys_utimensat ( %d, %p(%s), %p, 0x%x )", ARG1,ARG2,ARG2,ARG3,ARG4);
+   PRE_REG_READ4(long, "utimensat",
+                 int, dfd, char *, filename, struct timespec *, utimes, int, flags);
+   PRE_MEM_RASCIIZ( "utimensat(filename)", ARG2 );
+   if (ARG3 != 0)
+      PRE_MEM_READ( "utimensat(tvp)", ARG3, 2 * sizeof(struct vki_timespec) );
 }
 
 PRE(sys_newfstatat)
@@ -2823,19 +2910,6 @@
    PRE_REG_READ3(int, "ioprio_set", int, which, int, who, int, ioprio);
 }
 
-
-/* XXX I don't think this is really the right place for this.
-   Move it elsewhere in this file? */
-PRE(sys_utimensat)
-{
-   PRINT("sys_utimensat ( %d, %p(%s), %p )", ARG1,ARG2,ARG2,ARG3);
-   PRE_REG_READ3(long, "utimensat",
-                 int, dfd, char *, filename, struct timespec *, tvp);
-   PRE_MEM_RASCIIZ( "utimensat(filename)", ARG2 );
-   if (ARG3 != 0)
-      PRE_MEM_READ( "utimensat(tvp)", ARG3, sizeof(struct vki_timespec) );
-}
-
 #undef PRE
 #undef POST
 
diff --git a/coregrind/m_syswrap/syswrap-ppc32-linux.c b/coregrind/m_syswrap/syswrap-ppc32-linux.c
index 2da5111..92e4d40 100644
--- a/coregrind/m_syswrap/syswrap-ppc32-linux.c
+++ b/coregrind/m_syswrap/syswrap-ppc32-linux.c
@@ -1823,6 +1823,15 @@
    LINX_(__NR_faccessat,         sys_faccessat),         // 298
    LINX_(__NR_set_robust_list,   sys_set_robust_list),   // 299
    LINXY(__NR_get_robust_list,   sys_get_robust_list),   // 300
+//   LINX_(__NR_move_pages,        sys_ni_syscall),        // 301
+//   LINX_(__NR_getcpu,            sys_ni_syscall),        // 302
+   LINXY(__NR_epoll_pwait,       sys_epoll_pwait),       // 303
+   LINX_(__NR_utimensat,         sys_utimensat),         // 304
+   LINXY(__NR_signalfd,          sys_signalfd),          // 305
+   LINXY(__NR_timerfd,           sys_timerfd),           // 306
+   LINX_(__NR_eventfd,           sys_eventfd),           // 307
+//   LINX_(__NR_sync_file_range2,   sys_ni_syscall),       // 308
+//   LINX_(__NR_fallocate,        sys_ni_syscall),         // 309
 };
 
 const UInt ML_(syscall_table_size) = 
diff --git a/coregrind/m_syswrap/syswrap-ppc64-linux.c b/coregrind/m_syswrap/syswrap-ppc64-linux.c
index ebf975f..28934e4 100644
--- a/coregrind/m_syswrap/syswrap-ppc64-linux.c
+++ b/coregrind/m_syswrap/syswrap-ppc64-linux.c
@@ -1478,7 +1478,15 @@
    LINX_(__NR_faccessat,         sys_faccessat),          // 298
    LINX_(__NR_set_robust_list,   sys_set_robust_list),    // 299
    LINXY(__NR_get_robust_list,   sys_get_robust_list),    // 300
-
+//   LINX_(__NR_move_pages,        sys_ni_syscall),        // 301
+//   LINX_(__NR_getcpu,            sys_ni_syscall),        // 302
+   LINXY(__NR_epoll_pwait,       sys_epoll_pwait),       // 303
+   LINX_(__NR_utimensat,         sys_utimensat),         // 304
+   LINXY(__NR_signalfd,          sys_signalfd),          // 305
+   LINXY(__NR_timerfd,           sys_timerfd),           // 306
+   LINX_(__NR_eventfd,           sys_eventfd),           // 307
+//   LINX_(__NR_sync_file_range2,   sys_ni_syscall),       // 308
+//   LINX_(__NR_fallocate,        sys_ni_syscall),         // 309
 };
 
 const UInt ML_(syscall_table_size) = 
diff --git a/coregrind/m_syswrap/syswrap-x86-linux.c b/coregrind/m_syswrap/syswrap-x86-linux.c
index 8019310..b96007c 100644
--- a/coregrind/m_syswrap/syswrap-x86-linux.c
+++ b/coregrind/m_syswrap/syswrap-x86-linux.c
@@ -2224,9 +2224,13 @@
 //   LINX_(__NR_vmsplice,          sys_ni_syscall),       // 316
 //   LINX_(__NR_move_pages,        sys_ni_syscall),       // 317
 //   LINX_(__NR_getcpu,            sys_ni_syscall),       // 318
-//   LINX_(__NR_epoll_pwait,       sys_ni_syscall),       // 319
+   LINXY(__NR_epoll_pwait,       sys_epoll_pwait),      // 319
 
    LINX_(__NR_utimensat,         sys_utimensat),        // 320
+   LINXY(__NR_signalfd,          sys_signalfd),         // 321
+   LINXY(__NR_timerfd,           sys_timerfd),          // 322
+   LINX_(__NR_eventfd,           sys_eventfd),          // 323
+//   LINX_(__NR_fallocate,        sys_ni_syscall),        // 324
 };
 
 const UInt ML_(syscall_table_size) = 
diff --git a/memcheck/tests/Makefile.am b/memcheck/tests/Makefile.am
index 8bc298b..e75c2d3 100644
--- a/memcheck/tests/Makefile.am
+++ b/memcheck/tests/Makefile.am
@@ -65,6 +65,7 @@
 	leak-tree.stderr.exp2 leak-tree.stderr.exp64 \
 	leak-regroot.vgtest leak-regroot.stderr.exp \
 	leakotron.vgtest leakotron.stdout.exp leakotron.stderr.exp \
+	linux-syscalls-2007 linux-syscalls-2007.stderr.exp \
 	long_namespace_xml.vgtest long_namespace_xml.stdout.exp \
 	long_namespace_xml.stderr.exp \
 	lsframe1.vgtest lsframe1.stdout.exp lsframe1.stderr.exp \
@@ -170,6 +171,7 @@
 	doublefree error_counts errs1 exitprog execve execve2 erringfds \
 	fprw fwrite hello inits inline \
 	leak-0 leak-cycle leak-pool leak-tree leak-regroot leakotron \
+	linux-syscalls-2007 \
 	long_namespace_xml \
 	lsframe1 lsframe2 \
 	mallinfo \
diff --git a/memcheck/tests/linux-syscalls-2007.c b/memcheck/tests/linux-syscalls-2007.c
new file mode 100644
index 0000000..0cbafa1
--- /dev/null
+++ b/memcheck/tests/linux-syscalls-2007.c
@@ -0,0 +1,75 @@
+/**
+ * Test program for some Linux syscalls introduced during 2006 and 2007:
+ * - epoll_pwait() was introduced in the 2.6.19 kernel, released in November
+ *     2006.
+ * - utimensat(), eventfd(), timerfd() and signalfd() were introduced in the
+ *     2.6.22 kernel, released in July 2007.
+ *
+ * See also http://bugs.kde.org/show_bug.cgi?id=160907.
+ */
+
+#define _GNU_SOURCE
+
+#include "../../config.h"
+#include <fcntl.h>
+#include <signal.h>
+#if defined(HAVE_SYS_EPOLL_H)
+#include <sys/epoll.h>
+#endif
+#if defined(HAVE_SYS_EVENTFD_H)
+#include <sys/eventfd.h>
+#endif
+#if defined(HAVE_SYS_POLL_H)
+#include <sys/poll.h>
+#endif
+#if defined(HAVE_SYS_SIGNALFD_H)
+#include <sys/signalfd.h>
+#endif
+#include <sys/stat.h>
+#include <unistd.h>
+
+int main (void)
+{
+#if defined(HAVE_SIGNALFD) && defined(HAVE_EVENTFD) \
+    && defined(HAVE_EVENTFD_READ) && defined(HAVE_PPOLL)
+  {
+    sigset_t mask;
+    sigemptyset (&mask);
+    sigaddset (&mask, SIGUSR1);
+    int fd = signalfd (-1, &mask, 0);
+    sigaddset (&mask, SIGUSR2);
+    fd = signalfd (fd, &mask, 0);
+    int fd2 = eventfd (5, 0);
+    eventfd_t ev;
+    eventfd_read (fd2, &ev);
+    struct timespec ts = { .tv_sec = 1, .tv_nsec = 0 };
+    struct pollfd pfd[2] = { [0].fd = fd, [0].events = POLLIN|POLLOUT,
+                             [1].fd = fd2, [1].events = POLLIN|POLLOUT };
+    ppoll (pfd, 2, &ts, &mask);
+  }
+#endif
+
+#if defined(HAVE_UTIMENSAT)
+  unlink("/tmp/valgrind-utimensat-test");
+  close (creat ("/tmp/valgrind-utimensat-test", S_IRUSR | S_IWUSR));
+  {
+    struct timespec ts2[2] = { [0].tv_sec = 10000000, [1].tv_sec = 20000000 };
+    utimensat (AT_FDCWD, "/tmp/valgrind-utimensat-test", ts2, 0);
+  }
+  unlink("/tmp/valgrind-utimensat-test");
+#endif
+
+#if defined(HAVE_EPOLL_CREATE) && defined(HAVE_EPOLL_PWAIT)
+  {
+    int fd3 = epoll_create (10);
+    struct epoll_event evs[10];
+    sigset_t mask;
+    sigemptyset (&mask);
+    sigaddset (&mask, SIGUSR1);
+    sigaddset (&mask, SIGUSR2);
+    epoll_pwait (fd3, evs, 10, 0, &mask);
+  }
+#endif
+
+  return 0;
+}
diff --git a/memcheck/tests/linux-syscalls-2007.stderr.exp b/memcheck/tests/linux-syscalls-2007.stderr.exp
new file mode 100644
index 0000000..c4aa6f0
--- /dev/null
+++ b/memcheck/tests/linux-syscalls-2007.stderr.exp
@@ -0,0 +1,7 @@
+
+
+ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
+malloc/free: in use at exit: 0 bytes in 0 blocks.
+malloc/free: 0 allocs, 0 frees, 0 bytes allocated.
+For a detailed leak analysis,  rerun with: --leak-check=yes
+For counts of detected errors, rerun with: -v
diff --git a/memcheck/tests/linux-syscalls-2007.vgtest b/memcheck/tests/linux-syscalls-2007.vgtest
new file mode 100644
index 0000000..55e548a
--- /dev/null
+++ b/memcheck/tests/linux-syscalls-2007.vgtest
@@ -0,0 +1 @@
+prog: linux-syscalls-2007