[v5,7/8] linux: Use long time_t for wait4/getrusage

Message ID 20200303175355.15770-8-alistair.francis@wdc.com
State New, archived
Headers

Commit Message

Alistair Francis March 3, 2020, 5:53 p.m. UTC
  The Linux kernel expects rusage to use a 32-bit time_t, even on archs
with a 64-bit time_t (like RV32). To address this let's convert
rusage to/from 32-bit and 64-bit to ensure the kernel always gets
a 32-bit time_t.

While we are converting these functions let's also convert them to be
the y2038 safe versions. This means there is a *64 function that is
called by a backwards compatible wrapper.

Reviewed-by: Lukasz Majewski <lukma@denx.de>
---
 include/sys/resource.h                | 11 +++++
 sysdeps/unix/syscalls.list            |  1 -
 sysdeps/unix/sysv/linux/getrusage.c   | 58 +++++++++++++++++++++++++++
 sysdeps/unix/sysv/linux/tv32-compat.h | 47 ++++++++++++++++++++++
 sysdeps/unix/sysv/linux/wait4.c       | 50 ++++++++++++++++++++++-
 5 files changed, 164 insertions(+), 3 deletions(-)
 create mode 100644 sysdeps/unix/sysv/linux/getrusage.c
  

Comments

Adhemerval Zanella March 27, 2020, 6:31 p.m. UTC | #1
On 03/03/2020 14:53, Alistair Francis wrote:
> The Linux kernel expects rusage to use a 32-bit time_t, even on archs
> with a 64-bit time_t (like RV32). To address this let's convert
> rusage to/from 32-bit and 64-bit to ensure the kernel always gets
> a 32-bit time_t.
> 
> While we are converting these functions let's also convert them to be
> the y2038 safe versions. This means there is a *64 function that is
> called by a backwards compatible wrapper.
> 
> Reviewed-by: Lukasz Majewski <lukma@denx.de>
> ---
>  include/sys/resource.h                | 11 +++++
>  sysdeps/unix/syscalls.list            |  1 -
>  sysdeps/unix/sysv/linux/getrusage.c   | 58 +++++++++++++++++++++++++++
>  sysdeps/unix/sysv/linux/tv32-compat.h | 47 ++++++++++++++++++++++
>  sysdeps/unix/sysv/linux/wait4.c       | 50 ++++++++++++++++++++++-
>  5 files changed, 164 insertions(+), 3 deletions(-)
>  create mode 100644 sysdeps/unix/sysv/linux/getrusage.c
> 
> diff --git a/include/sys/resource.h b/include/sys/resource.h
> index 9d604dfe3e..64925f257c 100644
> --- a/include/sys/resource.h
> +++ b/include/sys/resource.h
> @@ -134,5 +134,16 @@ extern int __getrusage (enum __rusage_who __who, struct rusage *__usage)
>  extern int __setrlimit (enum __rlimit_resource __resource,
>  			const struct rlimit *__rlimits);
>  libc_hidden_proto (__setrlimit);
> +
> +#if __TIMESIZE == 64
> +# define __getrusage64 __getrusage
> +# define __wait4_time64 __wait4
> +#else
> +extern int __getrusage64 (enum __rusage_who who, struct __rusage64 *usage);
> +libc_hidden_proto (__getrusage64)
> +extern pid_t __wait4_time64 (pid_t pid, int *stat_loc, int options,
> +                             struct __rusage64 *usage);
> +libc_hidden_proto (__wait4_time64)
> +#endif
>  #endif
>  #endif

Ok.

> diff --git a/sysdeps/unix/syscalls.list b/sysdeps/unix/syscalls.list
> index d249049d6e..01c4a0e6b1 100644
> --- a/sysdeps/unix/syscalls.list
> +++ b/sysdeps/unix/syscalls.list
> @@ -29,7 +29,6 @@ getpeername	-	getpeername	i:ibN	__getpeername	getpeername
>  getpid		-	getpid		Ei:	__getpid	getpid
>  getpriority	-	getpriority	i:ii	__getpriority	getpriority
>  getrlimit	-	getrlimit	i:ip	__getrlimit	getrlimit
> -getrusage	-	getrusage	i:ip	__getrusage	getrusage
>  getsockname	-	getsockname	i:ibN	__getsockname	getsockname
>  getsockopt	-	getsockopt	i:iiiBN	getsockopt
>  getuid		-	getuid		Ei:	__getuid	getuid

Ok.

