am 41ff8b98: am 6e3b0f2d: Merge "Don\'t corrupt the thread list in static executables."

* commit '41ff8b98044de19d6ea5228452c2d555c4224da7':
  Don't corrupt the thread list in static executables.
This commit is contained in:
Elliott Hughes 2012-09-06 10:44:13 -07:00 committed by Android Git Automerger
commit de0dc25112
6 changed files with 69 additions and 24 deletions

View File

@ -76,7 +76,7 @@ void __libc_init_tls(unsigned** elfdata)
pthread_attr_init(&thread_attr);
pthread_attr_setstack(&thread_attr, (void*)stackbottom, stacksize);
_init_thread(&thread, gettid(), &thread_attr, (void*)stackbottom);
_init_thread(&thread, gettid(), &thread_attr, (void*)stackbottom, false);
__init_tls(tls_area, &thread);
tls_area[TLS_SLOT_BIONIC_PREINIT] = elfdata;

View File

@ -67,9 +67,6 @@ __noreturn void __libc_init(uintptr_t *elfdata,
__libc_init_tls(NULL);
/* get the initial thread from TLS and add it to gThreadList */
_pthread_internal_add(__get_thread());
/* Initialize the C runtime environment */
__libc_init_common(elfdata);

View File

@ -117,8 +117,8 @@ _pthread_internal_free(pthread_internal_t* thread)
static void
_pthread_internal_remove_locked( pthread_internal_t* thread )
{
thread->next->pref = thread->pref;
thread->pref[0] = thread->next;
thread->next->prev = thread->prev;
thread->prev[0] = thread->next;
}
static void
@ -130,14 +130,17 @@ _pthread_internal_remove( pthread_internal_t* thread )
}
__LIBC_ABI_PRIVATE__ void
_pthread_internal_add( pthread_internal_t* thread )
_pthread_internal_add(pthread_internal_t* thread)
{
pthread_mutex_lock(&gThreadListLock);
thread->pref = &gThreadList;
thread->next = thread->pref[0];
if (thread->next)
thread->next->pref = &thread->next;
thread->pref[0] = thread;
thread->prev = &gThreadList;
thread->next = *(thread->prev);
if (thread->next != NULL) {
thread->next->prev = &thread->next;
}
*(thread->prev) = thread;
pthread_mutex_unlock(&gThreadListLock);
}
@ -203,7 +206,8 @@ void __thread_entry(int (*func)(void*), void *arg, void **tls)
}
__LIBC_ABI_PRIVATE__
int _init_thread(pthread_internal_t * thread, pid_t kernel_id, pthread_attr_t * attr, void * stack_base)
int _init_thread(pthread_internal_t* thread, pid_t kernel_id, pthread_attr_t* attr,
void* stack_base, bool add_to_thread_list)
{
int error = 0;
@ -231,10 +235,12 @@ int _init_thread(pthread_internal_t * thread, pid_t kernel_id, pthread_attr_t *
pthread_cond_init(&thread->join_cond, NULL);
thread->join_count = 0;
thread->cleanup_stack = NULL;
_pthread_internal_add(thread);
if (add_to_thread_list) {
_pthread_internal_add(thread);
}
return error;
}
@ -348,7 +354,7 @@ int pthread_create(pthread_t *thread_out, pthread_attr_t const * attr,
return clone_errno;
}
int init_errno = _init_thread(thread, tid, (pthread_attr_t*) attr, stack);
int init_errno = _init_thread(thread, tid, (pthread_attr_t*) attr, stack, true);
if (init_errno != 0) {
// Mark the thread detached and let its __thread_entry run to
// completion. (It'll just exit immediately, cleaning up its resources.)
@ -1919,8 +1925,8 @@ int pthread_key_create(pthread_key_t *key, void (*destructor_function)(void *))
/* This deletes a pthread_key_t. note that the standard mandates that this does
* not call the destructor of non-NULL key values. Instead, it is the
* responsability of the caller to properly dispose of the corresponding data
* and resources, using any mean it finds suitable.
* responsibility of the caller to properly dispose of the corresponding data
* and resources, using any means it finds suitable.
*
* On the other hand, this function will clear the corresponding key data
* values in all known threads. this prevents later (invalid) calls to
@ -2184,7 +2190,7 @@ int pthread_once( pthread_once_t* once_control, void (*init_routine)(void) )
for (;;) {
/* Try to atomically set the INITIALIZING flag.
* This requires a cmpxchg loop, and we may need
* to exit prematurely if we detect that
* to exit prematurely if we detect that
* COMPLETED is now set.
*/
int32_t oldval, newval;

View File

@ -29,13 +29,14 @@
#define _PTHREAD_INTERNAL_H_
#include <pthread.h>
#include <stdbool.h>
__BEGIN_DECLS
typedef struct pthread_internal_t
{
struct pthread_internal_t* next;
struct pthread_internal_t** pref;
struct pthread_internal_t** prev;
pthread_attr_t attr;
pid_t kernel_id;
pthread_cond_t join_cond;
@ -46,7 +47,8 @@ typedef struct pthread_internal_t
void** tls; /* thread-local storage area */
} pthread_internal_t;
extern int _init_thread(pthread_internal_t * thread, pid_t kernel_id, pthread_attr_t * attr, void * stack_base);
int _init_thread(pthread_internal_t* thread, pid_t kernel_id, pthread_attr_t* attr,
void* stack_base, bool add_to_thread_list);
void _pthread_internal_add( pthread_internal_t* thread );
pthread_internal_t* __get_thread(void);
@ -100,9 +102,9 @@ static __inline__ int timespec_cmp0( const struct timespec* a )
return 0;
}
extern int __pthread_cond_timedwait(pthread_cond_t*,
extern int __pthread_cond_timedwait(pthread_cond_t*,
pthread_mutex_t*,
const struct timespec*,
const struct timespec*,
clockid_t);
extern int __pthread_cond_timedwait_relative(pthread_cond_t*,

View File

@ -20,9 +20,10 @@ LOCAL_PATH := $(call my-dir)
test_src_files = \
getcwd_test.cpp \
pthread_test.cpp \
regex_test.cpp \
# Build for the device (with bionic). Run with:
# Build for the device (with bionic's .so). Run with:
# adb shell /data/nativetest/bionic-unit-tests/bionic-unit-tests
include $(CLEAR_VARS)
LOCAL_MODULE := bionic-unit-tests
@ -30,6 +31,16 @@ LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
LOCAL_SRC_FILES := $(test_src_files)
include $(BUILD_NATIVE_TEST)
# Build for the device (with bionic's .a). Run with:
# adb shell /data/nativetest/bionic-unit-tests-static/bionic-unit-tests-static
include $(CLEAR_VARS)
LOCAL_FORCE_STATIC_EXECUTABLE := true
LOCAL_STATIC_LIBRARIES += libstlport_static libstdc++ libm libc
LOCAL_MODULE := bionic-unit-tests-static
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
LOCAL_SRC_FILES := $(test_src_files)
include $(BUILD_NATIVE_TEST)
# Build for the host (with glibc).
# Note that this will build against glibc, so it's not useful for testing
# bionic's implementation, but it does let you use glibc as a reference
@ -37,6 +48,7 @@ include $(BUILD_NATIVE_TEST)
include $(CLEAR_VARS)
LOCAL_MODULE := bionic-unit-tests-glibc
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
LOCAL_LDFLAGS += -lpthread
LOCAL_SRC_FILES := $(test_src_files)
include $(BUILD_HOST_NATIVE_TEST)

28
tests/pthread_test.cpp Normal file
View File

@ -0,0 +1,28 @@
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <gtest/gtest.h>
#include <errno.h>
#include <pthread.h>
TEST(pthread, pthread_key_create) {
pthread_key_t key;
ASSERT_EQ(0, pthread_key_create(&key, NULL));
ASSERT_EQ(0, pthread_key_delete(key));
// Can't delete a key that's already been deleted.
ASSERT_EQ(EINVAL, pthread_key_delete(key));
}