sysdeps/wait: Use the waitid syscall if required

Message ID 20190925225514.7224-1-alistair.francis@wdc.com
State New, archived
Headers

Commit Message

Alistair Francis Sept. 25, 2019, 10:55 p.m. UTC
  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(-)
  

Comments

Dmitry V. Levin Oct. 12, 2019, 12:24 p.m. UTC | #1
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. UTC | #2
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 V. Levin Oct. 16, 2019, 5:35 p.m. UTC | #3
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. UTC | #4
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 V. Levin Oct. 16, 2019, 6:36 p.m. UTC | #5
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.
  
Alistair Francis Oct. 22, 2019, 10:25 p.m. UTC | #6
On Wed, Oct 16, 2019 at 11:36 AM Dmitry V. Levin <ldv@altlinux.org> wrote:
>
> 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.

I'm still a little lost here.

How would I do this? The only option I can see is for RISC-V to have
it's own syscall.list that removes the wait4 call. Is there a better
way to override these?

Alistair

>

>
> --
> ldv
  
Joseph Myers Oct. 22, 2019, 10:38 p.m. UTC | #7
On Tue, 22 Oct 2019, Alistair Francis wrote:

> How would I do this? The only option I can see is for RISC-V to have
> it's own syscall.list that removes the wait4 call. Is there a better
> way to override these?

You could write a wait4.c implementation which overrides the syscalls.list 
entry by being in a sysdeps directory that gets searched earlier (and 
check the build logs to make sure the intended implementation is indeed 
getting built, as it's easy to get sysdeps ordering wrong).  You don't 
need your own syscalls.list.

If this issue applies for all future 32-bit linux/generic architectures, 
the implementation might go in sysdeps/unix/sysv/linux/generic/wordsize-32 
and have #if conditionals allowing it use the wait4 syscall on 
architectures that have it, if doing so is desirable.  It shouldn't go in 
a RISC-V-specific directory unless it's genuinely specific to RISC-V and 
not other future architectures.  Or it could go in 
sysdeps/unix/sysv/linux/wait4.c, with the syscalls.list entry being 
removed.
  
Alistair Francis Oct. 22, 2019, 10:43 p.m. UTC | #8
On Tue, Oct 22, 2019 at 3:39 PM Joseph Myers <joseph@codesourcery.com> wrote:
>
> On Tue, 22 Oct 2019, Alistair Francis wrote:
>
> > How would I do this? The only option I can see is for RISC-V to have
> > it's own syscall.list that removes the wait4 call. Is there a better
> > way to override these?
>
> You could write a wait4.c implementation which overrides the syscalls.list
> entry by being in a sysdeps directory that gets searched earlier (and
> check the build logs to make sure the intended implementation is indeed
> getting built, as it's easy to get sysdeps ordering wrong).  You don't
> need your own syscalls.list.

Ah, that's very helpful.

>
> If this issue applies for all future 32-bit linux/generic architectures,
> the implementation might go in sysdeps/unix/sysv/linux/generic/wordsize-32
> and have #if conditionals allowing it use the wait4 syscall on
> architectures that have it, if doing so is desirable.  It shouldn't go in

Yes, it isn't RISC-V specific, so that makes sense.

> a RISC-V-specific directory unless it's genuinely specific to RISC-V and
> not other future architectures.  Or it could go in
> sysdeps/unix/sysv/linux/wait4.c, with the syscalls.list entry being
> removed.

This seems like the best option to me, as every 32-bit architectures
is one day going to need this and maybe others will as well.

Would adding sysdeps/unix/sysv/linux/wait4.c and removing wait from
syscalls.list be ok with everyone?
Otherwise I'll put it in sysdeps/unix/sysv/linux/generic/wordsize-32/wait4.c.

For the implementation it looks like I can just copy __libc_wait() but
use INLINE_SYSCALL_CALL()'s instead.

Alistair

>
> --
> Joseph S. Myers
> joseph@codesourcery.com
  

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)