> diff --git a/sysdeps/unix/sysv/linux/getrusage.c b/sysdeps/unix/sysv/linux/getrusage.c
> new file mode 100644
> index 0000000000..a4e382ed53
> --- /dev/null
> +++ b/sysdeps/unix/sysv/linux/getrusage.c
> @@ -0,0 +1,58 @@
> +/* getrusage -- get the rusage struct.  Linux version.
> +   Copyright (C) 2020 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   The GNU C Library is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library; if not, see
> +   <http://www.gnu.org/licenses/>.  */
> +
> +#include <sys/time.h>
> +#include <sys/resource.h>
> +#include <sys/types.h>
> +#include <sysdep.h>
> +#include <tv32-compat.h>
> +
> +int
> +__getrusage64 (enum __rusage_who who, struct __rusage64 *usage)
> +{
> +#if __KERNEL_OLD_TIMEVAL_MATCHES_TIMEVAL64
> +  return INLINE_SYSCALL_CALL (getrusage, who, usage);
> +#else
> +  struct __rusage32 usage32;
> +  if (INLINE_SYSCALL_CALL (getrusage, who, &usage32) == -1)
> +    return -1;
> +
> +  rusage32_to_rusage64 (&usage32, usage);
> +  return 0;
> +#endif
> +}
> +

Ok.

> +#if __TIMESIZE != 64
> +libc_hidden_def (__getrusage64)
> +int
> +__getrusage (enum __rusage_who who, struct rusage *usage)
> +{
> +  int ret ;
> +  struct __rusage64 usage64;
> +
> +  ret = __getrusage64 (who, &usage64);
> +
> +  if (ret != 0)
> +    return ret;
> +
> +  rusage64_to_rusage (&usage64, usage);
> +
> +  return ret;
> +}
> +#endif
> +weak_alias (__getrusage, getrusage)

Ok.

> diff --git a/sysdeps/unix/sysv/linux/tv32-compat.h b/sysdeps/unix/sysv/linux/tv32-compat.h
> index b8791b1db8..1ada1f729c 100644
> --- a/sysdeps/unix/sysv/linux/tv32-compat.h
> +++ b/sysdeps/unix/sysv/linux/tv32-compat.h
> @@ -20,6 +20,7 @@
>  #define _TV32_COMPAT_H 1
>  
>  #include <bits/types/time_t.h>
> +#include <sys/resource.h>
>  
>  /* Structures containing 'struct timeval' with 32-bit time_t.  */
>  struct __itimerval32
> @@ -28,4 +29,50 @@ struct __itimerval32
>    struct __timeval32 it_value;
>  };
>  
> +struct __rusage32
> +{
> +  struct __timeval32 ru_utime;	/* user time used */
> +  struct __timeval32 ru_stime;	/* system time used */
> +  long ru_maxrss;		/* maximum resident set size */
> +  long ru_ixrss;		/* integral shared memory size */
> +  long ru_idrss;		/* integral unshared data size */
> +  long ru_isrss;		/* integral unshared stack size */
> +  long ru_minflt;		/* page reclaims */
> +  long ru_majflt;		/* page faults */
> +  long ru_nswap;		/* swaps */
> +  long ru_inblock;		/* block input operations */
> +  long ru_oublock;		/* block output operations */
> +  long ru_msgsnd;		/* messages sent */
> +  long ru_msgrcv;		/* messages received */
> +  long ru_nsignals;		/* signals received */
> +  long ru_nvcsw;		/* voluntary context switches */
> +  long ru_nivcsw;		/* involuntary " */
> +};
> +
> +static inline void
> +rusage32_to_rusage64 (const struct __rusage32 *restrict r32,
> +                    struct __rusage64 *restrict r64)
> +{
> +  /* Make sure the entire output structure is cleared, including
> +     padding and reserved fields.  */
> +  memset (r64, 0, sizeof *r64);
> +
> +  r64->ru_utime    = valid_timeval32_to_timeval64 (r32->ru_utime);
> +  r64->ru_stime    = valid_timeval32_to_timeval64 (r32->ru_stime);
> +  r64->ru_maxrss   = r32->ru_maxrss;
> +  r64->ru_ixrss    = r32->ru_ixrss;
> +  r64->ru_idrss    = r32->ru_idrss;
> +  r64->ru_isrss    = r32->ru_isrss;
> +  r64->ru_minflt   = r32->ru_minflt;
> +  r64->ru_majflt   = r32->ru_majflt;
> +  r64->ru_nswap    = r32->ru_nswap;
> +  r64->ru_inblock  = r32->ru_inblock;
> +  r64->ru_oublock  = r32->ru_oublock;
> +  r64->ru_msgsnd   = r32->ru_msgsnd;
> +  r64->ru_msgrcv   = r32->ru_msgrcv;
> +  r64->ru_nsignals = r32->ru_nsignals;
> +  r64->ru_nvcsw    = r32->ru_nvcsw;
> +  r64->ru_nivcsw   = r32->ru_nivcsw;
> +}
> +
>  #endif /* tv32-compat.h */

Ok.

