Merge "Don't corrupt the thread list if the main thread exits."
This commit is contained in:
		@@ -40,10 +40,10 @@
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
 | 
			
		||||
extern unsigned __get_sp(void);
 | 
			
		||||
extern pid_t    gettid(void);
 | 
			
		||||
extern pid_t gettid(void);
 | 
			
		||||
 | 
			
		||||
char*  __progname;
 | 
			
		||||
char **environ;
 | 
			
		||||
char** environ;
 | 
			
		||||
 | 
			
		||||
/* from asm/page.h */
 | 
			
		||||
unsigned int __page_size = PAGE_SIZE;
 | 
			
		||||
@@ -60,48 +60,42 @@ int __system_properties_init(void);
 | 
			
		||||
 * stores the pointer in TLS, but does not add it to pthread's gThreadList. This
 | 
			
		||||
 * has to be done later from libc itself (see __libc_init_common).
 | 
			
		||||
 *
 | 
			
		||||
 * This function also stores elfdata argument in a specific TLS slot to be later
 | 
			
		||||
 * This function also stores the elf_data argument in a specific TLS slot to be later
 | 
			
		||||
 * picked up by the libc constructor.
 | 
			
		||||
 */
 | 
			
		||||
void __libc_init_tls(unsigned** elfdata)
 | 
			
		||||
{
 | 
			
		||||
    pthread_attr_t             thread_attr;
 | 
			
		||||
    static pthread_internal_t  thread;
 | 
			
		||||
    static void*               tls_area[BIONIC_TLS_SLOTS];
 | 
			
		||||
void __libc_init_tls(unsigned** elf_data) {
 | 
			
		||||
  unsigned stack_top = (__get_sp() & ~(PAGE_SIZE - 1)) + PAGE_SIZE;
 | 
			
		||||
  unsigned stack_size = 128 * 1024;
 | 
			
		||||
  unsigned stack_bottom = stack_top - stack_size;
 | 
			
		||||
 | 
			
		||||
    /* setup pthread runtime and main thread descriptor */
 | 
			
		||||
    unsigned stacktop = (__get_sp() & ~(PAGE_SIZE - 1)) + PAGE_SIZE;
 | 
			
		||||
    unsigned stacksize = 128 * 1024;
 | 
			
		||||
    unsigned stackbottom = stacktop - stacksize;
 | 
			
		||||
  pthread_attr_t thread_attr;
 | 
			
		||||
  pthread_attr_init(&thread_attr);
 | 
			
		||||
  pthread_attr_setstack(&thread_attr, (void*) stack_bottom, stack_size);
 | 
			
		||||
 | 
			
		||||
    pthread_attr_init(&thread_attr);
 | 
			
		||||
    pthread_attr_setstack(&thread_attr, (void*)stackbottom, stacksize);
 | 
			
		||||
    _init_thread(&thread, gettid(), &thread_attr, (void*)stackbottom, false);
 | 
			
		||||
    __init_tls(tls_area, &thread);
 | 
			
		||||
  static pthread_internal_t thread;
 | 
			
		||||
  _init_thread(&thread, gettid(), &thread_attr, (void*) stack_bottom, false);
 | 
			
		||||
 | 
			
		||||
    tls_area[TLS_SLOT_BIONIC_PREINIT] = elfdata;
 | 
			
		||||
  static void* tls_area[BIONIC_TLS_SLOTS];
 | 
			
		||||
  __init_tls(tls_area, &thread);
 | 
			
		||||
  tls_area[TLS_SLOT_BIONIC_PREINIT] = elf_data;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void __libc_init_common(uintptr_t *elfdata)
 | 
			
		||||
{
 | 
			
		||||
    int     argc = *elfdata;
 | 
			
		||||
    char**  argv = (char**)(elfdata + 1);
 | 
			
		||||
    char**  envp = argv + argc + 1;
 | 
			
		||||
void __libc_init_common(uintptr_t* elf_data) {
 | 
			
		||||
  int argc = *elf_data;
 | 
			
		||||
  char** argv = (char**) (elf_data + 1);
 | 
			
		||||
  char** envp = argv + argc + 1;
 | 
			
		||||
 | 
			
		||||
    /* get the initial thread from TLS and add it to gThreadList */
 | 
			
		||||
    _pthread_internal_add(__get_thread());
 | 
			
		||||
  // Get the main thread from TLS and add it to the thread list.
 | 
			
		||||
  pthread_internal_t* main_thread = __get_thread();
 | 
			
		||||
  main_thread->allocated_on_heap = false;
 | 
			
		||||
  _pthread_internal_add(main_thread);
 | 
			
		||||
 | 
			
		||||
    /* clear errno */
 | 
			
		||||
    errno = 0;
 | 
			
		||||
  // Set various globals.
 | 
			
		||||
  errno = 0;
 | 
			
		||||
  __progname = argv[0] ? argv[0] : "<unknown>";
 | 
			
		||||
  environ = envp;
 | 
			
		||||
 | 
			
		||||
    /* set program name */
 | 
			
		||||
    __progname = argv[0] ? argv[0] : "<unknown>";
 | 
			
		||||
 | 
			
		||||
    /* setup environment pointer */
 | 
			
		||||
    environ = envp;
 | 
			
		||||
 | 
			
		||||
    /* setup system properties - requires environment */
 | 
			
		||||
    __system_properties_init();
 | 
			
		||||
  __system_properties_init(); // Requires 'environ'.
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* This function will be called during normal program termination
 | 
			
		||||
@@ -111,39 +105,42 @@ void __libc_init_common(uintptr_t *elfdata)
 | 
			
		||||
 * 'fini_array' points to a list of function addresses. The first
 | 
			
		||||
 * entry in the list has value -1, the last one has value 0.
 | 
			
		||||
 */
 | 
			
		||||
void __libc_fini(void* array)
 | 
			
		||||
{
 | 
			
		||||
    int count;
 | 
			
		||||
    void** fini_array = array;
 | 
			
		||||
    const size_t  minus1 = ~(size_t)0; /* ensure proper sign extension */
 | 
			
		||||
void __libc_fini(void* array) {
 | 
			
		||||
  void** fini_array = array;
 | 
			
		||||
  const size_t minus1 = ~(size_t)0; /* ensure proper sign extension */
 | 
			
		||||
 | 
			
		||||
    /* Sanity check - first entry must be -1 */
 | 
			
		||||
    if (array == NULL || (size_t)fini_array[0] != minus1) {
 | 
			
		||||
        return;
 | 
			
		||||
  /* Sanity check - first entry must be -1 */
 | 
			
		||||
  if (array == NULL || (size_t)fini_array[0] != minus1) {
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /* skip over it */
 | 
			
		||||
  fini_array += 1;
 | 
			
		||||
 | 
			
		||||
  /* Count the number of destructors. */
 | 
			
		||||
  int count = 0;
 | 
			
		||||
  while (fini_array[count] != NULL) {
 | 
			
		||||
    ++count;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /* Now call each destructor in reverse order. */
 | 
			
		||||
  while (count > 0) {
 | 
			
		||||
    void (*func)() = (void (*)) fini_array[--count];
 | 
			
		||||
 | 
			
		||||
    /* Sanity check, any -1 in the list is ignored */
 | 
			
		||||
    if ((size_t)func == minus1) {
 | 
			
		||||
      continue;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* skip over it */
 | 
			
		||||
    fini_array += 1;
 | 
			
		||||
 | 
			
		||||
    /* Count the number of destructors. */
 | 
			
		||||
    for (count = 0; fini_array[count] != NULL; count++);
 | 
			
		||||
 | 
			
		||||
    /* Now call each destructor in reverse order. */
 | 
			
		||||
    while (count > 0) {
 | 
			
		||||
        void (*func)() = (void (*)) fini_array[--count];
 | 
			
		||||
 | 
			
		||||
        /* Sanity check, any -1 in the list is ignored */
 | 
			
		||||
        if ((size_t)func == minus1)
 | 
			
		||||
            continue;
 | 
			
		||||
 | 
			
		||||
        func();
 | 
			
		||||
    }
 | 
			
		||||
    func();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
#ifndef LIBC_STATIC
 | 
			
		||||
    {
 | 
			
		||||
        extern void __libc_postfini(void) __attribute__((weak));
 | 
			
		||||
        if (__libc_postfini)
 | 
			
		||||
            __libc_postfini();
 | 
			
		||||
  {
 | 
			
		||||
    extern void __libc_postfini(void) __attribute__((weak));
 | 
			
		||||
    if (__libc_postfini) {
 | 
			
		||||
      __libc_postfini();
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -105,44 +105,41 @@ static pthread_internal_t* gThreadList = NULL;
 | 
			
		||||
static pthread_mutex_t gThreadListLock = PTHREAD_MUTEX_INITIALIZER;
 | 
			
		||||
static pthread_mutex_t gDebuggerNotificationLock = PTHREAD_MUTEX_INITIALIZER;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
_pthread_internal_free(pthread_internal_t* thread)
 | 
			
		||||
{
 | 
			
		||||
    if (thread != NULL) {
 | 
			
		||||
        free(thread);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
_pthread_internal_remove_locked( pthread_internal_t*  thread )
 | 
			
		||||
{
 | 
			
		||||
static void _pthread_internal_remove_locked(pthread_internal_t* thread) {
 | 
			
		||||
  if (thread->next != NULL) {
 | 
			
		||||
    thread->next->prev = thread->prev;
 | 
			
		||||
    thread->prev[0]    = thread->next;
 | 
			
		||||
  }
 | 
			
		||||
  if (thread->prev != NULL) {
 | 
			
		||||
    thread->prev->next = thread->next;
 | 
			
		||||
  } else {
 | 
			
		||||
    gThreadList = thread->next;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // The main thread is not heap-allocated. See __libc_init_tls for the declaration,
 | 
			
		||||
  // and __libc_init_common for the point where it's added to the thread list.
 | 
			
		||||
  if (thread->allocated_on_heap) {
 | 
			
		||||
    free(thread);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
_pthread_internal_remove( pthread_internal_t*  thread )
 | 
			
		||||
{
 | 
			
		||||
    pthread_mutex_lock(&gThreadListLock);
 | 
			
		||||
    _pthread_internal_remove_locked(thread);
 | 
			
		||||
    pthread_mutex_unlock(&gThreadListLock);
 | 
			
		||||
static void _pthread_internal_remove(pthread_internal_t* thread) {
 | 
			
		||||
  pthread_mutex_lock(&gThreadListLock);
 | 
			
		||||
  _pthread_internal_remove_locked(thread);
 | 
			
		||||
  pthread_mutex_unlock(&gThreadListLock);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
__LIBC_ABI_PRIVATE__ void
 | 
			
		||||
_pthread_internal_add(pthread_internal_t* thread)
 | 
			
		||||
{
 | 
			
		||||
    pthread_mutex_lock(&gThreadListLock);
 | 
			
		||||
__LIBC_ABI_PRIVATE__ void _pthread_internal_add(pthread_internal_t* thread) {
 | 
			
		||||
  pthread_mutex_lock(&gThreadListLock);
 | 
			
		||||
 | 
			
		||||
    thread->prev = &gThreadList;
 | 
			
		||||
    thread->next = *(thread->prev);
 | 
			
		||||
    if (thread->next != NULL) {
 | 
			
		||||
        thread->next->prev = &thread->next;
 | 
			
		||||
    }
 | 
			
		||||
    *(thread->prev) = thread;
 | 
			
		||||
  // We insert at the head.
 | 
			
		||||
  thread->next = gThreadList;
 | 
			
		||||
  thread->prev = NULL;
 | 
			
		||||
  if (thread->next != NULL) {
 | 
			
		||||
    thread->next->prev = thread;
 | 
			
		||||
  }
 | 
			
		||||
  gThreadList = thread;
 | 
			
		||||
 | 
			
		||||
    pthread_mutex_unlock(&gThreadListLock);
 | 
			
		||||
  pthread_mutex_unlock(&gThreadListLock);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
__LIBC_ABI_PRIVATE__ pthread_internal_t*
 | 
			
		||||
@@ -312,6 +309,7 @@ int pthread_create(pthread_t *thread_out, pthread_attr_t const * attr,
 | 
			
		||||
    if (thread == NULL) {
 | 
			
		||||
        return ENOMEM;
 | 
			
		||||
    }
 | 
			
		||||
    thread->allocated_on_heap = true;
 | 
			
		||||
 | 
			
		||||
    if (attr == NULL) {
 | 
			
		||||
        attr = &gDefaultPthreadAttr;
 | 
			
		||||
@@ -323,7 +321,7 @@ int pthread_create(pthread_t *thread_out, pthread_attr_t const * attr,
 | 
			
		||||
    if (stack == NULL) {
 | 
			
		||||
        stack = mkstack(stack_size, attr->guard_size);
 | 
			
		||||
        if (stack == NULL) {
 | 
			
		||||
            _pthread_internal_free(thread);
 | 
			
		||||
            free(thread);
 | 
			
		||||
            return ENOMEM;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@@ -353,7 +351,7 @@ int pthread_create(pthread_t *thread_out, pthread_attr_t const * attr,
 | 
			
		||||
        if (stack != attr->stack_base) {
 | 
			
		||||
            munmap(stack, stack_size);
 | 
			
		||||
        }
 | 
			
		||||
        _pthread_internal_free(thread);
 | 
			
		||||
        free(thread);
 | 
			
		||||
        errno = old_errno;
 | 
			
		||||
        return clone_errno;
 | 
			
		||||
    }
 | 
			
		||||
@@ -585,7 +583,6 @@ void pthread_exit(void * retval)
 | 
			
		||||
    // otherwise, keep it in memory and signal any joiners.
 | 
			
		||||
    if (thread->attr.flags & PTHREAD_ATTR_FLAG_DETACHED) {
 | 
			
		||||
        _pthread_internal_remove(thread);
 | 
			
		||||
        _pthread_internal_free(thread);
 | 
			
		||||
    } else {
 | 
			
		||||
        pthread_mutex_lock(&gThreadListLock);
 | 
			
		||||
 | 
			
		||||
@@ -677,7 +674,6 @@ FoundIt:
 | 
			
		||||
     */
 | 
			
		||||
    if (count <= 0) {
 | 
			
		||||
        _pthread_internal_remove_locked(thread);
 | 
			
		||||
        _pthread_internal_free(thread);
 | 
			
		||||
    }
 | 
			
		||||
    pthread_mutex_unlock(&gThreadListLock);
 | 
			
		||||
    return 0;
 | 
			
		||||
 
 | 
			
		||||
@@ -36,9 +36,10 @@ __BEGIN_DECLS
 | 
			
		||||
typedef struct pthread_internal_t
 | 
			
		||||
{
 | 
			
		||||
    struct pthread_internal_t*  next;
 | 
			
		||||
    struct pthread_internal_t** prev;
 | 
			
		||||
    struct pthread_internal_t*  prev;
 | 
			
		||||
    pthread_attr_t              attr;
 | 
			
		||||
    pid_t                       kernel_id;
 | 
			
		||||
    bool                        allocated_on_heap;
 | 
			
		||||
    pthread_cond_t              join_cond;
 | 
			
		||||
    int                         join_count;
 | 
			
		||||
    void*                       return_value;
 | 
			
		||||
 
 | 
			
		||||
@@ -109,3 +109,20 @@ TEST(pthread, pthread_join_self) {
 | 
			
		||||
  void* result;
 | 
			
		||||
  ASSERT_EQ(EDEADLK, pthread_join(pthread_self(), &result));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#if __BIONIC__ // For some reason, gtest on bionic can cope with this but gtest on glibc can't.
 | 
			
		||||
 | 
			
		||||
static void TestBug37410() {
 | 
			
		||||
  pthread_t t1;
 | 
			
		||||
  ASSERT_EQ(0, pthread_create(&t1, NULL, JoinFn, reinterpret_cast<void*>(pthread_self())));
 | 
			
		||||
  pthread_exit(NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// We have to say "DeathTest" here so gtest knows to run this test (which exits)
 | 
			
		||||
// in its own process.
 | 
			
		||||
TEST(pthread_DeathTest, pthread_bug_37410) {
 | 
			
		||||
  // http://code.google.com/p/android/issues/detail?id=37410
 | 
			
		||||
  ::testing::FLAGS_gtest_death_test_style = "threadsafe";
 | 
			
		||||
  EXPECT_EXIT(TestBug37410(), ::testing::ExitedWithCode(0), "");
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user