am ee99ebbc: am 7a8e20c9: Merge "Explain the sigprocmask in pthread_exit."

* commit 'ee99ebbc8f0447880f316a10b2249f813f964172':
  Explain the sigprocmask in pthread_exit.
This commit is contained in:
Elliott Hughes 2013-10-29 18:31:06 -07:00 committed by Android Git Automerger
commit 8695949391
3 changed files with 34 additions and 32 deletions

View File

@ -83,25 +83,20 @@ void __pthread_cleanup_pop( __pthread_cleanup_t* c, int execute )
c->__cleanup_routine(c->__cleanup_arg); c->__cleanup_routine(c->__cleanup_arg);
} }
void pthread_exit(void * retval) void pthread_exit(void* retval) {
{
pthread_internal_t* thread = __get_thread(); pthread_internal_t* thread = __get_thread();
void* stack_base = thread->attr.stack_base;
size_t stack_size = thread->attr.stack_size;
int user_stack = (thread->attr.flags & PTHREAD_ATTR_FLAG_USER_STACK) != 0;
sigset_t mask;
// call the cleanup handlers first // Call the cleanup handlers first.
while (thread->cleanup_stack) { while (thread->cleanup_stack) {
__pthread_cleanup_t* c = thread->cleanup_stack; __pthread_cleanup_t* c = thread->cleanup_stack;
thread->cleanup_stack = c->__cleanup_prev; thread->cleanup_stack = c->__cleanup_prev;
c->__cleanup_routine(c->__cleanup_arg); c->__cleanup_routine(c->__cleanup_arg);
} }
// call the TLS destructors, it is important to do that before removing this // Call the TLS destructors. It is important to do that before removing this
// thread from the global list. this will ensure that if someone else deletes // thread from the global list. This will ensure that if someone else deletes
// a TLS key, the corresponding value will be set to NULL in this thread's TLS // a TLS key, the corresponding value will be set to NULL in this thread's TLS
// space (see pthread_key_delete) // space (see pthread_key_delete).
pthread_key_clean_all(); pthread_key_clean_all();
if (thread->alternate_signal_stack != NULL) { if (thread->alternate_signal_stack != NULL) {
@ -116,42 +111,49 @@ void pthread_exit(void * retval)
thread->alternate_signal_stack = NULL; thread->alternate_signal_stack = NULL;
} }
// if the thread is detached, destroy the pthread_internal_t // Keep track of what we need to know about the stack before we lose the pthread_internal_t.
// otherwise, keep it in memory and signal any joiners. 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); pthread_mutex_lock(&gThreadListLock);
if (thread->attr.flags & PTHREAD_ATTR_FLAG_DETACHED) { if (thread->attr.flags & PTHREAD_ATTR_FLAG_DETACHED) {
_pthread_internal_remove_locked(thread); _pthread_internal_remove_locked(thread);
} else { } else {
/* make sure that the thread struct doesn't have stale pointers to a stack that // Make sure that the thread struct doesn't have stale pointers to a stack that
* will be unmapped after the exit call below. // will be unmapped after the exit call below.
*/ if (!user_allocated_stack) {
if (!user_stack) {
thread->attr.stack_base = NULL; thread->attr.stack_base = NULL;
thread->attr.stack_size = 0; thread->attr.stack_size = 0;
thread->tls = NULL; thread->tls = NULL;
} }
/* Indicate that the thread has exited for joining threads. */ // Indicate that the thread has exited for joining threads.
thread->attr.flags |= PTHREAD_ATTR_FLAG_ZOMBIE; thread->attr.flags |= PTHREAD_ATTR_FLAG_ZOMBIE;
thread->return_value = retval; thread->return_value = retval;
/* Signal the joining thread if present. */ // Signal the joining thread if present.
if (thread->attr.flags & PTHREAD_ATTR_FLAG_JOINED) { if (thread->attr.flags & PTHREAD_ATTR_FLAG_JOINED) {
pthread_cond_signal(&thread->join_cond); pthread_cond_signal(&thread->join_cond);
} }
} }
pthread_mutex_unlock(&gThreadListLock); pthread_mutex_unlock(&gThreadListLock);
sigfillset(&mask); if (user_allocated_stack) {
sigdelset(&mask, SIGSEGV);
sigprocmask(SIG_SETMASK, &mask, NULL);
if (user_stack) {
// Cleaning up this thread's stack is the creator's responsibility, not ours. // Cleaning up this thread's stack is the creator's responsibility, not ours.
__exit(0); __exit(0);
} else { } else {
// We need to munmap the stack we're running on before calling exit. // We need to munmap the stack we're running on before calling exit.
// That's not something we can do in C. // That's not something we can do in C.
// We don't want to take a signal after we've unmapped the stack.
// That's one last thing we can handle in C.
sigset_t mask;
sigfillset(&mask);
sigprocmask(SIG_SETMASK, &mask, NULL);
_exit_with_stack_teardown(stack_base, stack_size, 0); _exit_with_stack_teardown(stack_base, stack_size, 0);
} }
} }

View File

@ -175,7 +175,7 @@ int pthread_create(pthread_t* thread_out, pthread_attr_t const* attr,
} }
} else { } else {
// The caller did provide a stack, so remember we're not supposed to free it. // The caller did provide a stack, so remember we're not supposed to free it.
thread->attr.flags |= PTHREAD_ATTR_FLAG_USER_STACK; thread->attr.flags |= PTHREAD_ATTR_FLAG_USER_ALLOCATED_STACK;
} }
// Make room for the TLS area. // Make room for the TLS area.
@ -202,7 +202,7 @@ int pthread_create(pthread_t* thread_out, pthread_attr_t const* attr,
int tid = __pthread_clone(start_routine, child_stack, flags, arg); int tid = __pthread_clone(start_routine, child_stack, flags, arg);
if (tid < 0) { if (tid < 0) {
int clone_errno = errno; int clone_errno = errno;
if ((thread->attr.flags & PTHREAD_ATTR_FLAG_USER_STACK) == 0) { if ((thread->attr.flags & PTHREAD_ATTR_FLAG_USER_ALLOCATED_STACK) == 0) {
munmap(thread->attr.stack_base, thread->attr.stack_size); munmap(thread->attr.stack_base, thread->attr.stack_size);
} }
free(thread); free(thread);

View File

@ -69,7 +69,7 @@ __LIBC_HIDDEN__ void _pthread_internal_remove_locked(pthread_internal_t* thread)
#define PTHREAD_ATTR_FLAG_DETACHED 0x00000001 #define PTHREAD_ATTR_FLAG_DETACHED 0x00000001
/* Was the thread's stack allocated by the user rather than by us? */ /* Was the thread's stack allocated by the user rather than by us? */
#define PTHREAD_ATTR_FLAG_USER_STACK 0x00000002 #define PTHREAD_ATTR_FLAG_USER_ALLOCATED_STACK 0x00000002
/* Has the thread been joined by another thread? */ /* Has the thread been joined by another thread? */
#define PTHREAD_ATTR_FLAG_JOINED 0x00000004 #define PTHREAD_ATTR_FLAG_JOINED 0x00000004