diff --git a/musl_src.gni b/musl_src.gni index 876f5b648c7d848dd4bc5de4b506e86cf7ed5c66..0391b722675b6cf17a807b78131b15f98e56a349 100644 --- a/musl_src.gni +++ b/musl_src.gni @@ -1555,7 +1555,7 @@ if (musl_arch == "arm") { "src/math/fmaf.c", "src/math/sqrt.c", "src/math/sqrtf.c", - "src/process/vfork.c", + "src/process/arm/fork.s", "src/setjmp/longjmp.c", "src/setjmp/setjmp.c", "src/signal/restore.c", @@ -1647,7 +1647,7 @@ if (musl_arch == "arm") { "src/math/sqrtf.c", "src/math/sqrtl.c", "src/math/truncl.c", - "src/process/vfork.c", + "src/process/x86_64/fork.s", "src/setjmp/longjmp.c", "src/setjmp/setjmp.c", "src/signal/restore.c", @@ -2061,6 +2061,7 @@ musl_src_porting_file = [ "ldso/ns_config.h", "ldso/strops.h", "src/legacy/ulimit.c", + "src/linux/clone.c", "src/linux/gettid.c", "src/linux/reboot.c", "src/linux/tgkill.c", @@ -2124,6 +2125,11 @@ musl_src_porting_file = [ "src/ldso/arm/dlvsym.s", "src/ldso/riscv64/dlvsym.s", "src/ldso/x86_64/dlvsym.s", + "src/unistd/getpid.c", + "src/process/fork.c", + "src/process/vfork.c", + "src/process/arm/__vfork.s", + "src/process/x86_64/__vfork.s", ] musl_inc_hook_files = [ diff --git a/porting/linux/user/src/env/__init_tls.c b/porting/linux/user/src/env/__init_tls.c index 153305e0780d50d52ad64d0a5e74ec3d02adab42..9abef853f73b1ae05a19d33b54eaddf52c0be6a0 100644 --- a/porting/linux/user/src/env/__init_tls.c +++ b/porting/linux/user/src/env/__init_tls.c @@ -19,7 +19,7 @@ int __init_tp(void *p) if (r < 0) return -1; if (!r) libc.can_do_threads = 1; td->detach_state = DT_JOINABLE; - td->tid = __syscall(SYS_set_tid_address, &__thread_list_lock); + td->tid = td->cached_pid = __syscall(SYS_set_tid_address, &__thread_list_lock); td->locale = &libc.global_locale; td->robust_list.head = &td->robust_list.head; td->sysinfo = __sysinfo; diff --git a/porting/linux/user/src/internal/pthread_impl.h b/porting/linux/user/src/internal/pthread_impl.h index dfc557a727458b792a9529e3093b9d1877db47c5..ff582d65d618b655a83e2f0e535954c030abed00 100644 --- a/porting/linux/user/src/internal/pthread_impl.h +++ b/porting/linux/user/src/internal/pthread_impl.h @@ -39,6 +39,7 @@ struct pthread { /* Part 2 -- implementation details, non-ABI. */ int tid; + int cached_pid; int errno_val; volatile int detach_state; volatile int cancel; diff --git a/porting/linux/user/src/linux/clone.c b/porting/linux/user/src/linux/clone.c index 23202cb758ff12495d4a46a0dc46284470b1a07a..bab0752a70a2b27a5f003d12a1481a666b7929f4 100644 --- a/porting/linux/user/src/linux/clone.c +++ b/porting/linux/user/src/linux/clone.c @@ -48,19 +48,36 @@ int clone(int (*func)(void *), void *stack, int flags, void *arg, ...) tls = va_arg(ap, void *); ctid = va_arg(ap, pid_t *); va_end(ap); - if (!(flags & (CLONE_VM | CLONE_VFORK)) && func) { - clone_args = (struct __clone_args *)malloc(sizeof(struct __clone_args)); - if (clone_args == NULL) { - errno = ENOMEM; - return -1; + + pthread_t self = __pthread_self(); + pid_t parent_pid = self->cached_pid; + self->cached_pid = 0; + pid_t caller_tid = self->tid; + + if (!(flags & (CLONE_VM | CLONE_VFORK))) { + self->tid = -1; + if (func) { + clone_args = (struct __clone_args *)malloc(sizeof(struct __clone_args)); + if (clone_args == NULL) { + errno = ENOMEM; + return -1; + } + clone_args->func = clone_func; + clone_args->arg = arg; + clone_func = __start_child; } - clone_args->func = clone_func; - clone_args->arg = arg; - clone_func = __start_child; } ret = __syscall_ret(__clone(clone_func, stack, flags, (void *)clone_args, ptid, tls, ctid)); if (!(flags & (CLONE_VM | CLONE_VFORK)) && func) { free(clone_args); } + + if (ret != 0) { + self->cached_pid = parent_pid; + self->tid = caller_tid; + } else if (self->tid == -1) { + self->tid = __syscall(SYS_gettid); + self->cached_pid = self->tid; + } return ret; } diff --git a/porting/linux/user/src/process/arm/__vfork.s b/porting/linux/user/src/process/arm/__vfork.s new file mode 100644 index 0000000000000000000000000000000000000000..5774d7dd49ba59fb4de3298a58c95b2c1fe5db86 --- /dev/null +++ b/porting/linux/user/src/process/arm/__vfork.s @@ -0,0 +1,10 @@ +.syntax unified +.hidden __vfork +.type __vfork,%function +__vfork: + mov ip, r7 + mov r7, 190 + svc 0 + mov r7, ip + .hidden __syscall_ret + b __syscall_ret diff --git a/porting/linux/user/src/process/fork.c b/porting/linux/user/src/process/fork.c new file mode 100644 index 0000000000000000000000000000000000000000..45c0bc882e3433d8d550477663dfae13baad3956 --- /dev/null +++ b/porting/linux/user/src/process/fork.c @@ -0,0 +1,38 @@ +#include +#include +#include +#include "syscall.h" +#include "libc.h" +#include "pthread_impl.h" + +static void dummy(int x) +{ +} + +weak_alias(dummy, __fork_handler); + +pid_t fork(void) +{ + pid_t ret; + sigset_t set; + __fork_handler(-1); + __block_all_sigs(&set); +#ifdef SYS_fork + ret = __syscall(SYS_fork); +#else + ret = __syscall(SYS_clone, SIGCHLD, 0); +#endif + if (!ret) { + pthread_t self = __pthread_self(); + self->tid = __syscall(SYS_gettid); + self->cached_pid = self->tid; + self->robust_list.off = 0; + self->robust_list.pending = 0; + self->next = self->prev = self; + __thread_list_lock = 0; + libc.threads_minus_1 = 0; + } + __restore_sigs(&set); + __fork_handler(!ret); + return __syscall_ret(ret); +} diff --git a/porting/linux/user/src/process/vfork.c b/porting/linux/user/src/process/vfork.c new file mode 100644 index 0000000000000000000000000000000000000000..4901f538d43d9433e0620e71693a00d74f8b555a --- /dev/null +++ b/porting/linux/user/src/process/vfork.c @@ -0,0 +1,27 @@ +#define _GNU_SOURCE +#include +#include +#include "syscall.h" +#include "pthread_impl.h" + +hidden pid_t __vfork(void) +{ + /* vfork syscall cannot be made from C code */ +#ifdef SYS_fork + return syscall(SYS_fork); +#else + return syscall(SYS_clone, SIGCHLD, 0); +#endif +} + +pid_t vfork(void) +{ + pthread_t self = __pthread_self(); + pid_t parent_pid = self->cached_pid; + self->cached_pid = 0; + pid_t ret = __vfork(); + if (ret != 0) { + self->cached_pid = parent_pid; + } + return ret; +} diff --git a/porting/linux/user/src/process/x86_64/__vfork.s b/porting/linux/user/src/process/x86_64/__vfork.s new file mode 100644 index 0000000000000000000000000000000000000000..684dd315eb552c486e2294c5d8a3be065ed587ad --- /dev/null +++ b/porting/linux/user/src/process/x86_64/__vfork.s @@ -0,0 +1,10 @@ +.hidden __vfork +.type __vfork,@function +__vfork: + pop %rdx + mov $58,%eax + syscall + push %rdx + mov %rax,%rdi + .hidden __syscall_ret + jmp __syscall_ret diff --git a/porting/linux/user/src/thread/pthread_create.c b/porting/linux/user/src/thread/pthread_create.c index 7e20ecb07fd46576ae158a643016afdb15c14274..8555750adbf1951d27575ddf4ada6c516d24bf47 100644 --- a/porting/linux/user/src/thread/pthread_create.c +++ b/porting/linux/user/src/thread/pthread_create.c @@ -10,6 +10,8 @@ #include #include +pid_t getpid(void); + void log_print(const char* info,...) { va_list ap; @@ -389,6 +391,7 @@ int __pthread_create(pthread_t *restrict res, const pthread_attr_t *restrict att new->stack_size = stack - stack_limit; new->guard_size = guard; new->self = new; + new->cached_pid = getpid(); new->tsd = (void *)tsd; new->locale = &libc.global_locale; if (attr._a_detach) { @@ -424,7 +427,7 @@ int __pthread_create(pthread_t *restrict res, const pthread_attr_t *restrict att __tl_lock(); libc.threads_minus_1++; - ret = __clone((c11 ? start_c11 : start), stack, flags, args, &new->tid, TP_ADJ(new), &__thread_list_lock); + ret = clone((c11 ? start_c11 : start), stack, flags, args, &new->tid, TP_ADJ(new), &__thread_list_lock); /* All clone failures translate to EAGAIN. If explicit scheduling * was requested, attempt it before unlocking the thread list so diff --git a/porting/linux/user/src/unistd/getpid.c b/porting/linux/user/src/unistd/getpid.c new file mode 100644 index 0000000000000000000000000000000000000000..4dbfcf8d1877546b53e7e85155d6c7f4453a628a --- /dev/null +++ b/porting/linux/user/src/unistd/getpid.c @@ -0,0 +1,17 @@ +#include +#include "pthread_impl.h" +#include "syscall.h" + +static pid_t __get_cached_pid() +{ + return __pthread_self()->cached_pid; +} + +pid_t getpid(void) +{ + pid_t cached_pid = __get_cached_pid(); + if (cached_pid != 0) { + return cached_pid; + } + return __syscall(SYS_getpid); +}