rv32 uses the generic include/uapi/asm-generic/unistd.h and it has no __NR_wait4 after kernel commit d4c08b9776b3 ("riscv: Use latest system call ABI"), use __NR_waitid instead.
This code is based on sysdeps/unix/sysv/linux/wait4.c of glibc.
Notes: The kernel wait4 syscall has the 'pid == INT_MIN' path and returns -ESRCH, but the kernel waitid syscall has no such path, to let this __NR_waitid based sys_wait4 has the same return value and pass the 'waitpid_min' test, we emulate such path in our new nolibc __NR_waitid branch.
Signed-off-by: Zhangjin Wu falcon@tinylab.org --- tools/include/nolibc/sys.h | 54 ++++++++++++++++++++++++++++++++++++ tools/include/nolibc/types.h | 15 +++++++++- 2 files changed, 68 insertions(+), 1 deletion(-)
diff --git a/tools/include/nolibc/sys.h b/tools/include/nolibc/sys.h index 00c7197dcd50..2642b380c6aa 100644 --- a/tools/include/nolibc/sys.h +++ b/tools/include/nolibc/sys.h @@ -12,6 +12,7 @@
/* system includes */ #include <asm/unistd.h> +#include <asm/siginfo.h> /* for siginfo_t */ #include <asm/signal.h> /* for SIGCHLD */ #include <asm/ioctls.h> #include <asm/mman.h> @@ -1333,7 +1334,60 @@ int unlink(const char *path) static __attribute__((unused)) pid_t sys_wait4(pid_t pid, int *status, int options, struct rusage *rusage) { +#ifdef __NR_wait4 return my_syscall4(__NR_wait4, pid, status, options, rusage); +#elif defined(__NR_waitid) + siginfo_t infop; + int idtype = P_PID; + int ret; + + /* emulate the 'pid == INT_MIN' path of wait4 */ + if (pid == INT_MIN) + return -ESRCH; + + if (pid < -1) { + idtype = P_PGID; + pid *= -1; + } else if (pid == -1) { + idtype = P_ALL; + } else if (pid == 0) { + idtype = P_PGID; + } + + options |= WEXITED; + + ret = my_syscall5(__NR_waitid, idtype, pid, &infop, options, rusage); + if (ret < 0) + return ret; + + if (status) { + switch (infop.si_code) { + case CLD_EXITED: + *status = W_EXITCODE(infop.si_status, 0); + break; + case CLD_DUMPED: + *status = __WCOREFLAG | infop.si_status; + break; + case CLD_KILLED: + *status = infop.si_status; + break; + case CLD_TRAPPED: + case CLD_STOPPED: + *status = W_STOPCODE(infop.si_status); + break; + case CLD_CONTINUED: + *status = __W_CONTINUED; + break; + default: + *status = 0; + break; + } + } + + return infop.si_pid; +#else +#error Neither __NR_wait4 nor __NR_waitid defined, cannot implement sys_wait4() +#endif }
static __attribute__((unused)) diff --git a/tools/include/nolibc/types.h b/tools/include/nolibc/types.h index ee914391439c..c4f95c267607 100644 --- a/tools/include/nolibc/types.h +++ b/tools/include/nolibc/types.h @@ -92,8 +92,21 @@ #define WTERMSIG(status) ((status) & 0x7f) #define WIFSIGNALED(status) ((status) - 1 < 0xff)
-/* waitpid() flags */ +/* waitpid() and waitid() flags */ #define WNOHANG 1 +#define WEXITED 0x00000004 + +/* first argument for waitid() */ +#define P_ALL 0 +#define P_PID 1 +#define P_PGID 2 +#define P_PIDFD 3 + +/* Macros used on waitid's status setting */ +#define W_EXITCODE(ret, sig) ((ret) << 8 | (sig)) +#define W_STOPCODE(sig) ((sig) << 8 | 0x7f) +#define __W_CONTINUED 0xffff +#define __WCOREFLAG 0x80
/* standard exit() codes */ #define EXIT_SUCCESS 0