Patchwork sysdeps/wait: Use the waitid syscall if required

login
register
mail settings
Submitter Alistair Francis
Date Sept. 25, 2019, 10:55 p.m.
Message ID <20190925225514.7224-1-alistair.francis@wdc.com>
Download mbox | patch
Permalink /patch/34665/
State New
Headers show

Comments

Alistair Francis - Sept. 25, 2019, 10:55 p.m.
If the waitpid and wait4 syscalls aren't avaliable (such as y2038 safe
32-bit systems) let us use the waitid syscall isntead.

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

For full support we need the 5.4+ kernel as that allows a pid of 0 with
the P_PGID idtype.

2019-09-16  Alistair Francis  <alistair.francis@wdc.com>

	* sysdeps/unix/sysv/linux/wait.c: Use the waitid syscall if required.
	* sysdeps/unix/sysv/linux/waitpid.c: Likewise.
	* sysdeps/unix/sysv/linux/waitpid_nocancel.c: Likewise.
---
Tested with the 5.3 kernel + two waitid patches with RV32.

Currently no supported glibc architecture will use the new waitid
syscall.

 sysdeps/unix/sysv/linux/wait.c             | 41 +++++++++++++--
 sysdeps/unix/sysv/linux/waitpid.c          | 59 +++++++++++++++++++++-
 sysdeps/unix/sysv/linux/waitpid_nocancel.c | 56 +++++++++++++++++++-
 3 files changed, 151 insertions(+), 5 deletions(-)
Dmitry Levin - Oct. 12, 2019, 12:24 p.m.
On Wed, Sep 25, 2019 at 03:55:14PM -0700, Alistair Francis wrote:
> If the waitpid and wait4 syscalls aren't avaliable (such as y2038 safe
> 32-bit systems) let us use the waitid syscall isntead.
> 
> Unfortunately waitid is substantially differnt to waitpid and wait4, so
> the conversion ends up being complex.
> 
> For full support we need the 5.4+ kernel as that allows a pid of 0 with
> the P_PGID idtype.
> 
> 2019-09-16  Alistair Francis  <alistair.francis@wdc.com>
> 
> 	* sysdeps/unix/sysv/linux/wait.c: Use the waitid syscall if required.
> 	* sysdeps/unix/sysv/linux/waitpid.c: Likewise.
> 	* sysdeps/unix/sysv/linux/waitpid_nocancel.c: Likewise.

If wait4 is not available, shouldn't it be emulated as well as waitpid?
Alistair Francis - Oct. 16, 2019, 3:54 p.m.
On Sat, Oct 12, 2019 at 5:24 AM Dmitry V. Levin <ldv@altlinux.org> wrote:
>
> On Wed, Sep 25, 2019 at 03:55:14PM -0700, Alistair Francis wrote:
> > If the waitpid and wait4 syscalls aren't avaliable (such as y2038 safe
> > 32-bit systems) let us use the waitid syscall isntead.
> >
> > Unfortunately waitid is substantially differnt to waitpid and wait4, so
> > the conversion ends up being complex.
> >
> > For full support we need the 5.4+ kernel as that allows a pid of 0 with
> > the P_PGID idtype.
> >
> > 2019-09-16  Alistair Francis  <alistair.francis@wdc.com>
> >
> >       * sysdeps/unix/sysv/linux/wait.c: Use the waitid syscall if required.
> >       * sysdeps/unix/sysv/linux/waitpid.c: Likewise.
> >       * sysdeps/unix/sysv/linux/waitpid_nocancel.c: Likewise.
>
> If wait4 is not available, shouldn't it be emulated as well as waitpid?

Yes, it is by the changed in wait.c.

Alistair

>
>
> --
> ldv
Dmitry Levin - Oct. 16, 2019, 5:35 p.m.
On Wed, Oct 16, 2019 at 08:54:08AM -0700, Alistair Francis wrote:
> On Sat, Oct 12, 2019 at 5:24 AM Dmitry V. Levin wrote:
> > On Wed, Sep 25, 2019 at 03:55:14PM -0700, Alistair Francis wrote:
> > > If the waitpid and wait4 syscalls aren't avaliable (such as y2038 safe
> > > 32-bit systems) let us use the waitid syscall isntead.
> > >
> > > Unfortunately waitid is substantially differnt to waitpid and wait4, so
> > > the conversion ends up being complex.
> > >
> > > For full support we need the 5.4+ kernel as that allows a pid of 0 with
> > > the P_PGID idtype.
> > >
> > > 2019-09-16  Alistair Francis  <alistair.francis@wdc.com>
> > >
> > >       * sysdeps/unix/sysv/linux/wait.c: Use the waitid syscall if required.
> > >       * sysdeps/unix/sysv/linux/waitpid.c: Likewise.
> > >       * sysdeps/unix/sysv/linux/waitpid_nocancel.c: Likewise.
> >
> > If wait4 is not available, shouldn't it be emulated as well as waitpid?
> 
> Yes, it is by the changed in wait.c.

