index aa9bd3832075d0fd2295e2edfcd2d98e539d7622..e04cf8e7f8246682ee406e61117a77a1447d1998 100644 (file)
#include <pthread.h>
+#include <signal.h>
#include <stdlib.h>
#include <sys/mman.h>
#include "pthread_internal.h"
-extern "C" void _exit_with_stack_teardown(void*, size_t, int);
-extern "C" void __exit(int);
+extern "C" __noreturn void _exit_with_stack_teardown(void*, size_t);
+extern "C" __noreturn void __exit(int);
+extern "C" int __set_tid_address(int*);
/* CAVEAT: our implementation of pthread_cleanup_push/pop doesn't support C++ exceptions
* and thread cancelation
}
}
-void pthread_exit(void* retval) {
+void pthread_exit(void* return_value) {
pthread_internal_t* thread = __get_thread();
+ thread->return_value = return_value;
// Call the cleanup handlers first.
while (thread->cleanup_stack) {
// Keep track of what we need to know about the stack before we lose the pthread_internal_t.
void* stack_base = thread->attr.stack_base;
size_t stack_size = thread->attr.stack_size;
- bool user_allocated_stack = ((thread->attr.flags & PTHREAD_ATTR_FLAG_USER_ALLOCATED_STACK) != 0);
-
- // If the thread is detached, destroy the pthread_internal_t,
- // otherwise keep it in memory and signal any joiners.
- pthread_mutex_lock(&gThreadListLock);
- if (thread->attr.flags & PTHREAD_ATTR_FLAG_DETACHED) {
- _pthread_internal_remove_locked(thread);
- } else {
- // Make sure that the pthread_internal_t doesn't have stale pointers to a stack that
- // will be unmapped after the exit call below.
- if (!user_allocated_stack) {
- thread->attr.stack_base = NULL;
- thread->attr.stack_size = 0;
- thread->tls = NULL;
- }
-
- // Indicate that the thread has exited for joining threads.
- thread->attr.flags |= PTHREAD_ATTR_FLAG_ZOMBIE;
- thread->return_value = retval;
-
- // Signal the joining thread if present.
- if (thread->attr.flags & PTHREAD_ATTR_FLAG_JOINED) {
- pthread_cond_signal(&thread->join_cond);
+ bool free_stack = false;
+
+ pthread_mutex_lock(&g_thread_list_lock);
+ if ((thread->attr.flags & PTHREAD_ATTR_FLAG_DETACHED) != 0) {
+ // The thread is detached, so we can free the pthread_internal_t.
+ // First make sure that the kernel does not try to clear the tid field
+ // because we'll have freed the memory before the thread actually exits.
+ __set_tid_address(NULL);
+
+ // pthread_internal_t is freed below with stack, not here.
+ _pthread_internal_remove_locked(thread, false);
+ if (!thread->user_allocated_stack()) {
+ free_stack = true;
}
}
- pthread_mutex_unlock(&gThreadListLock);
+ pthread_mutex_unlock(&g_thread_list_lock);
- if (user_allocated_stack) {
- // Cleaning up this thread's stack is the creator's responsibility, not ours.
- __exit(0);
- } else {
+ // Detached threads exit with stack teardown, and everything deallocated here.
+ // Threads that can be joined exit but leave their stacks for the pthread_join caller to clean up.
+ if (free_stack) {
// We need to munmap the stack we're running on before calling exit.
// That's not something we can do in C.
sigfillset(&mask);
sigprocmask(SIG_SETMASK, &mask, NULL);
- _exit_with_stack_teardown(stack_base, stack_size, 0);
+ _exit_with_stack_teardown(stack_base, stack_size);
+ } else {
+ __exit(0);
}
-
- /* NOTREACHED, but we told the compiler this function is noreturn, and it doesn't believe us. */
- abort();
}