summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRich Felker <dalias@aerifal.cx>2024-02-22 18:50:34 -0500
committerRich Felker <dalias@aerifal.cx>2024-02-22 18:50:34 -0500
commit19563e1850808af216b1b84263bb7e83cccce506 (patch)
tree76aa0be0c61791fcae503569477efb87401cb83e /src
parent7020e85fd768be02e7f5971f1707229407cfa1e4 (diff)
downloadmusl-19563e1850808af216b1b84263bb7e83cccce506.tar.gz
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.
Diffstat (limited to 'src')
-rw-r--r--src/internal/emulate_wait4.c55
-rw-r--r--src/internal/syscall.h12
-rw-r--r--src/linux/wait4.c2
-rw-r--r--src/process/waitpid.c2
-rw-r--r--src/stdio/pclose.c2
-rw-r--r--src/unistd/faccessat.c2
6 files changed, 71 insertions, 4 deletions
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 <sys/wait.h>
+#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);