> diff --git a/sysdeps/unix/sysv/linux/wait4.c b/sysdeps/unix/sysv/linux/wait4.c
> index 3a8bed1169..da591da4d4 100644
> --- a/sysdeps/unix/sysv/linux/wait4.c
> +++ b/sysdeps/unix/sysv/linux/wait4.c
> @@ -18,14 +18,30 @@
>  
>  #include <sys/wait.h>
>  #include <sys/resource.h>
> +#include <sys/types.h>
>  #include <sysdep-cancel.h>
> +#include <tv32-compat.h>
>  
>  pid_t
> -__wait4 (pid_t pid, int *stat_loc, int options, struct rusage *usage)
> +__wait4_time64 (pid_t pid, int *stat_loc, int options, struct __rusage64 *usage)
>  {
>  #ifdef __NR_wait4
> +# if __KERNEL_OLD_TIMEVAL_MATCHES_TIMEVAL64
>    return SYSCALL_CANCEL (wait4, pid, stat_loc, options, usage);
> +# else
> +  struct __rusage32 usage32;
> +  pid_t ret = SYSCALL_CANCEL (wait4, pid, stat_loc, options, &usage32);
> +
> +  if (ret != 0)
> +    return ret;
> +
> +  if (usage != NULL)
> +      rusage32_to_rusage64 (&usage32, usage);

Indentation seems wrong.

> +
> +  return ret;
> +# endif
>  #elif defined (__ASSUME_WAITID_PID0_P_PGID)
> +  struct __rusage32 usage32;
>    idtype_t idtype = P_PID;
>  
>    if (pid < -1)
> @@ -41,7 +57,12 @@ __wait4 (pid_t pid, int *stat_loc, int options, struct rusage *usage)
>    options |= WEXITED;
>  
>    siginfo_t infop;
> +
> +# if __KERNEL_OLD_TIMEVAL_MATCHES_TIMEVAL64
>    if (SYSCALL_CANCEL (waitid, idtype, pid, &infop, options, usage) < 0)
> +# else
> +  if (SYSCALL_CANCEL (waitid, idtype, pid, &infop, options, &usage32) < 0)
> +# endif
>      return -1;
>  
>    if (stat_loc)
> @@ -70,8 +91,13 @@ __wait4 (pid_t pid, int *stat_loc, int options, struct rusage *usage)
>          }
>      }
>  
> +# if __KERNEL_OLD_TIMEVAL_MATCHES_TIMEVAL64 == 0
> +  if (usage != NULL)
> +      rusage32_to_rusage64 (&usage32, usage);
> +# endif

I think compiler will start to emit an unused variable warning if this
code is being used with an 64 bit architecture that only supports
waitid (which seems to be idea for new generic on Linux).

So I think it should be:

  # if __KERNEL_OLD_TIMEVAL_MATCHES_TIMEVAL64
    if (SYSCALL_CANCEL (waitid, idtype, pid, &infop, options, usage) < 0)
      return -1;
  # else
    {
      struct __rusage32 usage32;
      if (SYSCALL_CANCEL (waitid, idtype, pid, &infop, options, &usage32) < 0)
        return -1;
      if (usage != NULL)
        rusage32_to_rusage64 (&usage32, usage);
    }
  # endif

