linux: Use long time_t for wait4/getrusage

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>
Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
This commit is contained in:
Alistair Francis 2019-12-23 13:26:50 -08:00
parent 5d24ba82c4
commit 600f00b747
5 changed files with 164 additions and 3 deletions

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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 */

View File

@ -18,13 +18,28 @@
#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)
idtype_t idtype = P_PID;
@ -41,8 +56,19 @@ __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)
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
if (stat_loc)
{
@ -71,7 +97,7 @@ __wait4 (pid_t pid, int *stat_loc, int options, struct rusage *usage)
}
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)