diff options
author | Rich Felker <dalias@aerifal.cx> | 2013-04-26 16:04:30 -0400 |
---|---|---|
committer | Rich Felker <dalias@aerifal.cx> | 2013-04-26 16:04:30 -0400 |
commit | 6e531f999a82cf39a951e1e9bba3cb80a6eb1464 (patch) | |
tree | c17563fb2d6210fb8b513b0c968e4ad5bfcf02d0 /src | |
parent | 23f21c304fd6a7592b70927e247129c5a2bc2390 (diff) | |
download | musl-6e531f999a82cf39a951e1e9bba3cb80a6eb1464.tar.gz musl-6e531f999a82cf39a951e1e9bba3cb80a6eb1464.tar.xz musl-6e531f999a82cf39a951e1e9bba3cb80a6eb1464.zip |
add comments on some of the pthread_exit logic
Diffstat (limited to 'src')
-rw-r--r-- | src/thread/pthread_create.c | 17 |
1 files changed, 15 insertions, 2 deletions
diff --git a/src/thread/pthread_create.c b/src/thread/pthread_create.c index 0cd2d6c2..6a37ee9b 100644 --- a/src/thread/pthread_create.c +++ b/src/thread/pthread_create.c @@ -32,6 +32,10 @@ _Noreturn void pthread_exit(void *result) self->dead = 1; __unlock(self->killlock); + /* 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. */ __syscall(SYS_rt_sigprocmask, SIG_BLOCK, SIGALL_SET, 0, _NSIG/8); do n = libc.threads_minus_1; @@ -39,8 +43,17 @@ _Noreturn void pthread_exit(void *result) if (!n) exit(0); if (self->detached && self->map_base) { - if (self->detached == 2) - __syscall(SYS_set_tid_address, 0); + /* 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); } |