> +
>    return infop.si_pid;
> -# else
> +#else
>  /* Linux waitid prior kernel 5.4 does not support waiting for the current
>     process.  It is possible to emulate wait4 it by calling getpgid for
>     PID 0, however, it would require an additional syscall and it is inherent
> @@ -81,5 +107,25 @@ __wait4 (pid_t pid, int *stat_loc, int options, struct rusage *usage)
>  # error "The kernel ABI does not provide a way to implement wait4"
>  #endif
>  }
> +
> +#if __TIMESIZE != 64
> +libc_hidden_def (__wait4_time64)
> +
> +pid_t
> +__wait4 (pid_t pid, int *stat_loc, int options, struct rusage *usage)
> +{
> +  pid_t ret ;
> +  struct __rusage64 usage64;
> +
> +  ret = __wait4_time64 (pid, stat_loc, options, &usage64);
> +
> +  if (ret != 0)
> +    return ret;
> +
> +  rusage64_to_rusage (&usage64, usage);
> +
> +  return ret;
> +}
> +#endif
>  libc_hidden_def (__wait4);
>  weak_alias (__wait4, wait4)
> 

Ok.
  
Alistair Francis March 27, 2020, 6:42 p.m. UTC | #2
On Fri, Mar 27, 2020 at 11:32 AM Adhemerval Zanella via Libc-alpha
<libc-alpha@sourceware.org> wrote:
>
>
>
> On 03/03/2020 14:53, Alistair Francis wrote:
> > The Linux kernel expects rusage to use a 32-bit time_t, even on archs
> > with a 64-bit time_t (like RV32). To address this let's convert
> > rusage to/from 32-bit and 64-bit to ensure the kernel always gets
> > a 32-bit time_t.
> >
> > While we are converting these functions let's also convert them to be
> > the y2038 safe versions. This means there is a *64 function that is
> > called by a backwards compatible wrapper.
> >
> > Reviewed-by: Lukasz Majewski <lukma@denx.de>
> > ---
> >  include/sys/resource.h                | 11 +++++
> >  sysdeps/unix/syscalls.list            |  1 -
> >  sysdeps/unix/sysv/linux/getrusage.c   | 58 +++++++++++++++++++++++++++
> >  sysdeps/unix/sysv/linux/tv32-compat.h | 47 ++++++++++++++++++++++
> >  sysdeps/unix/sysv/linux/wait4.c       | 50 ++++++++++++++++++++++-
> >  5 files changed, 164 insertions(+), 3 deletions(-)
> >  create mode 100644 sysdeps/unix/sysv/linux/getrusage.c
> >
> > diff --git a/include/sys/resource.h b/include/sys/resource.h
> > index 9d604dfe3e..64925f257c 100644
> > --- a/include/sys/resource.h
> > +++ b/include/sys/resource.h
> > @@ -134,5 +134,16 @@ extern int __getrusage (enum __rusage_who __who, struct rusage *__usage)
> >  extern int __setrlimit (enum __rlimit_resource __resource,
> >                       const struct rlimit *__rlimits);
> >  libc_hidden_proto (__setrlimit);
> > +
> > +#if __TIMESIZE == 64
> > +# define __getrusage64 __getrusage
> > +# define __wait4_time64 __wait4
> > +#else
> > +extern int __getrusage64 (enum __rusage_who who, struct __rusage64 *usage);
> > +libc_hidden_proto (__getrusage64)
> > +extern pid_t __wait4_time64 (pid_t pid, int *stat_loc, int options,
> > +                             struct __rusage64 *usage);
> > +libc_hidden_proto (__wait4_time64)
> > +#endif
> >  #endif
> >  #endif
>
> Ok.
>
> > diff --git a/sysdeps/unix/syscalls.list b/sysdeps/unix/syscalls.list
> > index d249049d6e..01c4a0e6b1 100644
> > --- a/sysdeps/unix/syscalls.list
> > +++ b/sysdeps/unix/syscalls.list
> > @@ -29,7 +29,6 @@ getpeername -       getpeername     i:ibN   __getpeername   getpeername
> >  getpid               -       getpid          Ei:     __getpid        getpid
> >  getpriority  -       getpriority     i:ii    __getpriority   getpriority
> >  getrlimit    -       getrlimit       i:ip    __getrlimit     getrlimit
> > -getrusage    -       getrusage       i:ip    __getrusage     getrusage
> >  getsockname  -       getsockname     i:ibN   __getsockname   getsockname
> >  getsockopt   -       getsockopt      i:iiiBN getsockopt
> >  getuid               -       getuid          Ei:     __getuid        getuid
>
> Ok.
>
> > diff --git a/sysdeps/unix/sysv/linux/getrusage.c b/sysdeps/unix/sysv/linux/getrusage.c
> > new file mode 100644
> > index 0000000000..a4e382ed53
> > --- /dev/null
> > +++ b/sysdeps/unix/sysv/linux/getrusage.c
> > @@ -0,0 +1,58 @@
> > +/* getrusage -- get the rusage struct.  Linux version.
> > +   Copyright (C) 2020 Free Software Foundation, Inc.
> > +   This file is part of the GNU C Library.
> > +
> > +   The GNU C Library is free software; you can redistribute it and/or
> > +   modify it under the terms of the GNU Lesser General Public
> > +   License as published by the Free Software Foundation; either
> > +   version 2.1 of the License, or (at your option) any later version.
> > +
> > +   The GNU C Library is distributed in the hope that it will be useful,
> > +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> > +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> > +   Lesser General Public License for more details.
> > +
> > +   You should have received a copy of the GNU Lesser General Public
> > +   License along with the GNU C Library; if not, see
> > +   <http://www.gnu.org/licenses/>.  */
> > +
> > +#include <sys/time.h>
> > +#include <sys/resource.h>
> > +#include <sys/types.h>
> > +#include <sysdep.h>
> > +#include <tv32-compat.h>
> > +
> > +int
> > +__getrusage64 (enum __rusage_who who, struct __rusage64 *usage)
> > +{
> > +#if __KERNEL_OLD_TIMEVAL_MATCHES_TIMEVAL64
> > +  return INLINE_SYSCALL_CALL (getrusage, who, usage);
> > +#else
> > +  struct __rusage32 usage32;
> > +  if (INLINE_SYSCALL_CALL (getrusage, who, &usage32) == -1)
> > +    return -1;
> > +
> > +  rusage32_to_rusage64 (&usage32, usage);
> > +  return 0;
> > +#endif
> > +}
> > +
>
> Ok.
>
> > +#if __TIMESIZE != 64
> > +libc_hidden_def (__getrusage64)
> > +int
> > +__getrusage (enum __rusage_who who, struct rusage *usage)
> > +{
> > +  int ret ;
> > +  struct __rusage64 usage64;
> > +
> > +  ret = __getrusage64 (who, &usage64);
> > +
> > +  if (ret != 0)
> > +    return ret;
> > +
> > +  rusage64_to_rusage (&usage64, usage);
> > +
> > +  return ret;
> > +}
> > +#endif
> > +weak_alias (__getrusage, getrusage)
>
> Ok.
>
> > diff --git a/sysdeps/unix/sysv/linux/tv32-compat.h b/sysdeps/unix/sysv/linux/tv32-compat.h
> > index b8791b1db8..1ada1f729c 100644
> > --- a/sysdeps/unix/sysv/linux/tv32-compat.h
> > +++ b/sysdeps/unix/sysv/linux/tv32-compat.h
> > @@ -20,6 +20,7 @@
> >  #define _TV32_COMPAT_H 1
> >
> >  #include <bits/types/time_t.h>
> > +#include <sys/resource.h>
> >
> >  /* Structures containing 'struct timeval' with 32-bit time_t.  */
> >  struct __itimerval32
> > @@ -28,4 +29,50 @@ struct __itimerval32
> >    struct __timeval32 it_value;
> >  };
> >
> > +struct __rusage32
> > +{
> > +  struct __timeval32 ru_utime;       /* user time used */
> > +  struct __timeval32 ru_stime;       /* system time used */
> > +  long ru_maxrss;            /* maximum resident set size */
> > +  long ru_ixrss;             /* integral shared memory size */
> > +  long ru_idrss;             /* integral unshared data size */
> > +  long ru_isrss;             /* integral unshared stack size */
> > +  long ru_minflt;            /* page reclaims */
> > +  long ru_majflt;            /* page faults */
> > +  long ru_nswap;             /* swaps */
> > +  long ru_inblock;           /* block input operations */
> > +  long ru_oublock;           /* block output operations */
> > +  long ru_msgsnd;            /* messages sent */
> > +  long ru_msgrcv;            /* messages received */
> > +  long ru_nsignals;          /* signals received */
> > +  long ru_nvcsw;             /* voluntary context switches */
> > +  long ru_nivcsw;            /* involuntary " */
> > +};
> > +
> > +static inline void
> > +rusage32_to_rusage64 (const struct __rusage32 *restrict r32,
> > +                    struct __rusage64 *restrict r64)
> > +{
> > +  /* Make sure the entire output structure is cleared, including
> > +     padding and reserved fields.  */
> > +  memset (r64, 0, sizeof *r64);
> > +
> > +  r64->ru_utime    = valid_timeval32_to_timeval64 (r32->ru_utime);
> > +  r64->ru_stime    = valid_timeval32_to_timeval64 (r32->ru_stime);
> > +  r64->ru_maxrss   = r32->ru_maxrss;
> > +  r64->ru_ixrss    = r32->ru_ixrss;
> > +  r64->ru_idrss    = r32->ru_idrss;
> > +  r64->ru_isrss    = r32->ru_isrss;
> > +  r64->ru_minflt   = r32->ru_minflt;
> > +  r64->ru_majflt   = r32->ru_majflt;
> > +  r64->ru_nswap    = r32->ru_nswap;
> > +  r64->ru_inblock  = r32->ru_inblock;
> > +  r64->ru_oublock  = r32->ru_oublock;
> > +  r64->ru_msgsnd   = r32->ru_msgsnd;
> > +  r64->ru_msgrcv   = r32->ru_msgrcv;
> > +  r64->ru_nsignals = r32->ru_nsignals;
> > +  r64->ru_nvcsw    = r32->ru_nvcsw;
> > +  r64->ru_nivcsw   = r32->ru_nivcsw;
> > +}
> > +
> >  #endif /* tv32-compat.h */
>
> Ok.
>
> > diff --git a/sysdeps/unix/sysv/linux/wait4.c b/sysdeps/unix/sysv/linux/wait4.c
> > index 3a8bed1169..da591da4d4 100644
> > --- a/sysdeps/unix/sysv/linux/wait4.c
> > +++ b/sysdeps/unix/sysv/linux/wait4.c
> > @@ -18,14 +18,30 @@
> >
> >  #include <sys/wait.h>
> >  #include <sys/resource.h>
> > +#include <sys/types.h>
> >  #include <sysdep-cancel.h>
> > +#include <tv32-compat.h>
> >
> >  pid_t
> > -__wait4 (pid_t pid, int *stat_loc, int options, struct rusage *usage)
> > +__wait4_time64 (pid_t pid, int *stat_loc, int options, struct __rusage64 *usage)
> >  {
> >  #ifdef __NR_wait4
> > +# if __KERNEL_OLD_TIMEVAL_MATCHES_TIMEVAL64
> >    return SYSCALL_CANCEL (wait4, pid, stat_loc, options, usage);
> > +# else
> > +  struct __rusage32 usage32;
> > +  pid_t ret = SYSCALL_CANCEL (wait4, pid, stat_loc, options, &usage32);
> > +
> > +  if (ret != 0)
> > +    return ret;
> > +
> > +  if (usage != NULL)
> > +      rusage32_to_rusage64 (&usage32, usage);
>
> Indentation seems wrong.

Fixed.

>
> > +
> > +  return ret;
> > +# endif
> >  #elif defined (__ASSUME_WAITID_PID0_P_PGID)
> > +  struct __rusage32 usage32;
> >    idtype_t idtype = P_PID;
> >
> >    if (pid < -1)
> > @@ -41,7 +57,12 @@ __wait4 (pid_t pid, int *stat_loc, int options, struct rusage *usage)
> >    options |= WEXITED;
> >
> >    siginfo_t infop;
> > +
> > +# if __KERNEL_OLD_TIMEVAL_MATCHES_TIMEVAL64
> >    if (SYSCALL_CANCEL (waitid, idtype, pid, &infop, options, usage) < 0)
> > +# else
> > +  if (SYSCALL_CANCEL (waitid, idtype, pid, &infop, options, &usage32) < 0)
> > +# endif
> >      return -1;
> >
> >    if (stat_loc)
> > @@ -70,8 +91,13 @@ __wait4 (pid_t pid, int *stat_loc, int options, struct rusage *usage)
> >          }
> >      }
> >
> > +# if __KERNEL_OLD_TIMEVAL_MATCHES_TIMEVAL64 == 0
> > +  if (usage != NULL)
> > +      rusage32_to_rusage64 (&usage32, usage);
> > +# endif
>
> I think compiler will start to emit an unused variable warning if this
> code is being used with an 64 bit architecture that only supports
> waitid (which seems to be idea for new generic on Linux).
>
> So I think it should be:
>
>   # if __KERNEL_OLD_TIMEVAL_MATCHES_TIMEVAL64
>     if (SYSCALL_CANCEL (waitid, idtype, pid, &infop, options, usage) < 0)
>       return -1;
>   # else
>     {
>       struct __rusage32 usage32;
>       if (SYSCALL_CANCEL (waitid, idtype, pid, &infop, options, &usage32) < 0)
>         return -1;
>       if (usage != NULL)
>         rusage32_to_rusage64 (&usage32, usage);
>     }
>   # endif

