From 19563e1850808af216b1b84263bb7e83cccce506 Mon Sep 17 00:00:00 2001 From: Rich Felker Date: Thu, 22 Feb 2024 18:50:34 -0500 Subject: add framework to support archs without a native wait4 syscall this commit should make no codegen change for existing archs, but is a prerequisite for new archs including riscv32. the wait4 emulation backend provides both cancellable and non-cancellable variants because waitpid is required to be a cancellation point, but all of our other uses are not, and most of them cannot be. based on patch by Stefan O'Rear. --- src/internal/emulate_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 | 2 +- 6 files changed, 71 insertions(+), 4 deletions(-) create mode 100644 src/internal/emulate_wait4.c (limited to 'src') diff --git a/src/internal/emulate_wait4.c b/src/internal/emulate_wait4.c new file mode 100644 index 00000000..f6303412 --- /dev/null +++ b/src/internal/emulate_wait4.c @@ -0,0 +1,55 @@ +#include +#include "syscall.h" + +#ifndef SYS_wait4 +hidden long __emulate_wait4(int 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 4a446157..33d981f9 100644 --- a/src/internal/syscall.h +++ b/src/internal/syscall.h @@ -391,6 +391,18 @@ static inline long __alt_socketcall(int sys, int sock, int cp, syscall_arg_t a, #define __sys_open_cp(...) __SYSCALL_DISP(__sys_open_cp,,__VA_ARGS__) #define sys_open_cp(...) __syscall_ret(__sys_open_cp(__VA_ARGS__)) +#ifdef SYS_wait4 +#define __sys_wait4(a,b,c,d) __syscall(SYS_wait4,a,b,c,d) +#define __sys_wait4_cp(a,b,c,d) __syscall_cp(SYS_wait4,a,b,c,d) +#else +hidden long __emulate_wait4(int, int *, int, void *, int); +#define __sys_wait4(a,b,c,d) __emulate_wait4(a,b,c,d,0) +#define __sys_wait4_cp(a,b,c,d) __emulate_wait4(a,b,c,d,1) +#endif + +#define sys_wait4(a,b,c,d) __syscall_ret(__sys_wait4(a,b,c,d)) +#define sys_wait4_cp(a,b,c,d) __syscall_ret(__sys_wait4_cp(a,b,c,d)) + hidden void __procfdname(char __buf[static 15+3*sizeof(int)], unsigned); hidden void *__vdsosym(const char *, const char *); diff --git a/src/linux/wait4.c b/src/linux/wait4.c index ff2e3e66..fb08c0d0 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 = __sys_wait4(pid, status, options, dest); 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..80231862 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 sys_wait4_cp(pid, status, options, 0); } diff --git a/src/stdio/pclose.c b/src/stdio/pclose.c index 080a4262..c64da405 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=__sys_wait4(pid, &status, 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 557503eb..43052dd7 100644 --- a/src/unistd/faccessat.c +++ b/src/unistd/faccessat.c @@ -53,7 +53,7 @@ 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]); - __syscall(SYS_wait4, pid, &status, __WCLONE, 0); + __sys_wait4(pid, &status, __WCLONE, 0); __restore_sigs(&set); -- cgit v1.2.1