diff options
Diffstat (limited to 'src/thread/pthread_create.c')
-rw-r--r-- | src/thread/pthread_create.c | 24 |
1 files changed, 13 insertions, 11 deletions
diff --git a/src/thread/pthread_create.c b/src/thread/pthread_create.c index ac06d7a7..a86b5e1b 100644 --- a/src/thread/pthread_create.c +++ b/src/thread/pthread_create.c @@ -39,9 +39,11 @@ _Noreturn void __pthread_exit(void *result) LOCK(self->exitlock); - /* Mark this thread dead before decrementing count */ + /* Access to target the exiting thread with syscalls that use + * its kernel tid is controlled by killlock. For detached threads, + * any use past this point would have undefined behavior, but for + * joinable threads it's a valid usage that must be handled. */ LOCK(self->killlock); - self->dead = 1; /* Block all signals before decrementing the live thread count. * This is important to ensure that dynamically allocated TLS @@ -49,20 +51,14 @@ _Noreturn void __pthread_exit(void *result) * 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. */ + * decrement, restore the tid, 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; + UNLOCK(self->killlock); __restore_sigs(&set); exit(0); } @@ -113,6 +109,12 @@ _Noreturn void __pthread_exit(void *result) __unmapself(self->map_base, self->map_size); } + /* After the kernel thread exits, its tid may be reused. Clear it + * to prevent inadvertent use and inform functions that would use + * it that it's no longer available. */ + self->tid = 0; + UNLOCK(self->killlock); + for (;;) __syscall(SYS_exit, 0); } |