From 9ca6f23f7fcb6a387a394bc09a2aad1971b27857 Mon Sep 17 00:00:00 2001 From: Stefan O'Rear Date: Thu, 3 Sep 2020 05:20:45 -0400 Subject: [PATCH 07/14] Emulate wait4 using waitid riscv32 and future architectures lack wait4. waitpid is required by POSIX to be a cancellation point. pclose is specified as undefined if a cancellation occurs, so it would be permitted for it to call a cancellable wait function; however, as a quality of implementation matter, pclose must close the pipe fd before it can wait (consider popen("yes","r")) and if the wait could be interrupted the pipe FILE would be left in an intermediate state that portable software cannot recover from, so the only useful behavior is for pclose to NOT be a cancellation point. We therefore support both at a small cost in code size. wait4 is historically not a cancellation point in musl; we retain that since we need the non-cancellable version of __wait4 anyway. --- src/internal/__wait4.c | 55 ++++++++++++++++++++++++++++++++++++++++++ src/internal/syscall.h | 12 +++++++++ src/linux/wait4.c | 2 +- src/process/waitpid.c | 2 +- src/stdio/pclose.c | 2 +- src/unistd/faccessat.c | 6 ++++- 6 files changed, 75 insertions(+), 4 deletions(-) create mode 100644 src/internal/__wait4.c diff --git a/src/internal/__wait4.c b/src/internal/__wait4.c new file mode 100644 index 00000000..04d7dc64 --- /dev/null +++ b/src/internal/__wait4.c @@ -0,0 +1,55 @@ +#include +#include "syscall.h" + +#ifndef SYS_wait4 +hidden pid_t __wait4(pid_t pid, int *status, int options, void *kru, int cp) +{ + idtype_t t; + int r; + siginfo_t info; + + info.si_pid = 0; + if (pid < -1) { + t = P_PGID; + pid = -pid; + } else if (pid == -1) { + t = P_ALL; + } else if (pid == 0) { + t = P_PGID; + } else { + t = P_PID; + } + + if (cp) r = __syscall_cp(SYS_waitid, t, pid, &info, options|WEXITED, kru); + else r = __syscall(SYS_waitid, t, pid, &info, options|WEXITED, kru); + + if (r<0) return r; + + if (info.si_pid && status) { + int sw=0; + switch (info.si_code) { + case CLD_CONTINUED: + sw = 0xffff; + break; + case CLD_DUMPED: + sw = info.si_status&0x7f | 0x80; + break; + case CLD_EXITED: + sw = (info.si_status&0xff) << 8; + break; + case CLD_KILLED: + sw = info.si_status&0x7f; + break; + case CLD_STOPPED: + case CLD_TRAPPED: + /* see ptrace(2); the high bits of si_status can contain */ + /* PTRACE_EVENT_ values which must be preserved */ + sw = (info.si_status << 8) + 0x7f; + break; + } + *status = sw; + } + + return info.si_pid; +} +#endif diff --git a/src/internal/syscall.h b/src/internal/syscall.h index 4f41e1dc..27642938 100644 --- a/src/internal/syscall.h +++ b/src/internal/syscall.h @@ -5,6 +5,8 @@ #include #include #include "syscall_arch.h" +#define __NEED_pid_t +#include #ifndef SYSCALL_RLIM_INFINITY #define SYSCALL_RLIM_INFINITY (~0ULL) @@ -395,4 +397,14 @@ hidden void __procfdname(char __buf[static 15+3*sizeof(int)], unsigned); hidden void *__vdsosym(const char *, const char *); +#ifdef SYS_wait4 +static inline pid_t __wait4(pid_t pid, int *status, int options, void *kru, int cp) +{ + if (cp) return __syscall_cp(SYS_wait4, pid, status, options, kru); + else return __syscall(SYS_wait4, pid, status, options, kru); +} +#else +hidden pid_t __wait4(pid_t pid, int *status, int options, void *kru, int cp); +#endif + #endif diff --git a/src/linux/wait4.c b/src/linux/wait4.c index 83650e34..32652dc2 100644 --- a/src/linux/wait4.c +++ b/src/linux/wait4.c @@ -26,7 +26,7 @@ pid_t wait4(pid_t pid, int *status, int options, struct rusage *ru) } #endif char *dest = ru ? (char *)&ru->ru_maxrss - 4*sizeof(long) : 0; - r = __syscall(SYS_wait4, pid, status, options, dest); + r = __wait4(pid, status, options, dest, 0); if (r>0 && ru && sizeof(time_t) > sizeof(long)) { long kru[4]; memcpy(kru, dest, 4*sizeof(long)); diff --git a/src/process/waitpid.c b/src/process/waitpid.c index 1b65bf05..e5ff27ca 100644 --- a/src/process/waitpid.c +++ b/src/process/waitpid.c @@ -3,5 +3,5 @@ pid_t waitpid(pid_t pid, int *status, int options) { - return syscall_cp(SYS_wait4, pid, status, options, 0); + return __wait4(pid, status, options, 0, 1); } diff --git a/src/stdio/pclose.c b/src/stdio/pclose.c index 080a4262..b60d8f2c 100644 --- a/src/stdio/pclose.c +++ b/src/stdio/pclose.c @@ -7,7 +7,7 @@ int pclose(FILE *f) int status, r; pid_t pid = f->pipe_pid; fclose(f); - while ((r=__syscall(SYS_wait4, pid, &status, 0, 0)) == -EINTR); + while ((r=__wait4(pid, &status, 0, 0, 0)) == -EINTR); if (r<0) return __syscall_ret(r); return status; } diff --git a/src/unistd/faccessat.c b/src/unistd/faccessat.c index 76bbd4c7..8bf34995 100644 --- a/src/unistd/faccessat.c +++ b/src/unistd/faccessat.c @@ -34,7 +34,6 @@ int faccessat(int fd, const char *filename, int amode, int flag) char stack[1024]; sigset_t set; pid_t pid; - int status; int ret, p[2]; if (pipe2(p, O_CLOEXEC)) return __syscall_ret(-EBUSY); @@ -48,7 +47,12 @@ int faccessat(int fd, const char *filename, int amode, int flag) if (pid<0 || __syscall(SYS_read, p[0], &ret, sizeof ret) != sizeof(ret)) ret = -EBUSY; __syscall(SYS_close, p[0]); +#ifdef SYS_wait4 + int status; __syscall(SYS_wait4, pid, &status, __WCLONE, 0); +#else + __syscall(SYS_waitid, P_PID, pid, &(siginfo_t){0}, __WCLONE|WEXITED, 0); +#endif __restore_sigs(&set); -- 2.25.4