Good point, I have fixed this.

Alistair

>
> > +
> >    return infop.si_pid;
> > -# else
> > +#else
> >  /* Linux waitid prior kernel 5.4 does not support waiting for the current
> >     process.  It is possible to emulate wait4 it by calling getpgid for
> >     PID 0, however, it would require an additional syscall and it is inherent
> > @@ -81,5 +107,25 @@ __wait4 (pid_t pid, int *stat_loc, int options, struct rusage *usage)
> >  # error "The kernel ABI does not provide a way to implement wait4"
> >  #endif
> >  }
> > +
> > +#if __TIMESIZE != 64
> > +libc_hidden_def (__wait4_time64)
> > +
> > +pid_t
> > +__wait4 (pid_t pid, int *stat_loc, int options, struct rusage *usage)
> > +{
> > +  pid_t ret ;
> > +  struct __rusage64 usage64;
> > +
> > +  ret = __wait4_time64 (pid, stat_loc, options, &usage64);
> > +
> > +  if (ret != 0)
> > +    return ret;
> > +
> > +  rusage64_to_rusage (&usage64, usage);
> > +
> > +  return ret;
> > +}
> > +#endif
> >  libc_hidden_def (__wait4);
> >  weak_alias (__wait4, wait4)
> >
>
> Ok.
  
Andreas Schwab April 4, 2020, 2:52 p.m. UTC | #3
On Mär 03 2020, Alistair Francis wrote:

> +#if __TIMESIZE != 64
> +libc_hidden_def (__wait4_time64)
> +
> +pid_t
> +__wait4 (pid_t pid, int *stat_loc, int options, struct rusage *usage)
> +{
> +  pid_t ret ;
> +  struct __rusage64 usage64;
> +
> +  ret = __wait4_time64 (pid, stat_loc, options, &usage64);
> +
> +  if (ret != 0)
> +    return ret;
> +
> +  rusage64_to_rusage (&usage64, usage);

usage can be NULL.

Andreas.
  

Patch

diff --git a/include/sys/resource.h b/include/sys/resource.h
index 9d604dfe3e..64925f257c 100644
--- a/include/sys/resource.h
+++ b/include/sys/resource.h
@@ -134,5 +134,16 @@  extern int __getrusage (enum __rusage_who __who, struct rusage *__usage)
 extern int __setrlimit (enum __rlimit_resource __resource,
 			const struct rlimit *__rlimits);
 libc_hidden_proto (__setrlimit);
+
+#if __TIMESIZE == 64
+# define __getrusage64 __getrusage
+# define __wait4_time64 __wait4
+#else
+extern int __getrusage64 (enum __rusage_who who, struct __rusage64 *usage);
+libc_hidden_proto (__getrusage64)
+extern pid_t __wait4_time64 (pid_t pid, int *stat_loc, int options,
+                             struct __rusage64 *usage);
+libc_hidden_proto (__wait4_time64)
+#endif
 #endif
 #endif
diff --git a/sysdeps/unix/syscalls.list b/sysdeps/unix/syscalls.list
index d249049d6e..01c4a0e6b1 100644
--- a/sysdeps/unix/syscalls.list
+++ b/sysdeps/unix/syscalls.list
@@ -29,7 +29,6 @@  getpeername	-	getpeername	i:ibN	__getpeername	getpeername
 getpid		-	getpid		Ei:	__getpid	getpid
 getpriority	-	getpriority	i:ii	__getpriority	getpriority
 getrlimit	-	getrlimit	i:ip	__getrlimit	getrlimit
-getrusage	-	getrusage	i:ip	__getrusage	getrusage
 getsockname	-	getsockname	i:ibN	__getsockname	getsockname
 getsockopt	-	getsockopt	i:iiiBN	getsockopt
 getuid		-	getuid		Ei:	__getuid	getuid
diff --git a/sysdeps/unix/sysv/linux/getrusage.c b/sysdeps/unix/sysv/linux/getrusage.c
new file mode 100644
index 0000000000..a4e382ed53
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/getrusage.c
@@ -0,0 +1,58 @@ 
+/* getrusage -- get the rusage struct.  Linux version.
+   Copyright (C) 2020 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/types.h>
+#include <sysdep.h>
+#include <tv32-compat.h>
+
+int
+__getrusage64 (enum __rusage_who who, struct __rusage64 *usage)
+{
+#if __KERNEL_OLD_TIMEVAL_MATCHES_TIMEVAL64
+  return INLINE_SYSCALL_CALL (getrusage, who, usage);
+#else
+  struct __rusage32 usage32;
+  if (INLINE_SYSCALL_CALL (getrusage, who, &usage32) == -1)
+    return -1;
+
+  rusage32_to_rusage64 (&usage32, usage);
+  return 0;
+#endif
+}
+
+#if __TIMESIZE != 64
+libc_hidden_def (__getrusage64)
+int
+__getrusage (enum __rusage_who who, struct rusage *usage)
+{
+  int ret ;
+  struct __rusage64 usage64;
+
+  ret = __getrusage64 (who, &usage64);
+
+  if (ret != 0)
+    return ret;
+
+  rusage64_to_rusage (&usage64, usage);
+
+  return ret;
+}
+#endif
+weak_alias (__getrusage, getrusage)
diff --git a/sysdeps/unix/sysv/linux/tv32-compat.h b/sysdeps/unix/sysv/linux/tv32-compat.h
index b8791b1db8..1ada1f729c 100644
--- a/sysdeps/unix/sysv/linux/tv32-compat.h
+++ b/sysdeps/unix/sysv/linux/tv32-compat.h
@@ -20,6 +20,7 @@ 
 #define _TV32_COMPAT_H 1
 
 #include <bits/types/time_t.h>
+#include <sys/resource.h>
 
 /* Structures containing 'struct timeval' with 32-bit time_t.  */
 struct __itimerval32
