This is the mail archive of the libc-alpha@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[RFC v2 08/20] sysdeps/wait: Use waitid if avaliable


If the waitid syscall is avaliable let's use that as waitpid
and wait4 aren't always avaliable (they aren't avaliable on RV32).

Unfortunately waitid is substantially differnt to waitpid and wait4, so
the conversion ends up being complex.

Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 ChangeLog                                  |  3 ++
 sysdeps/unix/sysv/linux/wait.c             | 21 ++++++++-
 sysdeps/unix/sysv/linux/waitpid.c          | 54 ++++++++++++++++++++++
 sysdeps/unix/sysv/linux/waitpid_nocancel.c | 53 +++++++++++++++++++++
 4 files changed, 129 insertions(+), 2 deletions(-)

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..67b94776a4 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,
-				 (struct rusage *) NULL);
+  pid_t result;
+
+#ifdef __NR_waitid
+  siginfo_t infop;
+
+  result = SYSCALL_CANCEL (waitid, P_ALL, 0, &infop, WEXITED);
+
+  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..8c0e2f882a 100644
--- a/sysdeps/unix/sysv/linux/waitpid.c
+++ b/sysdeps/unix/sysv/linux/waitpid.c
@@ -20,12 +20,66 @@
 #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, waitid_options = 0;
+  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();
+  }
+
+  /* Convert the older WNOHANG, WUNTRACED and WCONTINUED options to the newer
+   * ones uses for waitid().
+   */
+  if (options | WNOHANG) {
+    waitid_options |= WNOHANG;
+  }
+  if (options | WUNTRACED) {
+    waitid_options |= WSTOPPED;
+  }
+  if (options | WCONTINUED) {
+    waitid_options |= WCONTINUED;
+  }
+
+  /* waitid() requires at least WEXITED, WSTOPPED or WCONTINUED to be
+   * specified. If none were specified default to WEXITED as that is what
+   * waitpid() and wait4() do.
+   */
+  if (options == 0 || waitid_options == WNOHANG) {
+    waitid_options |= WEXITED;
+  }
+
+  ret = SYSCALL_CANCEL (waitid, idtype, pid, &infop, waitid_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..d14b7bf260 100644
--- a/sysdeps/unix/sysv/linux/waitpid_nocancel.c
+++ b/sysdeps/unix/sysv/linux/waitpid_nocancel.c
@@ -27,6 +27,59 @@ __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, waitid_options = 0;
+  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();
+  }
+
+  /* Convert the older WNOHANG, WUNTRACED and WCONTINUED options to the newer
+   * ones uses for waitid().
+   */
+  if (options | WNOHANG) {
+    waitid_options |= WNOHANG;
+  }
+  if (options | WUNTRACED) {
+    waitid_options |= WSTOPPED;
+  }
+  if (options | WCONTINUED) {
+    waitid_options |= WCONTINUED;
+  }
+
+  /* waitid() requires at least WEXITED, WSTOPPED or WCONTINUED to be
+   * specified. If none were specified default to WEXITED as that is what
+   * waitpid() and wait4() do.
+   */
+  if (options == 0 || waitid_options == WNOHANG) {
+    waitid_options |= WEXITED;
+  }
+
+  ret = INLINE_SYSCALL_CALL (waitid, idtype, pid, &infop, waitid_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
-- 
2.22.0


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]