summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRich Felker <dalias@aerifal.cx>2019-10-19 21:29:55 -0400
committerRich Felker <dalias@aerifal.cx>2019-10-19 21:29:55 -0400
commit5850546e9669f793aab61dfc7c4f2c1ff35c4b29 (patch)
tree6edcd74d9a2b449fd013692cc5cbf25ae78538b8
parent7e8171143124f7f510db555dc6f6327a965a3e84 (diff)
downloadmusl-5850546e9669f793aab61dfc7c4f2c1ff35c4b29.tar.gz
wait4, getrusage: add time64/x32 variant
presently the kernel does not actually define time64 versions of these syscalls, and they're not really needed except to represent extreme cpu time usage. however, x32's versions of the syscalls already behave as time64 ones, meaning the functions were broken on x32 if the caller used any part of the rusage result other than ru_utime and ru_stime. commit 7e8171143124f7f510db555dc6f6327a965a3e84 made it possible to fix this by treating x32's syscalls as time64 versions. in the non-time64-syscall case, make the syscall with the rusage destination pointer adjusted so that all members but the timevals line up between the libc and kernel structures. on 64-bit archs, or present 32-bit archs with 32-bit time_t, the timevals will line up too and no further work is needed. for future 32-bit archs with 64-bit time_t, the timevals are copied into place, contingent on time_t being larger than long.
-rw-r--r--src/linux/wait4.c34
-rw-r--r--src/misc/getrusage.c30
2 files changed, 61 insertions, 3 deletions
diff --git a/src/linux/wait4.c b/src/linux/wait4.c
index 97f12cc5..83650e34 100644
--- a/src/linux/wait4.c
+++ b/src/linux/wait4.c
@@ -1,9 +1,39 @@
#define _GNU_SOURCE
#include <sys/wait.h>
#include <sys/resource.h>
+#include <string.h>
+#include <errno.h>
#include "syscall.h"
-pid_t wait4(pid_t pid, int *status, int options, struct rusage *usage)
+pid_t wait4(pid_t pid, int *status, int options, struct rusage *ru)
{
- return syscall(SYS_wait4, pid, status, options, usage);
+ int r;
+#ifdef SYS_wait4_time64
+ if (ru) {
+ long long kru64[18];
+ r = __syscall(SYS_wait4_time64, pid, status, options, kru64);
+ if (!r) {
+ ru->ru_utime = (struct timeval)
+ { .tv_sec = kru64[0], .tv_usec = kru64[1] };
+ ru->ru_stime = (struct timeval)
+ { .tv_sec = kru64[2], .tv_usec = kru64[3] };
+ char *slots = (char *)&ru->ru_maxrss;
+ for (int i=0; i<14; i++)
+ *(long *)(slots + i*sizeof(long)) = kru64[4+i];
+ }
+ if (SYS_wait4_time64 == SYS_wait4 || r != -ENOSYS)
+ return __syscall_ret(r);
+ }
+#endif
+ char *dest = ru ? (char *)&ru->ru_maxrss - 4*sizeof(long) : 0;
+ r = __syscall(SYS_wait4, pid, status, options, dest);
+ if (r>0 && ru && sizeof(time_t) > sizeof(long)) {
+ long kru[4];
+ memcpy(kru, dest, 4*sizeof(long));
+ ru->ru_utime = (struct timeval)
+ { .tv_sec = kru[0], .tv_usec = kru[1] };
+ ru->ru_stime = (struct timeval)
+ { .tv_sec = kru[2], .tv_usec = kru[3] };
+ }
+ return __syscall_ret(r);
}
diff --git a/src/misc/getrusage.c b/src/misc/getrusage.c
index 0aaf0ac7..8e03e2e3 100644
--- a/src/misc/getrusage.c
+++ b/src/misc/getrusage.c
@@ -1,7 +1,35 @@
#include <sys/resource.h>
+#include <string.h>
+#include <errno.h>
#include "syscall.h"
int getrusage(int who, struct rusage *ru)
{
- return syscall(SYS_getrusage, who, ru);
+ int r;
+#ifdef SYS_getrusage_time64
+ long long kru64[18];
+ r = __syscall(SYS_getrusage_time64, who, kru64);
+ if (!r) {
+ ru->ru_utime = (struct timeval)
+ { .tv_sec = kru64[0], .tv_usec = kru64[1] };
+ ru->ru_stime = (struct timeval)
+ { .tv_sec = kru64[2], .tv_usec = kru64[3] };
+ char *slots = (char *)&ru->ru_maxrss;
+ for (int i=0; i<14; i++)
+ *(long *)(slots + i*sizeof(long)) = kru64[4+i];
+ }
+ if (SYS_getrusage_time64 == SYS_getrusage || r != -ENOSYS)
+ return __syscall_ret(r);
+#endif
+ char *dest = (char *)&ru->ru_maxrss - 4*sizeof(long);
+ r = __syscall(SYS_getrusage, who, dest);
+ if (!r && sizeof(time_t) > sizeof(long)) {
+ long kru[4];
+ memcpy(kru, dest, 4*sizeof(long));
+ ru->ru_utime = (struct timeval)
+ { .tv_sec = kru[0], .tv_usec = kru[1] };
+ ru->ru_stime = (struct timeval)
+ { .tv_sec = kru[2], .tv_usec = kru[3] };
+ }
+ return __syscall_ret(r);
}