diff options
Diffstat (limited to 'libc-top-half/musl/src/process/fork.c')
-rw-r--r-- | libc-top-half/musl/src/process/fork.c | 86 |
1 files changed, 86 insertions, 0 deletions
diff --git a/libc-top-half/musl/src/process/fork.c b/libc-top-half/musl/src/process/fork.c new file mode 100644 index 0000000..54bc289 --- /dev/null +++ b/libc-top-half/musl/src/process/fork.c @@ -0,0 +1,86 @@ +#include <unistd.h> +#include <errno.h> +#include "libc.h" +#include "lock.h" +#include "pthread_impl.h" +#include "fork_impl.h" + +static volatile int *const dummy_lockptr = 0; + +weak_alias(dummy_lockptr, __at_quick_exit_lockptr); +weak_alias(dummy_lockptr, __atexit_lockptr); +weak_alias(dummy_lockptr, __dlerror_lockptr); +weak_alias(dummy_lockptr, __gettext_lockptr); +weak_alias(dummy_lockptr, __locale_lockptr); +weak_alias(dummy_lockptr, __random_lockptr); +weak_alias(dummy_lockptr, __sem_open_lockptr); +weak_alias(dummy_lockptr, __stdio_ofl_lockptr); +weak_alias(dummy_lockptr, __syslog_lockptr); +weak_alias(dummy_lockptr, __timezone_lockptr); +weak_alias(dummy_lockptr, __bump_lockptr); + +weak_alias(dummy_lockptr, __vmlock_lockptr); + +static volatile int *const *const atfork_locks[] = { + &__at_quick_exit_lockptr, + &__atexit_lockptr, + &__dlerror_lockptr, + &__gettext_lockptr, + &__locale_lockptr, + &__random_lockptr, + &__sem_open_lockptr, + &__stdio_ofl_lockptr, + &__syslog_lockptr, + &__timezone_lockptr, + &__bump_lockptr, +}; + +static void dummy(int x) { } +weak_alias(dummy, __fork_handler); +weak_alias(dummy, __malloc_atfork); +weak_alias(dummy, __ldso_atfork); + +static void dummy_0(void) { } +weak_alias(dummy_0, __tl_lock); +weak_alias(dummy_0, __tl_unlock); + +pid_t fork(void) +{ + sigset_t set; + __fork_handler(-1); + __block_app_sigs(&set); + int need_locks = libc.need_locks > 0; + if (need_locks) { + __ldso_atfork(-1); + __inhibit_ptc(); + for (int i=0; i<sizeof atfork_locks/sizeof *atfork_locks; i++) + if (*atfork_locks[i]) LOCK(*atfork_locks[i]); + __malloc_atfork(-1); + __tl_lock(); + } + pthread_t self=__pthread_self(), next=self->next; + pid_t ret = _Fork(); + int errno_save = errno; + if (need_locks) { + if (!ret) { + for (pthread_t td=next; td!=self; td=td->next) + td->tid = -1; + if (__vmlock_lockptr) { + __vmlock_lockptr[0] = 0; + __vmlock_lockptr[1] = 0; + } + } + __tl_unlock(); + __malloc_atfork(!ret); + for (int i=0; i<sizeof atfork_locks/sizeof *atfork_locks; i++) + if (*atfork_locks[i]) + if (ret) UNLOCK(*atfork_locks[i]); + else **atfork_locks[i] = 0; + __release_ptc(); + __ldso_atfork(!ret); + } + __restore_sigs(&set); + __fork_handler(!ret); + if (ret<0) errno = errno_save; + return ret; +} |