am de0dc251
: am 41ff8b98
: am 6e3b0f2d
: Merge "Don\'t corrupt the thread list in static executables."
* commit 'de0dc251120e03622d89d7af2ce44530d665e065': Don't corrupt the thread list in static executables.
This commit is contained in:
commit
684669dfd7
@ -76,7 +76,7 @@ void __libc_init_tls(unsigned** elfdata)
|
|||||||
|
|
||||||
pthread_attr_init(&thread_attr);
|
pthread_attr_init(&thread_attr);
|
||||||
pthread_attr_setstack(&thread_attr, (void*)stackbottom, stacksize);
|
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);
|
__init_tls(tls_area, &thread);
|
||||||
|
|
||||||
tls_area[TLS_SLOT_BIONIC_PREINIT] = elfdata;
|
tls_area[TLS_SLOT_BIONIC_PREINIT] = elfdata;
|
||||||
|
@ -67,9 +67,6 @@ __noreturn void __libc_init(uintptr_t *elfdata,
|
|||||||
|
|
||||||
__libc_init_tls(NULL);
|
__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 */
|
/* Initialize the C runtime environment */
|
||||||
__libc_init_common(elfdata);
|
__libc_init_common(elfdata);
|
||||||
|
|
||||||
|
@ -117,8 +117,8 @@ _pthread_internal_free(pthread_internal_t* thread)
|
|||||||
static void
|
static void
|
||||||
_pthread_internal_remove_locked( pthread_internal_t* thread )
|
_pthread_internal_remove_locked( pthread_internal_t* thread )
|
||||||
{
|
{
|
||||||
thread->next->pref = thread->pref;
|
thread->next->prev = thread->prev;
|
||||||
thread->pref[0] = thread->next;
|
thread->prev[0] = thread->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -130,14 +130,17 @@ _pthread_internal_remove( pthread_internal_t* thread )
|
|||||||
}
|
}
|
||||||
|
|
||||||
__LIBC_ABI_PRIVATE__ void
|
__LIBC_ABI_PRIVATE__ void
|
||||||
_pthread_internal_add( pthread_internal_t* thread )
|
_pthread_internal_add(pthread_internal_t* thread)
|
||||||
{
|
{
|
||||||
pthread_mutex_lock(&gThreadListLock);
|
pthread_mutex_lock(&gThreadListLock);
|
||||||
thread->pref = &gThreadList;
|
|
||||||
thread->next = thread->pref[0];
|
thread->prev = &gThreadList;
|
||||||
if (thread->next)
|
thread->next = *(thread->prev);
|
||||||
thread->next->pref = &thread->next;
|
if (thread->next != NULL) {
|
||||||
thread->pref[0] = thread;
|
thread->next->prev = &thread->next;
|
||||||
|
}
|
||||||
|
*(thread->prev) = thread;
|
||||||
|
|
||||||
pthread_mutex_unlock(&gThreadListLock);
|
pthread_mutex_unlock(&gThreadListLock);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -203,7 +206,8 @@ void __thread_entry(int (*func)(void*), void *arg, void **tls)
|
|||||||
}
|
}
|
||||||
|
|
||||||
__LIBC_ABI_PRIVATE__
|
__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;
|
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);
|
pthread_cond_init(&thread->join_cond, NULL);
|
||||||
thread->join_count = 0;
|
thread->join_count = 0;
|
||||||
|
|
||||||
thread->cleanup_stack = NULL;
|
thread->cleanup_stack = NULL;
|
||||||
|
|
||||||
_pthread_internal_add(thread);
|
if (add_to_thread_list) {
|
||||||
|
_pthread_internal_add(thread);
|
||||||
|
}
|
||||||
|
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -348,7 +354,7 @@ int pthread_create(pthread_t *thread_out, pthread_attr_t const * attr,
|
|||||||
return clone_errno;
|
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) {
|
if (init_errno != 0) {
|
||||||
// Mark the thread detached and let its __thread_entry run to
|
// Mark the thread detached and let its __thread_entry run to
|
||||||
// completion. (It'll just exit immediately, cleaning up its resources.)
|
// 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
|
/* 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
|
* not call the destructor of non-NULL key values. Instead, it is the
|
||||||
* responsability of the caller to properly dispose of the corresponding data
|
* responsibility of the caller to properly dispose of the corresponding data
|
||||||
* and resources, using any mean it finds suitable.
|
* and resources, using any means it finds suitable.
|
||||||
*
|
*
|
||||||
* On the other hand, this function will clear the corresponding key data
|
* On the other hand, this function will clear the corresponding key data
|
||||||
* values in all known threads. this prevents later (invalid) calls to
|
* 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 (;;) {
|
for (;;) {
|
||||||
/* Try to atomically set the INITIALIZING flag.
|
/* Try to atomically set the INITIALIZING flag.
|
||||||
* This requires a cmpxchg loop, and we may need
|
* 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.
|
* COMPLETED is now set.
|
||||||
*/
|
*/
|
||||||
int32_t oldval, newval;
|
int32_t oldval, newval;
|
||||||
|
@ -29,13 +29,14 @@
|
|||||||
#define _PTHREAD_INTERNAL_H_
|
#define _PTHREAD_INTERNAL_H_
|
||||||
|
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
__BEGIN_DECLS
|
__BEGIN_DECLS
|
||||||
|
|
||||||
typedef struct pthread_internal_t
|
typedef struct pthread_internal_t
|
||||||
{
|
{
|
||||||
struct pthread_internal_t* next;
|
struct pthread_internal_t* next;
|
||||||
struct pthread_internal_t** pref;
|
struct pthread_internal_t** prev;
|
||||||
pthread_attr_t attr;
|
pthread_attr_t attr;
|
||||||
pid_t kernel_id;
|
pid_t kernel_id;
|
||||||
pthread_cond_t join_cond;
|
pthread_cond_t join_cond;
|
||||||
@ -46,7 +47,8 @@ typedef struct pthread_internal_t
|
|||||||
void** tls; /* thread-local storage area */
|
void** tls; /* thread-local storage area */
|
||||||
} pthread_internal_t;
|
} 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 );
|
void _pthread_internal_add( pthread_internal_t* thread );
|
||||||
pthread_internal_t* __get_thread(void);
|
pthread_internal_t* __get_thread(void);
|
||||||
|
|
||||||
@ -100,9 +102,9 @@ static __inline__ int timespec_cmp0( const struct timespec* a )
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern int __pthread_cond_timedwait(pthread_cond_t*,
|
extern int __pthread_cond_timedwait(pthread_cond_t*,
|
||||||
pthread_mutex_t*,
|
pthread_mutex_t*,
|
||||||
const struct timespec*,
|
const struct timespec*,
|
||||||
clockid_t);
|
clockid_t);
|
||||||
|
|
||||||
extern int __pthread_cond_timedwait_relative(pthread_cond_t*,
|
extern int __pthread_cond_timedwait_relative(pthread_cond_t*,
|
||||||
|
@ -20,9 +20,10 @@ LOCAL_PATH := $(call my-dir)
|
|||||||
|
|
||||||
test_src_files = \
|
test_src_files = \
|
||||||
getcwd_test.cpp \
|
getcwd_test.cpp \
|
||||||
|
pthread_test.cpp \
|
||||||
regex_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
|
# adb shell /data/nativetest/bionic-unit-tests/bionic-unit-tests
|
||||||
include $(CLEAR_VARS)
|
include $(CLEAR_VARS)
|
||||||
LOCAL_MODULE := bionic-unit-tests
|
LOCAL_MODULE := bionic-unit-tests
|
||||||
@ -30,6 +31,16 @@ LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
|
|||||||
LOCAL_SRC_FILES := $(test_src_files)
|
LOCAL_SRC_FILES := $(test_src_files)
|
||||||
include $(BUILD_NATIVE_TEST)
|
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).
|
# Build for the host (with glibc).
|
||||||
# Note that this will build against glibc, so it's not useful for testing
|
# 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
|
# bionic's implementation, but it does let you use glibc as a reference
|
||||||
@ -37,6 +48,7 @@ include $(BUILD_NATIVE_TEST)
|
|||||||
include $(CLEAR_VARS)
|
include $(CLEAR_VARS)
|
||||||
LOCAL_MODULE := bionic-unit-tests-glibc
|
LOCAL_MODULE := bionic-unit-tests-glibc
|
||||||
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
|
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
|
||||||
|
LOCAL_LDFLAGS += -lpthread
|
||||||
LOCAL_SRC_FILES := $(test_src_files)
|
LOCAL_SRC_FILES := $(test_src_files)
|
||||||
include $(BUILD_HOST_NATIVE_TEST)
|
include $(BUILD_HOST_NATIVE_TEST)
|
||||||
|
|
||||||
|
28
tests/pthread_test.cpp
Normal file
28
tests/pthread_test.cpp
Normal 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));
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user