This change of wait.c affects __libc_wait only, I don't see how it makes
wait4 emulated.
Alistair Francis - Oct. 16, 2019, 6:17 p.m.
On Wed, Oct 16, 2019 at 10:35 AM Dmitry V. Levin <ldv@altlinux.org> wrote:
>
> On Wed, Oct 16, 2019 at 08:54:08AM -0700, Alistair Francis wrote:
> > On Sat, Oct 12, 2019 at 5:24 AM Dmitry V. Levin wrote:
> > > On Wed, Sep 25, 2019 at 03:55:14PM -0700, Alistair Francis wrote:
> > > > If the waitpid and wait4 syscalls aren't avaliable (such as y2038 safe
> > > > 32-bit systems) let us use the waitid syscall isntead.
> > > >
> > > > Unfortunately waitid is substantially differnt to waitpid and wait4, so
> > > > the conversion ends up being complex.
> > > >
> > > > For full support we need the 5.4+ kernel as that allows a pid of 0 with
> > > > the P_PGID idtype.
> > > >
> > > > 2019-09-16  Alistair Francis  <alistair.francis@wdc.com>
> > > >
> > > >       * sysdeps/unix/sysv/linux/wait.c: Use the waitid syscall if required.
> > > >       * sysdeps/unix/sysv/linux/waitpid.c: Likewise.
> > > >       * sysdeps/unix/sysv/linux/waitpid_nocancel.c: Likewise.
> > >
> > > If wait4 is not available, shouldn't it be emulated as well as waitpid?
> >
> > Yes, it is by the changed in wait.c.
>
> This change of wait.c affects __libc_wait only, I don't see how it makes
> wait4 emulated.

I'm not clear on what you mean. Do you mean the direct syscall from
sysdeps/unix/sysv/linux/syscalls.list?

Alistair

>
>
> --
> ldv
Dmitry Levin - Oct. 16, 2019, 6:36 p.m.
On Wed, Oct 16, 2019 at 11:17:47AM -0700, Alistair Francis wrote:
> On Wed, Oct 16, 2019 at 10:35 AM Dmitry V. Levin wrote:
> > On Wed, Oct 16, 2019 at 08:54:08AM -0700, Alistair Francis wrote:
> > > On Sat, Oct 12, 2019 at 5:24 AM Dmitry V. Levin wrote:
> > > > On Wed, Sep 25, 2019 at 03:55:14PM -0700, Alistair Francis wrote:
> > > > > If the waitpid and wait4 syscalls aren't avaliable (such as y2038 safe
> > > > > 32-bit systems) let us use the waitid syscall isntead.
> > > > >
> > > > > Unfortunately waitid is substantially differnt to waitpid and wait4, so
> > > > > the conversion ends up being complex.
> > > > >
> > > > > For full support we need the 5.4+ kernel as that allows a pid of 0 with
> > > > > the P_PGID idtype.
> > > > >
> > > > > 2019-09-16  Alistair Francis  <alistair.francis@wdc.com>
> > > > >
> > > > >       * sysdeps/unix/sysv/linux/wait.c: Use the waitid syscall if required.
> > > > >       * sysdeps/unix/sysv/linux/waitpid.c: Likewise.
> > > > >       * sysdeps/unix/sysv/linux/waitpid_nocancel.c: Likewise.
> > > >
> > > > If wait4 is not available, shouldn't it be emulated as well as waitpid?
> > >
> > > Yes, it is by the changed in wait.c.
> >
> > This change of wait.c affects __libc_wait only, I don't see how it makes
> > wait4 emulated.
> 
> I'm not clear on what you mean. Do you mean the direct syscall from
> sysdeps/unix/sysv/linux/syscalls.list?

Yes, I mean that since wait4(3) cannot be implemented as a direct syscall
on this architecture, this function has to be emulated.

Patch

diff --git a/sysdeps/unix/sysv/linux/wait.c b/sysdeps/unix/sysv/linux/wait.c
index c2385c752e2..28a27af8135 100644
--- a/sysdeps/unix/sysv/linux/wait.c
+++ b/sysdeps/unix/sysv/linux/wait.c
@@ -26,9 +26,44 @@ 
 pid_t
 __libc_wait (int *stat_loc)
 {
-  pid_t result = SYSCALL_CANCEL (wait4, WAIT_ANY, stat_loc, 0,
-				 (struct rusage *) NULL);
-  return result;
+#ifdef __NR_wait4
+  return SYSCALL_CANCEL (wait4, WAIT_ANY, stat_loc, 0,
+                         (struct rusage *) NULL);
+#else
+  siginfo_t infop;
+  __pid_t ret;
+
+  ret = SYSCALL_CANCEL (waitid, P_ALL, 0, &infop, WEXITED, NULL);
+
+  if (ret < 0)
+      return ret;
+
+  if (stat_loc)
+    {
+      *stat_loc = 0;
+      switch (infop.si_code)
+      {
+        case CLD_EXITED:
+            *stat_loc = infop.si_status << 8;
+            break;
+        case CLD_DUMPED:
+            *stat_loc = 0x80;
+            /* Fallthrough */
+        case CLD_KILLED:
+            *stat_loc |= infop.si_status;
+            break;
+        case CLD_TRAPPED:
+        case CLD_STOPPED:
+            *stat_loc = infop.si_status << 8 | 0x7f;
+            break;
+        case CLD_CONTINUED:
+            *stat_loc = 0xffff;
+            break;
+      }
+    }
+
+  return infop.si_pid;
+#endif
 }
 
 weak_alias (__libc_wait, __wait)
