|
Message-Id: <3fa391faaab13525d092921bad47b54119f3a6e4.1409524413.git.Jens.Gustedt@inria.fr> Date: Mon, 01 Sep 2014 00:47:46 +0200 From: Jens Gustedt <Jens.Gustedt@...ia.fr> To: musl@...ts.openwall.com Subject: [PATCH 8/9] separate pthread_create and pthread_exit in two different TU --- src/thread/pthread_create.c | 124 ++--------------------------------------- src/thread/pthread_exit.c | 130 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 135 insertions(+), 119 deletions(-) create mode 100644 src/thread/pthread_exit.c diff --git a/src/thread/pthread_create.c b/src/thread/pthread_create.c index c1feb62..7bc7b0f 100644 --- a/src/thread/pthread_create.c +++ b/src/thread/pthread_create.c @@ -10,102 +10,16 @@ void *__mmap(void *, size_t, int, int, int, off_t); int __munmap(void *, size_t); int __mprotect(void *, size_t, int); _Noreturn void __thrd_exit(int); +void __thread_enable(void); +_Noreturn void __pthread_exit(void *); +void *__copy_tls(unsigned char *); +extern volatile size_t __pthread_tsd_size; static void dummy_0() { } weak_alias(dummy_0, __acquire_ptc); weak_alias(dummy_0, __release_ptc); -weak_alias(dummy_0, __pthread_tsd_run_dtors); -weak_alias(dummy_0, __do_private_robust_list); -weak_alias(dummy_0, __do_orphaned_stdio_locks); - -_Noreturn void __pthread_exit(void *result) -{ - pthread_t self = __pthread_self(); - sigset_t set; - - self->result = result; - - while (self->cancelbuf) { - void (*f)(void *) = self->cancelbuf->__f; - void *x = self->cancelbuf->__x; - self->cancelbuf = self->cancelbuf->__next; - f(x); - } - - __pthread_tsd_run_dtors(); - - __lock(self->exitlock); - - /* Mark this thread dead before decrementing count */ - __lock(self->killlock); - self->dead = 1; - - /* Block all signals before decrementing the live thread count. - * This is important to ensure that dynamically allocated TLS - * is not under-allocated/over-committed, and possibly for other - * reasons as well. */ - __block_all_sigs(&set); - - /* Wait to unlock the kill lock, which governs functions like - * pthread_kill which target a thread id, until signals have - * been blocked. This precludes observation of the thread id - * as a live thread (with application code running in it) after - * the thread was reported dead by ESRCH being returned. */ - __unlock(self->killlock); - - /* It's impossible to determine whether this is "the last thread" - * until performing the atomic decrement, since multiple threads - * could exit at the same time. For the last thread, revert the - * decrement and unblock signals to give the atexit handlers and - * stdio cleanup code a consistent state. */ - if (a_fetch_add(&libc.threads_minus_1, -1)==0) { - libc.threads_minus_1 = 0; - __restore_sigs(&set); - exit(0); - } - - if (self->locale != &libc.global_locale) { - a_dec(&libc.uselocale_cnt); - if (self->locale->ctype_utf8) - a_dec(&libc.bytelocale_cnt_minus_1); - } - - __do_private_robust_list(); - __do_orphaned_stdio_locks(); - - if (self->detached && self->map_base) { - /* Detached threads must avoid the kernel clear_child_tid - * feature, since the virtual address will have been - * unmapped and possibly already reused by a new mapping - * at the time the kernel would perform the write. In - * the case of threads that started out detached, the - * initial clone flags are correct, but if the thread was - * detached later (== 2), we need to clear it here. */ - if (self->detached == 2) __syscall(SYS_set_tid_address, 0); - - /* The following call unmaps the thread's stack mapping - * and then exits without touching the stack. */ - __unmapself(self->map_base, self->map_size); - } - - for (;;) __syscall(SYS_exit, 0); -} - -void __do_cleanup_push(struct __ptcb *cb) -{ - if (!libc.has_thread_pointer) return; - struct pthread *self = __pthread_self(); - cb->__next = self->cancelbuf; - self->cancelbuf = cb; -} - -void __do_cleanup_pop(struct __ptcb *cb) -{ - if (!libc.has_thread_pointer) return; - __pthread_self()->cancelbuf = cb->__next; -} static int start(void *p) { @@ -135,24 +49,6 @@ static int start_c11(void *p) #define ROUND(x) (((x)+PAGE_SIZE-1)&-PAGE_SIZE) -/* pthread_key_create.c overrides this */ -static volatile size_t dummy = 0; -weak_alias(dummy, __pthread_tsd_size); -static void *dummy_tsd[1] = { 0 }; -weak_alias(dummy_tsd, __pthread_tsd_main); - -static FILE *volatile dummy_file = 0; -weak_alias(dummy_file, __stdin_used); -weak_alias(dummy_file, __stdout_used); -weak_alias(dummy_file, __stderr_used); - -static void init_file_lock(FILE *f) -{ - if (f && f->lock<0) f->lock = 0; -} - -void *__copy_tls(unsigned char *); - int __pthread_create(pthread_t *restrict res, const pthread_attr_t *restrict attrp, void *(*entry)(void *), void *restrict arg) { int ret, c11 = (attrp == __ATTRP_C11_THREAD); @@ -167,16 +63,7 @@ int __pthread_create(pthread_t *restrict res, const pthread_attr_t *restrict att if (!libc.can_do_threads) return ENOSYS; self = __pthread_self(); - if (!libc.threaded) { - for (FILE *f=libc.ofl_head; f; f=f->next) - init_file_lock(f); - init_file_lock(__stdin_used); - init_file_lock(__stdout_used); - init_file_lock(__stderr_used); - __syscall(SYS_rt_sigprocmask, SIG_UNBLOCK, SIGPT_SET, 0, _NSIG/8); - self->tsd = (void **)__pthread_tsd_main; - libc.threaded = 1; - } + if (!libc.threaded) __thread_enable(); if (attrp && !c11) attr = *attrp; __acquire_ptc(); @@ -273,5 +160,4 @@ fail_nomem: return c11 ? ENOMEM : EAGAIN; } -weak_alias(__pthread_exit, pthread_exit); weak_alias(__pthread_create, pthread_create); diff --git a/src/thread/pthread_exit.c b/src/thread/pthread_exit.c new file mode 100644 index 0000000..4f51269 --- /dev/null +++ b/src/thread/pthread_exit.c @@ -0,0 +1,130 @@ +#define _GNU_SOURCE +#include "pthread_impl.h" +#include "stdio_impl.h" +#include "libc.h" +#include <sys/mman.h> +#include <threads.h> + +static void dummy_0() +{ +} +weak_alias(dummy_0, __pthread_tsd_run_dtors); +weak_alias(dummy_0, __do_private_robust_list); +weak_alias(dummy_0, __do_orphaned_stdio_locks); + +_Noreturn void __pthread_exit(void *result) +{ + pthread_t self = __pthread_self(); + sigset_t set; + + self->result = result; + + while (self->cancelbuf) { + void (*f)(void *) = self->cancelbuf->__f; + void *x = self->cancelbuf->__x; + self->cancelbuf = self->cancelbuf->__next; + f(x); + } + + __pthread_tsd_run_dtors(); + + __lock(self->exitlock); + + /* Mark this thread dead before decrementing count */ + __lock(self->killlock); + self->dead = 1; + + /* Block all signals before decrementing the live thread count. + * This is important to ensure that dynamically allocated TLS + * is not under-allocated/over-committed, and possibly for other + * reasons as well. */ + __block_all_sigs(&set); + + /* Wait to unlock the kill lock, which governs functions like + * pthread_kill which target a thread id, until signals have + * been blocked. This precludes observation of the thread id + * as a live thread (with application code running in it) after + * the thread was reported dead by ESRCH being returned. */ + __unlock(self->killlock); + + /* It's impossible to determine whether this is "the last thread" + * until performing the atomic decrement, since multiple threads + * could exit at the same time. For the last thread, revert the + * decrement and unblock signals to give the atexit handlers and + * stdio cleanup code a consistent state. */ + if (a_fetch_add(&libc.threads_minus_1, -1)==0) { + libc.threads_minus_1 = 0; + __restore_sigs(&set); + exit(0); + } + + if (self->locale != &libc.global_locale) { + a_dec(&libc.uselocale_cnt); + if (self->locale->ctype_utf8) + a_dec(&libc.bytelocale_cnt_minus_1); + } + + __do_private_robust_list(); + __do_orphaned_stdio_locks(); + + if (self->detached && self->map_base) { + /* Detached threads must avoid the kernel clear_child_tid + * feature, since the virtual address will have been + * unmapped and possibly already reused by a new mapping + * at the time the kernel would perform the write. In + * the case of threads that started out detached, the + * initial clone flags are correct, but if the thread was + * detached later (== 2), we need to clear it here. */ + if (self->detached == 2) __syscall(SYS_set_tid_address, 0); + + /* The following call unmaps the thread's stack mapping + * and then exits without touching the stack. */ + __unmapself(self->map_base, self->map_size); + } + + for (;;) __syscall(SYS_exit, 0); +} + +void __do_cleanup_push(struct __ptcb *cb) +{ + if (!libc.has_thread_pointer) return; + struct pthread *self = __pthread_self(); + cb->__next = self->cancelbuf; + self->cancelbuf = cb; +} + +void __do_cleanup_pop(struct __ptcb *cb) +{ + if (!libc.has_thread_pointer) return; + __pthread_self()->cancelbuf = cb->__next; +} + +/* pthread_key_create.c overrides this */ +static volatile size_t dummy = 0; +weak_alias(dummy, __pthread_tsd_size); +static void *dummy_tsd[1] = { 0 }; +weak_alias(dummy_tsd, __pthread_tsd_main); + +static FILE *volatile dummy_file = 0; +weak_alias(dummy_file, __stdin_used); +weak_alias(dummy_file, __stdout_used); +weak_alias(dummy_file, __stderr_used); + +static void init_file_lock(FILE *f) +{ + if (f && f->lock<0) f->lock = 0; +} + +void __thread_enable(void) +{ + for (FILE *f=libc.ofl_head; f; f=f->next) + init_file_lock(f); + init_file_lock(__stdin_used); + init_file_lock(__stdout_used); + init_file_lock(__stderr_used); + __syscall(SYS_rt_sigprocmask, SIG_UNBLOCK, SIGPT_SET, 0, _NSIG/8); + __pthread_self()->tsd = (void **)__pthread_tsd_main; + libc.threaded = 1; +} + +weak_alias(__pthread_exit, pthread_exit); -- 1.7.10.4
Powered by blists - more mailing lists
Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.