@@ -28,4 +29,50 @@  struct __itimerval32
   struct __timeval32 it_value;
 };
 
+struct __rusage32
+{
+  struct __timeval32 ru_utime;	/* user time used */
+  struct __timeval32 ru_stime;	/* system time used */
+  long ru_maxrss;		/* maximum resident set size */
+  long ru_ixrss;		/* integral shared memory size */
+  long ru_idrss;		/* integral unshared data size */
+  long ru_isrss;		/* integral unshared stack size */
+  long ru_minflt;		/* page reclaims */
+  long ru_majflt;		/* page faults */
+  long ru_nswap;		/* swaps */
+  long ru_inblock;		/* block input operations */
+  long ru_oublock;		/* block output operations */
+  long ru_msgsnd;		/* messages sent */
+  long ru_msgrcv;		/* messages received */
+  long ru_nsignals;		/* signals received */
+  long ru_nvcsw;		/* voluntary context switches */
+  long ru_nivcsw;		/* involuntary " */
+};
+
+static inline void
+rusage32_to_rusage64 (const struct __rusage32 *restrict r32,
+                    struct __rusage64 *restrict r64)
+{
+  /* Make sure the entire output structure is cleared, including
+     padding and reserved fields.  */
+  memset (r64, 0, sizeof *r64);
+
+  r64->ru_utime    = valid_timeval32_to_timeval64 (r32->ru_utime);
+  r64->ru_stime    = valid_timeval32_to_timeval64 (r32->ru_stime);
+  r64->ru_maxrss   = r32->ru_maxrss;
+  r64->ru_ixrss    = r32->ru_ixrss;
+  r64->ru_idrss    = r32->ru_idrss;
+  r64->ru_isrss    = r32->ru_isrss;
+  r64->ru_minflt   = r32->ru_minflt;
+  r64->ru_majflt   = r32->ru_majflt;
+  r64->ru_nswap    = r32->ru_nswap;
+  r64->ru_inblock  = r32->ru_inblock;
+  r64->ru_oublock  = r32->ru_oublock;
+  r64->ru_msgsnd   = r32->ru_msgsnd;
+  r64->ru_msgrcv   = r32->ru_msgrcv;
+  r64->ru_nsignals = r32->ru_nsignals;
+  r64->ru_nvcsw    = r32->ru_nvcsw;
+  r64->ru_nivcsw   = r32->ru_nivcsw;
+}
+
 #endif /* tv32-compat.h */
