Esempio n. 1
0
void pthread_exit(void * retval)
{
    pthread_internal_t*  thread     = __get_thread();
    void*                stack_base = thread->attr.stack_base;
    int                  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
    while (thread->cleanup_stack) {
        __pthread_cleanup_t*  c = thread->cleanup_stack;
        thread->cleanup_stack   = c->__cleanup_prev;
        c->__cleanup_routine(c->__cleanup_arg);
    }

    // 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
    // a TLS key, the corresponding value will be set to NULL in this thread's TLS
    // space (see pthread_key_delete)
    pthread_key_clean_all();

    // 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 thread struct doesn't have stale pointers to a stack that
         * will be unmapped after the exit call below.
         */
        if (!user_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);
        }
    }
    pthread_mutex_unlock(&gThreadListLock);

    sigfillset(&mask);
    sigdelset(&mask, SIGSEGV);
    (void)sigprocmask(SIG_SETMASK, &mask, (sigset_t *)NULL);

    // destroy the thread stack
    if (user_stack)
        _exit_thread((int)retval);
    else
        _exit_with_stack_teardown(stack_base, stack_size, (int)retval);
}
Esempio n. 2
0
void pthread_exit(void* return_value) {
  pthread_internal_t* thread = __get_thread();

  ...

  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_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;
    }
    // pthread_join is responsible for destroying the pthread_internal_t for non-detached threads.
    // The kernel will futex_wake on the pthread_internal_t::tid field to wake pthread_join.
  }
  pthread_mutex_unlock(&g_thread_list_lock);

  // Perform a second key cleanup. When using jemalloc, a call to free from
  // _pthread_internal_remove_locked causes the memory associated with a key
  // to be reallocated.
  // TODO: When b/16847284 is fixed this call can be removed.
  pthread_key_clean_all();

  if (user_allocated_stack) {
    // Cleaning up this thread's stack is the creator's responsibility, not ours.
    __exit(0);
  } else {
    // We need to munmap the stack we're running on before calling exit.
    // 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);
  }
}
Esempio n. 3
0
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) {
    __pthread_cleanup_t* c = thread->cleanup_stack;
    thread->cleanup_stack = c->__cleanup_prev;
    c->__cleanup_routine(c->__cleanup_arg);
  }

  // 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
  // a TLS key, the corresponding value will be set to NULL in this thread's TLS
  // space (see pthread_key_delete).
  pthread_key_clean_all();

  if (thread->alternate_signal_stack != NULL) {
    // Tell the kernel to stop using the alternate signal stack.
    stack_t ss;
    ss.ss_sp = NULL;
    ss.ss_flags = SS_DISABLE;
    sigaltstack(&ss, NULL);

    // Free it.
    munmap(thread->alternate_signal_stack, SIGSTKSZ);
    thread->alternate_signal_stack = NULL;
  }

  // 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);

  pthread_mutex_lock(&gThreadListLock);
  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_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;
    }
    // pthread_join is responsible for destroying the pthread_internal_t for non-detached threads.
    // The kernel will futex_wake on the pthread_internal_t::tid field to wake pthread_join.
  }
  pthread_mutex_unlock(&gThreadListLock);

  if (user_allocated_stack) {
    // Cleaning up this thread's stack is the creator's responsibility, not ours.
    __exit(0);
  } else {
    // We need to munmap the stack we're running on before calling exit.
    // 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);
  }

  // NOTREACHED, but we told the compiler this function is noreturn, and it doesn't believe us.
  abort();
}