diff mbox series

[RFC,v1,04/16] sysdeps/wait: Use __NR_waitid if avaliable

Message ID 358c124ab1be979da9bc0051dc799dd2c37cdfb2.1561177967.git.alistair.francis@wdc.com
State New
Headers show
Series RISC-V glibc port for the 32-bit | expand

Commit Message

Alistair Francis June 22, 2019, 4:37 a.m. UTC
If the __NR_waitid syscall is avaliable let's use that as __NR_waitpid
and __NR_wait4 aren't always avaliable (they aren't avaliable on RV32).

Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 ChangeLog                                  |  3 ++
 sysdeps/unix/sysv/linux/wait.c             | 19 ++++++++++++-
 sysdeps/unix/sysv/linux/waitpid.c          | 33 ++++++++++++++++++++++
 sysdeps/unix/sysv/linux/waitpid_nocancel.c | 32 +++++++++++++++++++++
 4 files changed, 86 insertions(+), 1 deletion(-)
diff mbox series

Patch

diff --git a/ChangeLog b/ChangeLog
index f1c7acb6ab..9ed9bea8b1 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -5,6 +5,9 @@ 
 	* sysdeps/unix/sysv/linux/nanosleep_nocancel.c: Likewise.
 	* sysdeps/unix/sysv/linux/lowlevellock-futex.h: Use __NR_futex_time64 if we don't have __NR_futex.
 	* sysdeps/unix/sysv/linux/gettimeofday.c: Use clock_gettime64 syscall for gettimeofday.
+	* sysdeps/unix/sysv/linux/wait.c: Use __NR_waitid if avaliable.
+	* sysdeps/unix/sysv/linux/waitpid.c: Likewise.
+	* sysdeps/unix/sysv/linux/waitpid_nocancel.c: Likewise.
 
 2019-06-20  Dmitry V. Levin  <ldv@altlinux.org>
 	    Florian Weimer  <fweimer@redhat.com>
diff --git a/sysdeps/unix/sysv/linux/wait.c b/sysdeps/unix/sysv/linux/wait.c
index 498bd1c095..9e81ea61ba 100644
--- a/sysdeps/unix/sysv/linux/wait.c
+++ b/sysdeps/unix/sysv/linux/wait.c
@@ -26,8 +26,25 @@ 
 pid_t
 __libc_wait (int *stat_loc)
 {
-  pid_t result = SYSCALL_CANCEL (wait4, WAIT_ANY, stat_loc, 0,
+  pid_t result;
+
+#if defined(__NR_waitid)
+  siginfo_t infop;
+
+  result = SYSCALL_CANCEL (waitid, P_ALL, 0, &infop, 0);
+
+  if (stat_loc) {
+    *stat_loc = infop.si_status;
+  }
+
+  if (result == 0) {
+    result = infop.si_pid;
+  }
+#else
+  result = SYSCALL_CANCEL (wait4, WAIT_ANY, stat_loc, 0,
 				 (struct rusage *) NULL);
+#endif
+
   return result;
 }
 
diff --git a/sysdeps/unix/sysv/linux/waitpid.c b/sysdeps/unix/sysv/linux/waitpid.c
index f0897574c0..8bc15ba92f 100644
--- a/sysdeps/unix/sysv/linux/waitpid.c
+++ b/sysdeps/unix/sysv/linux/waitpid.c
@@ -20,12 +20,45 @@ 
 #include <sysdep-cancel.h>
 #include <stdlib.h>
 #include <sys/wait.h>
+#include <unistd.h>
 
 __pid_t
 __waitpid (__pid_t pid, int *stat_loc, int options)
 {
 #ifdef __NR_waitpid
   return SYSCALL_CANCEL (waitpid, pid, stat_loc, options);
+#elif defined(__NR_waitid)
+  int ret;
+  idtype_t idtype = P_PID;
+  siginfo_t infop;
+
+  /* Set this to zero so we can test if WNOHANG was specified in options
+   * and there were no children in a waitable state. This is required to match
+   * waitid() behaviour.
+   */
+  infop.si_pid = 0;
+
+  if (pid < -1) {
+    idtype = P_PGID;
+    pid *= -1;
+  } else if (pid == -1) {
+    idtype = P_ALL;
+  } else if (pid == 0) {
+    idtype = P_PGID;
+    pid = getpgrp();
+  }
+
+  ret = SYSCALL_CANCEL (waitid, idtype, pid, &infop, options);
+
+  if (stat_loc) {
+    *stat_loc = infop.si_status;
+  }
+
+  if (ret == 0) {
+    return infop.si_pid;
+  }
+
+  return ret;
 #else
   return SYSCALL_CANCEL (wait4, pid, stat_loc, options, NULL);
 #endif
diff --git a/sysdeps/unix/sysv/linux/waitpid_nocancel.c b/sysdeps/unix/sysv/linux/waitpid_nocancel.c
index 89e36a5c0b..d50d15c488 100644
--- a/sysdeps/unix/sysv/linux/waitpid_nocancel.c
+++ b/sysdeps/unix/sysv/linux/waitpid_nocancel.c
@@ -27,6 +27,38 @@  __waitpid_nocancel (__pid_t pid, int *stat_loc, int options)
 {
 #ifdef __NR_waitpid
   return INLINE_SYSCALL_CALL (waitpid, pid, stat_loc, options);
+#elif defined(__NR_waitid)
+  int ret;
+  idtype_t idtype = P_PID;
+  siginfo_t infop;
+
+  /* Set this to zero so we can test if WNOHANG was specified in options
+   * and there were no children in a waitable state. This is required to match
+   * waitid() behaviour.
+   */
+  infop.si_pid = 0;
+
+  if (pid < -1) {
+    idtype = P_PGID;
+    pid *= -1;
+  } else if (pid == -1) {
+    idtype = P_ALL;
+  } else if (pid == 0) {
+    idtype = P_PGID;
+    pid = getpgrp();
+  }
+
+  ret = INLINE_SYSCALL_CALL (waitid, idtype, pid, &infop, options);
+
+  if (stat_loc) {
+    *stat_loc = infop.si_status;
+  }
+
+  if (ret == 0) {
+    return infop.si_pid;
+  }
+
+  return ret;
 #else
   return INLINE_SYSCALL_CALL (wait4, pid, stat_loc, options, NULL);
 #endif