diff --git a/sysdeps/unix/sysv/linux/waitpid.c b/sysdeps/unix/sysv/linux/waitpid.c
index d35aac01bcc..a02275c3ff5 100644
--- a/sysdeps/unix/sysv/linux/waitpid.c
+++ b/sysdeps/unix/sysv/linux/waitpid.c
@@ -20,14 +20,71 @@ 
 #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);
-#else
+#elif defined(__NR_wait4)
   return SYSCALL_CANCEL (wait4, pid, stat_loc, options, NULL);
+#else
+  __pid_t ret;
+  idtype_t idtype = P_PID;
+  siginfo_t infop;
+
+  if (pid < -1)
+    {
+      idtype = P_PGID;
+      pid *= -1;
+    }
+  else if (pid == -1)
+    {
+      idtype = P_ALL;
+    }
+  else if (pid == 0)
+    {
+      /* Linux Kernels 5.4+ support pid 0 with P_PGID to specify wait on
+       * the current PID's group. Earlier kernels will return -EINVAL.
+       */
+      idtype = P_PGID;
+    }
+
+  options |= WEXITED;
+
+  ret = SYSCALL_CANCEL (waitid, idtype, pid, &infop, options, NULL);
+
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  if (stat_loc)
+    {
+      *stat_loc = 0;
+      switch (infop.si_code)
+        {
+        case CLD_EXITED:
+            *stat_loc = infop.si_status << 8;
+            break;
+        case CLD_DUMPED:
+            *stat_loc = 0x80;
+            /* Fallthrough */
+        case CLD_KILLED:
+            *stat_loc |= infop.si_status;
+            break;
+        case CLD_TRAPPED:
+        case CLD_STOPPED:
+            *stat_loc = infop.si_status << 8 | 0x7f;
+            break;
+        case CLD_CONTINUED:
+            *stat_loc = 0xffff;
+            break;
+        }
+    }
+
+  return infop.si_pid;
 #endif
 }
 libc_hidden_def (__waitpid)
diff --git a/sysdeps/unix/sysv/linux/waitpid_nocancel.c b/sysdeps/unix/sysv/linux/waitpid_nocancel.c
index 3697c6b938c..59b07c5f73d 100644
--- a/sysdeps/unix/sysv/linux/waitpid_nocancel.c
+++ b/sysdeps/unix/sysv/linux/waitpid_nocancel.c
@@ -27,8 +27,62 @@  __waitpid_nocancel (__pid_t pid, int *stat_loc, int options)
 {
 #ifdef __NR_waitpid
   return INLINE_SYSCALL_CALL (waitpid, pid, stat_loc, options);
-#else
+#elif defined (__NR_wait4)
   return INLINE_SYSCALL_CALL (wait4, pid, stat_loc, options, NULL);
+#else
+  __pid_t ret;
+  idtype_t idtype = P_PID;
+  siginfo_t infop;
+
+  if (pid < -1)
+    {
+      idtype = P_PGID;
+      pid *= -1;
+    }
+  else if (pid == -1)
+    {
+      idtype = P_ALL;
+    }
+  else if (pid == 0)
+    {
+      /* Linux Kernels 5.4+ support pid 0 with P_PGID to specify wait on
+       * the current PID's group. Earlier kernels will return -EINVAL.
+       */
+      idtype = P_PGID;
+    }
+
+  options |= WEXITED;
+
+  ret = INLINE_SYSCALL_CALL (waitid, idtype, pid, &infop, options, NULL);
+
+  if (ret < 0)
+      return ret;
+
+  if (stat_loc)
+    {
+      *stat_loc = 0;
+      switch (infop.si_code)
+        {
+        case CLD_EXITED:
+            *stat_loc = infop.si_status << 8;
+            break;
+        case CLD_DUMPED:
+            *stat_loc = 0x80;
+            /* Fallthrough */
+        case CLD_KILLED:
+            *stat_loc |= infop.si_status;
+            break;
+        case CLD_TRAPPED:
+        case CLD_STOPPED:
+            *stat_loc = infop.si_status << 8 | 0x7f;
+            break;
+        case CLD_CONTINUED:
+            *stat_loc = 0xffff;
+            break;
+        }
+    }
+
+  return infop.si_pid;
 #endif
 }
 libc_hidden_def (__waitpid_nocancel)