diff --git a/sysdeps/unix/sysv/linux/wait4.c b/sysdeps/unix/sysv/linux/wait4.c
index 3a8bed1169..da591da4d4 100644
--- a/sysdeps/unix/sysv/linux/wait4.c
+++ b/sysdeps/unix/sysv/linux/wait4.c
@@ -18,14 +18,30 @@ 
 
 #include <sys/wait.h>
 #include <sys/resource.h>
+#include <sys/types.h>
 #include <sysdep-cancel.h>
+#include <tv32-compat.h>
 
 pid_t
-__wait4 (pid_t pid, int *stat_loc, int options, struct rusage *usage)
+__wait4_time64 (pid_t pid, int *stat_loc, int options, struct __rusage64 *usage)
 {
 #ifdef __NR_wait4
+# if __KERNEL_OLD_TIMEVAL_MATCHES_TIMEVAL64
   return SYSCALL_CANCEL (wait4, pid, stat_loc, options, usage);
+# else
+  struct __rusage32 usage32;
+  pid_t ret = SYSCALL_CANCEL (wait4, pid, stat_loc, options, &usage32);
+
+  if (ret != 0)
+    return ret;
+
+  if (usage != NULL)
+      rusage32_to_rusage64 (&usage32, usage);
+
+  return ret;
+# endif
 #elif defined (__ASSUME_WAITID_PID0_P_PGID)
+  struct __rusage32 usage32;
   idtype_t idtype = P_PID;
 
   if (pid < -1)
@@ -41,7 +57,12 @@  __wait4 (pid_t pid, int *stat_loc, int options, struct rusage *usage)
   options |= WEXITED;
 
   siginfo_t infop;
+
+# if __KERNEL_OLD_TIMEVAL_MATCHES_TIMEVAL64
   if (SYSCALL_CANCEL (waitid, idtype, pid, &infop, options, usage) < 0)
+# else
+  if (SYSCALL_CANCEL (waitid, idtype, pid, &infop, options, &usage32) < 0)
+# endif
     return -1;
 
   if (stat_loc)
@@ -70,8 +91,13 @@  __wait4 (pid_t pid, int *stat_loc, int options, struct rusage *usage)
         }
     }
 
+# if __KERNEL_OLD_TIMEVAL_MATCHES_TIMEVAL64 == 0
+  if (usage != NULL)
+      rusage32_to_rusage64 (&usage32, usage);
+# endif
+
   return infop.si_pid;
-# else
+#else
 /* Linux waitid prior kernel 5.4 does not support waiting for the current
    process.  It is possible to emulate wait4 it by calling getpgid for
    PID 0, however, it would require an additional syscall and it is inherent
@@ -81,5 +107,25 @@  __wait4 (pid_t pid, int *stat_loc, int options, struct rusage *usage)
 # error "The kernel ABI does not provide a way to implement wait4"
 #endif
 }
+
+#if __TIMESIZE != 64
+libc_hidden_def (__wait4_time64)
+
+pid_t
+__wait4 (pid_t pid, int *stat_loc, int options, struct rusage *usage)
+{
+  pid_t ret ;
+  struct __rusage64 usage64;
+
+  ret = __wait4_time64 (pid, stat_loc, options, &usage64);
+
+  if (ret != 0)
+    return ret;
+
+  rusage64_to_rusage (&usage64, usage);
+
+  return ret;
+}
+#endif
 libc_hidden_def (__wait4);
 weak_alias (__wait4, wait4)