diff --git a/libc/Android.mk b/libc/Android.mk index 623bda240..d21878ae8 100644 --- a/libc/Android.mk +++ b/libc/Android.mk @@ -279,8 +279,6 @@ libc_bionic_src_files := \ bionic/__memcpy_chk.cpp \ bionic/__memmove_chk.cpp \ bionic/__memset_chk.cpp \ - bionic/pthread_attr.cpp \ - bionic/pthread_setname_np.cpp \ bionic/pthread_sigmask.cpp \ bionic/raise.cpp \ bionic/sbrk.cpp \ diff --git a/libc/bionic/dirent.cpp b/libc/bionic/dirent.cpp index 74297d821..3a7b5b414 100644 --- a/libc/bionic/dirent.cpp +++ b/libc/bionic/dirent.cpp @@ -36,8 +36,7 @@ #include #include -#include "private/ErrnoRestorer.h" -#include "private/ScopedPthreadMutexLocker.h" +#include struct DIR { int fd_; @@ -109,7 +108,7 @@ dirent* readdir(DIR* d) { } int readdir_r(DIR* d, dirent* entry, dirent** result) { - ErrnoRestorer errno_restorer; + int saved_errno = errno; *result = NULL; errno = 0; @@ -125,6 +124,7 @@ int readdir_r(DIR* d, dirent* entry, dirent** result) { memcpy(entry, next, next->d_reclen); *result = entry; } + errno = saved_errno; return 0; } diff --git a/libc/bionic/pthread.c b/libc/bionic/pthread.c index bdf2b8766..e1ace7dc2 100644 --- a/libc/bionic/pthread.c +++ b/libc/bionic/pthread.c @@ -26,12 +26,23 @@ * SUCH DAMAGE. */ -#include - +#include #include +#include #include +#include +#include +#include +#include +#include +#include +#include #include #include +#include +#include +#include +#include #include #include "bionic_atomic_inline.h" @@ -73,8 +84,23 @@ void ATTRIBUTES _thread_created_hook(pid_t thread_id); static const int kPthreadInitFailed = 1; +#define PTHREAD_ATTR_FLAG_DETACHED 0x00000001 +#define PTHREAD_ATTR_FLAG_USER_STACK 0x00000002 + +#define DEFAULT_STACKSIZE (1024 * 1024) + static pthread_mutex_t mmap_lock = PTHREAD_MUTEX_INITIALIZER; + +static const pthread_attr_t gDefaultPthreadAttr = { + .flags = 0, + .stack_base = NULL, + .stack_size = DEFAULT_STACKSIZE, + .guard_size = PAGE_SIZE, + .sched_policy = SCHED_NORMAL, + .sched_priority = 0 +}; + __LIBC_HIDDEN__ pthread_internal_t* gThreadList = NULL; __LIBC_HIDDEN__ pthread_mutex_t gThreadListLock = PTHREAD_MUTEX_INITIALIZER; static pthread_mutex_t gDebuggerNotificationLock = PTHREAD_MUTEX_INITIALIZER; @@ -280,7 +306,7 @@ int pthread_create(pthread_t *thread_out, pthread_attr_t const * attr, pthread_internal_t* thread = calloc(sizeof(*thread), 1); if (thread == NULL) { - return EAGAIN; + return ENOMEM; } thread->allocated_on_heap = true; @@ -295,7 +321,7 @@ int pthread_create(pthread_t *thread_out, pthread_attr_t const * attr, stack = mkstack(stack_size, attr->guard_size); if (stack == NULL) { free(thread); - return EAGAIN; + return ENOMEM; } } @@ -353,6 +379,152 @@ int pthread_create(pthread_t *thread_out, pthread_attr_t const * attr, } +int pthread_attr_init(pthread_attr_t * attr) +{ + *attr = gDefaultPthreadAttr; + return 0; +} + +int pthread_attr_destroy(pthread_attr_t * attr) +{ + memset(attr, 0x42, sizeof(pthread_attr_t)); + return 0; +} + +int pthread_attr_setdetachstate(pthread_attr_t * attr, int state) +{ + if (state == PTHREAD_CREATE_DETACHED) { + attr->flags |= PTHREAD_ATTR_FLAG_DETACHED; + } else if (state == PTHREAD_CREATE_JOINABLE) { + attr->flags &= ~PTHREAD_ATTR_FLAG_DETACHED; + } else { + return EINVAL; + } + return 0; +} + +int pthread_attr_getdetachstate(pthread_attr_t const * attr, int * state) +{ + *state = (attr->flags & PTHREAD_ATTR_FLAG_DETACHED) + ? PTHREAD_CREATE_DETACHED + : PTHREAD_CREATE_JOINABLE; + return 0; +} + +int pthread_attr_setschedpolicy(pthread_attr_t * attr, int policy) +{ + attr->sched_policy = policy; + return 0; +} + +int pthread_attr_getschedpolicy(pthread_attr_t const * attr, int * policy) +{ + *policy = attr->sched_policy; + return 0; +} + +int pthread_attr_setschedparam(pthread_attr_t * attr, struct sched_param const * param) +{ + attr->sched_priority = param->sched_priority; + return 0; +} + +int pthread_attr_getschedparam(pthread_attr_t const * attr, struct sched_param * param) +{ + param->sched_priority = attr->sched_priority; + return 0; +} + +int pthread_attr_setstacksize(pthread_attr_t * attr, size_t stack_size) +{ + if ((stack_size & (PAGE_SIZE - 1) || stack_size < PTHREAD_STACK_MIN)) { + return EINVAL; + } + attr->stack_size = stack_size; + return 0; +} + +int pthread_attr_getstacksize(pthread_attr_t const * attr, size_t * stack_size) +{ + *stack_size = attr->stack_size; + return 0; +} + +int pthread_attr_setstackaddr(pthread_attr_t * attr __attribute__((unused)), + void * stack_addr __attribute__((unused))) +{ + // This was removed from POSIX.1-2008, and is not implemented on bionic. + // Needed for ABI compatibility with the NDK. + return ENOSYS; +} + +int pthread_attr_getstackaddr(pthread_attr_t const * attr, void ** stack_addr) +{ + // This was removed from POSIX.1-2008. + // Needed for ABI compatibility with the NDK. + *stack_addr = (char*)attr->stack_base + attr->stack_size; + return 0; +} + +int pthread_attr_setstack(pthread_attr_t * attr, void * stack_base, size_t stack_size) +{ + if ((stack_size & (PAGE_SIZE - 1) || stack_size < PTHREAD_STACK_MIN)) { + return EINVAL; + } + if ((uint32_t)stack_base & (PAGE_SIZE - 1)) { + return EINVAL; + } + attr->stack_base = stack_base; + attr->stack_size = stack_size; + return 0; +} + +int pthread_attr_getstack(pthread_attr_t const * attr, void ** stack_base, size_t * stack_size) +{ + *stack_base = attr->stack_base; + *stack_size = attr->stack_size; + return 0; +} + +int pthread_attr_setguardsize(pthread_attr_t * attr, size_t guard_size) +{ + if (guard_size & (PAGE_SIZE - 1) || guard_size < PAGE_SIZE) { + return EINVAL; + } + + attr->guard_size = guard_size; + return 0; +} + +int pthread_attr_getguardsize(pthread_attr_t const * attr, size_t * guard_size) +{ + *guard_size = attr->guard_size; + return 0; +} + +int pthread_getattr_np(pthread_t thid, pthread_attr_t * attr) +{ + pthread_internal_t * thread = (pthread_internal_t *)thid; + *attr = thread->attr; + return 0; +} + +int pthread_attr_setscope(pthread_attr_t *attr __attribute__((unused)), int scope) +{ + if (scope == PTHREAD_SCOPE_SYSTEM) + return 0; + if (scope == PTHREAD_SCOPE_PROCESS) + return ENOTSUP; + + return EINVAL; +} + +int pthread_attr_getscope(pthread_attr_t const *attr __attribute__((unused))) +{ + return PTHREAD_SCOPE_SYSTEM; +} + + /* CAVEAT: our implementation of pthread_cleanup_push/pop doesn't support C++ exceptions * and thread cancelation */ @@ -1709,6 +1881,57 @@ int pthread_once( pthread_once_t* once_control, void (*init_routine)(void) ) return 0; } +/* This value is not exported by kernel headers, so hardcode it here */ +#define MAX_TASK_COMM_LEN 16 +#define TASK_COMM_FMT "/proc/self/task/%u/comm" + +int pthread_setname_np(pthread_t thid, const char *thname) +{ + size_t thname_len; + int saved_errno, ret; + + if (thid == 0 || thname == NULL) + return EINVAL; + + thname_len = strlen(thname); + if (thname_len >= MAX_TASK_COMM_LEN) + return ERANGE; + + saved_errno = errno; + if (thid == pthread_self()) + { + ret = prctl(PR_SET_NAME, (unsigned long)thname, 0, 0, 0) ? errno : 0; + } + else + { + /* Have to change another thread's name */ + pthread_internal_t *thread = (pthread_internal_t *)thid; + char comm_name[sizeof(TASK_COMM_FMT) + 8]; + ssize_t n; + int fd; + + snprintf(comm_name, sizeof(comm_name), TASK_COMM_FMT, (unsigned int)thread->kernel_id); + fd = open(comm_name, O_RDWR); + if (fd == -1) + { + ret = errno; + goto exit; + } + n = TEMP_FAILURE_RETRY(write(fd, thname, thname_len)); + close(fd); + + if (n < 0) + ret = errno; + else if ((size_t)n != thname_len) + ret = EIO; + else + ret = 0; + } +exit: + errno = saved_errno; + return ret; +} + /* Return the kernel thread ID for a pthread. * This is only defined for implementations where pthread <-> kernel is 1:1, which this is. * Not the same as pthread_getthreadid_np, which is commonly defined to be opaque. diff --git a/libc/bionic/pthread_attr.cpp b/libc/bionic/pthread_attr.cpp deleted file mode 100644 index 831a28e14..000000000 --- a/libc/bionic/pthread_attr.cpp +++ /dev/null @@ -1,165 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include - -#include "pthread_internal.h" - -#define DEFAULT_STACKSIZE (1024 * 1024) - -const pthread_attr_t gDefaultPthreadAttr = { - .flags = 0, - .stack_base = NULL, - .stack_size = DEFAULT_STACKSIZE, - .guard_size = PAGE_SIZE, - .sched_policy = SCHED_NORMAL, - .sched_priority = 0 -}; - -int pthread_attr_init(pthread_attr_t* attr) { - *attr = gDefaultPthreadAttr; - return 0; -} - -int pthread_attr_destroy(pthread_attr_t* attr) { - memset(attr, 0x42, sizeof(pthread_attr_t)); - return 0; -} - -int pthread_attr_setdetachstate(pthread_attr_t* attr, int state) { - if (state == PTHREAD_CREATE_DETACHED) { - attr->flags |= PTHREAD_ATTR_FLAG_DETACHED; - } else if (state == PTHREAD_CREATE_JOINABLE) { - attr->flags &= ~PTHREAD_ATTR_FLAG_DETACHED; - } else { - return EINVAL; - } - return 0; -} - -int pthread_attr_getdetachstate(pthread_attr_t const* attr, int* state) { - *state = (attr->flags & PTHREAD_ATTR_FLAG_DETACHED) ? PTHREAD_CREATE_DETACHED : PTHREAD_CREATE_JOINABLE; - return 0; -} - -int pthread_attr_setschedpolicy(pthread_attr_t* attr, int policy) { - attr->sched_policy = policy; - return 0; -} - -int pthread_attr_getschedpolicy(pthread_attr_t const* attr, int* policy) { - *policy = attr->sched_policy; - return 0; -} - -int pthread_attr_setschedparam(pthread_attr_t * attr, struct sched_param const* param) { - attr->sched_priority = param->sched_priority; - return 0; -} - -int pthread_attr_getschedparam(pthread_attr_t const* attr, struct sched_param* param) { - param->sched_priority = attr->sched_priority; - return 0; -} - -int pthread_attr_setstacksize(pthread_attr_t* attr, size_t stack_size) { - if ((stack_size & (PAGE_SIZE - 1) || stack_size < PTHREAD_STACK_MIN)) { - return EINVAL; - } - attr->stack_size = stack_size; - return 0; -} - -int pthread_attr_getstacksize(pthread_attr_t const* attr, size_t* stack_size) { - *stack_size = attr->stack_size; - return 0; -} - -int pthread_attr_setstackaddr(pthread_attr_t*, void*) { - // This was removed from POSIX.1-2008, and is not implemented on bionic. - // Needed for ABI compatibility with the NDK. - return ENOSYS; -} - -int pthread_attr_getstackaddr(pthread_attr_t const* attr, void** stack_addr) { - // This was removed from POSIX.1-2008. - // Needed for ABI compatibility with the NDK. - *stack_addr = (char*)attr->stack_base + attr->stack_size; - return 0; -} - -int pthread_attr_setstack(pthread_attr_t* attr, void* stack_base, size_t stack_size) { - if ((stack_size & (PAGE_SIZE - 1) || stack_size < PTHREAD_STACK_MIN)) { - return EINVAL; - } - if ((uint32_t)stack_base & (PAGE_SIZE - 1)) { - return EINVAL; - } - attr->stack_base = stack_base; - attr->stack_size = stack_size; - return 0; -} - -int pthread_attr_getstack(pthread_attr_t const* attr, void** stack_base, size_t* stack_size) { - *stack_base = attr->stack_base; - *stack_size = attr->stack_size; - return 0; -} - -int pthread_attr_setguardsize(pthread_attr_t* attr, size_t guard_size) { - if (guard_size & (PAGE_SIZE - 1) || guard_size < PAGE_SIZE) { - return EINVAL; - } - attr->guard_size = guard_size; - return 0; -} - -int pthread_attr_getguardsize(pthread_attr_t const* attr, size_t* guard_size) { - *guard_size = attr->guard_size; - return 0; -} - -int pthread_getattr_np(pthread_t thid, pthread_attr_t* attr) { - pthread_internal_t* thread = (pthread_internal_t*) thid; - *attr = thread->attr; - return 0; -} - -int pthread_attr_setscope(pthread_attr_t* , int scope) { - if (scope == PTHREAD_SCOPE_SYSTEM) { - return 0; - } - if (scope == PTHREAD_SCOPE_PROCESS) { - return ENOTSUP; - } - return EINVAL; -} - -int pthread_attr_getscope(pthread_attr_t const*) { - return PTHREAD_SCOPE_SYSTEM; -} diff --git a/libc/bionic/pthread_internal.h b/libc/bionic/pthread_internal.h index 63071d982..24b420cf7 100644 --- a/libc/bionic/pthread_internal.h +++ b/libc/bionic/pthread_internal.h @@ -62,10 +62,6 @@ pthread_internal_t* __get_thread(void); __LIBC_HIDDEN__ void pthread_key_clean_all(void); -#define PTHREAD_ATTR_FLAG_DETACHED 0x00000001 -#define PTHREAD_ATTR_FLAG_USER_STACK 0x00000002 - -extern __LIBC_HIDDEN__ const pthread_attr_t gDefaultPthreadAttr; extern pthread_internal_t* gThreadList; extern pthread_mutex_t gThreadListLock; diff --git a/libc/bionic/pthread_key.cpp b/libc/bionic/pthread_key.cpp index b01f9bd4f..00dacba96 100644 --- a/libc/bionic/pthread_key.cpp +++ b/libc/bionic/pthread_key.cpp @@ -26,10 +26,33 @@ * SUCH DAMAGE. */ +#include +#include +#include +#include +#include +#include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "bionic_atomic_inline.h" +#include "bionic_futex.h" +#include "bionic_pthread.h" +#include "bionic_ssp.h" #include "bionic_tls.h" +#include "debug_format.h" #include "pthread_internal.h" +#include "thread_private.h" /* A technical note regarding our thread-local-storage (TLS) implementation: * diff --git a/libc/bionic/pthread_setname_np.cpp b/libc/bionic/pthread_setname_np.cpp deleted file mode 100644 index 88b86ec1f..000000000 --- a/libc/bionic/pthread_setname_np.cpp +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include - -#include -#include // For snprintf. -#include -#include -#include -#include - -#include "pthread_internal.h" -#include "private/ErrnoRestorer.h" - -// This value is not exported by kernel headers. -#define MAX_TASK_COMM_LEN 16 -#define TASK_COMM_FMT "/proc/self/task/%u/comm" - -int pthread_setname_np(pthread_t thread, const char* thread_name) { - ErrnoRestorer errno_restorer; - - if (thread == 0 || thread_name == NULL) { - return EINVAL; - } - - size_t thread_name_len = strlen(thread_name); - if (thread_name_len >= MAX_TASK_COMM_LEN) { - return ERANGE; - } - - // Changing our own name is an easy special case. - if (thread == pthread_self()) { - return prctl(PR_SET_NAME, (unsigned long)thread_name, 0, 0, 0) ? errno : 0; - } - - // Have to change another thread's name. - pthread_internal_t* t = reinterpret_cast(thread); - char comm_name[sizeof(TASK_COMM_FMT) + 8]; - snprintf(comm_name, sizeof(comm_name), TASK_COMM_FMT, (unsigned int) t->kernel_id); - int fd = open(comm_name, O_RDWR); - if (fd == -1) { - return errno; - } - ssize_t n = TEMP_FAILURE_RETRY(write(fd, thread_name, thread_name_len)); - close(fd); - - if (n < 0) { - return errno; - } else if ((size_t)n != thread_name_len) { - return EIO; - } - return 0; -} diff --git a/libc/bionic/pthread_sigmask.cpp b/libc/bionic/pthread_sigmask.cpp index e4e1b2b98..9c9dc3ed8 100644 --- a/libc/bionic/pthread_sigmask.cpp +++ b/libc/bionic/pthread_sigmask.cpp @@ -30,13 +30,12 @@ #include #include -#include "private/ErrnoRestorer.h" -#include "private/kernel_sigset_t.h" +#include extern "C" int __rt_sigprocmask(int, const kernel_sigset_t*, kernel_sigset_t*, size_t); int pthread_sigmask(int how, const sigset_t* iset, sigset_t* oset) { - ErrnoRestorer errno_restorer; + int old_errno = errno; // 'in_set_ptr' is the second parameter to __rt_sigprocmask. It must be NULL // if 'set' is NULL to ensure correct semantics (which in this case would @@ -49,13 +48,15 @@ int pthread_sigmask(int how, const sigset_t* iset, sigset_t* oset) { } kernel_sigset_t out_set; - if (__rt_sigprocmask(how, in_set_ptr, &out_set, sizeof(out_set)) == -1) { - return errno; + int result = __rt_sigprocmask(how, in_set_ptr, &out_set, sizeof(out_set)); + if (result < 0) { + result = errno; } if (oset != NULL) { *oset = out_set.bionic; } - return 0; + errno = old_errno; + return result; } diff --git a/libc/bionic/strerror_r.cpp b/libc/bionic/strerror_r.cpp index 81120ecd3..646cc5239 100644 --- a/libc/bionic/strerror_r.cpp +++ b/libc/bionic/strerror_r.cpp @@ -7,8 +7,6 @@ #include #include -#include "private/ErrnoRestorer.h" - struct Pair { int code; const char* msg; @@ -44,7 +42,7 @@ extern "C" __LIBC_HIDDEN__ const char* __strsignal_lookup(int signal_number) { } int strerror_r(int error_number, char* buf, size_t buf_len) { - ErrnoRestorer errno_restorer; + int saved_errno = errno; size_t length; const char* error_name = __strerror_lookup(error_number); @@ -54,10 +52,11 @@ int strerror_r(int error_number, char* buf, size_t buf_len) { length = snprintf(buf, buf_len, "Unknown error %d", error_number); } if (length >= buf_len) { - errno_restorer.override(ERANGE); + errno = ERANGE; return -1; } + errno = saved_errno; return 0; } diff --git a/libc/bionic/stubs.cpp b/libc/bionic/stubs.cpp index 8ddc326e0..3f24d1bd5 100644 --- a/libc/bionic/stubs.cpp +++ b/libc/bionic/stubs.cpp @@ -31,17 +31,15 @@ #include #include #include +#include +#include +#include #include #include #include #include #include -#include "private/android_filesystem_config.h" -#include "private/debug_format.h" -#include "private/ErrnoRestorer.h" -#include "private/logd.h" - // Thread-specific state for the non-reentrant functions. static pthread_once_t stubs_once = PTHREAD_ONCE_INIT; static pthread_key_t stubs_key; @@ -60,7 +58,7 @@ static int do_getpw_r(int by_name, const char* name, uid_t uid, passwd** result) { // getpwnam_r and getpwuid_r don't modify errno, but library calls we // make might. - ErrnoRestorer errno_restorer; + int old_errno = errno; *result = NULL; // Our implementation of getpwnam(3) and getpwuid(3) use thread-local @@ -71,7 +69,9 @@ static int do_getpw_r(int by_name, const char* name, uid_t uid, // POSIX allows failure to find a match to be considered a non-error. // Reporting success (0) but with *result NULL is glibc's behavior. if (src == NULL) { - return (errno == ENOENT) ? 0 : errno; + int rc = (errno == ENOENT) ? 0 : errno; + errno = old_errno; + return rc; } // Work out where our strings will go in 'buf', and whether we've got @@ -84,11 +84,13 @@ static int do_getpw_r(int by_name, const char* name, uid_t uid, dst->pw_shell = buf + required_byte_count; required_byte_count += strlen(src->pw_shell) + 1; if (byte_count < required_byte_count) { + errno = old_errno; return ERANGE; } // Copy the strings. - snprintf(buf, byte_count, "%s%c%s%c%s", src->pw_name, 0, src->pw_dir, 0, src->pw_shell); + snprintf(buf, byte_count, "%s%c%s%c%s", + src->pw_name, 0, src->pw_dir, 0, src->pw_shell); // pw_passwd is non-POSIX and unused (always NULL) in bionic. // pw_gecos is non-POSIX and missing in bionic. @@ -99,6 +101,7 @@ static int do_getpw_r(int by_name, const char* name, uid_t uid, dst->pw_uid = src->pw_uid; *result = dst; + errno = old_errno; return 0; } diff --git a/libc/bionic/sysconf.cpp b/libc/bionic/sysconf.cpp index 869faef77..f4845e162 100644 --- a/libc/bionic/sysconf.cpp +++ b/libc/bionic/sysconf.cpp @@ -306,7 +306,7 @@ int sysconf(int name) { return _POSIX_THREAD_DESTRUCTOR_ITERATIONS; case _SC_THREAD_KEYS_MAX: - return (BIONIC_TLS_SLOTS - TLS_SLOT_FIRST_USER_SLOT - GLOBAL_INIT_THREAD_LOCAL_BUFFER_COUNT); + return (BIONIC_TLS_SLOTS - TLS_SLOT_FIRST_USER_SLOT); case _SC_THREAD_STACK_MIN: return SYSTEM_THREAD_STACK_MIN; case _SC_THREAD_THREADS_MAX: return SYSTEM_THREAD_THREADS_MAX; diff --git a/libc/bionic/tmpfile.cpp b/libc/bionic/tmpfile.cpp index 8419ff529..b97cc6c24 100644 --- a/libc/bionic/tmpfile.cpp +++ b/libc/bionic/tmpfile.cpp @@ -38,8 +38,6 @@ #include #include -#include "private/ErrnoRestorer.h" - class ScopedSignalBlocker { public: ScopedSignalBlocker() { @@ -79,8 +77,9 @@ static FILE* __tmpfile_dir(const char* tmp_dir) { struct stat sb; int rc = fstat(fd, &sb); if (rc == -1) { - ErrnoRestorer errno_restorer; + int old_errno = errno; close(fd); + errno = old_errno; return NULL; } } @@ -92,8 +91,9 @@ static FILE* __tmpfile_dir(const char* tmp_dir) { } // Failure. Clean up. We already unlinked, so we just need to close. - ErrnoRestorer errno_restorer; + int old_errno = errno; close(fd); + errno = old_errno; return NULL; } diff --git a/libc/private/ErrnoRestorer.h b/libc/private/ErrnoRestorer.h deleted file mode 100644 index ed6ab6270..000000000 --- a/libc/private/ErrnoRestorer.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (C) 2013 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. - */ - -#ifndef ERRNO_RESTORER_H -#define ERRNO_RESTORER_H - -#include - -class ErrnoRestorer { - public: - explicit ErrnoRestorer() : saved_errno_(errno) { - } - - ~ErrnoRestorer() { - errno = saved_errno_; - } - - void override(int new_errno) { - saved_errno_ = new_errno; - } - - private: - int saved_errno_; - - // Disallow copy and assignment. - ErrnoRestorer(const ErrnoRestorer&); - void operator=(const ErrnoRestorer&); -}; - -#endif // ERRNO_RESTORER_H diff --git a/libc/private/ThreadLocalBuffer.h b/libc/private/ThreadLocalBuffer.h index 703acd67a..1c5e3f48a 100644 --- a/libc/private/ThreadLocalBuffer.h +++ b/libc/private/ThreadLocalBuffer.h @@ -37,17 +37,18 @@ // TODO: move __cxa_guard_acquire and __cxa_guard_release into libc. #define GLOBAL_INIT_THREAD_LOCAL_BUFFER(name) \ + static pthread_once_t __bionic_tls_ ## name ## _once; \ static pthread_key_t __bionic_tls_ ## name ## _key; \ static void __bionic_tls_ ## name ## _key_destroy(void* buffer) { \ free(buffer); \ } \ - /* Run automatically when libc.so is opened by the dynamic linker. */ \ - __attribute__((constructor)) static void __bionic_tls_ ## name ## _key_init() { \ + static void __bionic_tls_ ## name ## _key_init() { \ pthread_key_create(&__bionic_tls_ ## name ## _key, __bionic_tls_ ## name ## _key_destroy); \ } // Leaves "name_tls_buffer" and "name_tls_buffer_size" defined and initialized. #define LOCAL_INIT_THREAD_LOCAL_BUFFER(type, name, byte_count) \ + pthread_once(&__bionic_tls_ ## name ## _once, __bionic_tls_ ## name ## _key_init); \ type name ## _tls_buffer = \ reinterpret_cast(pthread_getspecific(__bionic_tls_ ## name ## _key)); \ if (name ## _tls_buffer == NULL) { \ diff --git a/libc/private/bionic_futex.h b/libc/private/bionic_futex.h index 6c7fdbe9e..eb49fb755 100644 --- a/libc/private/bionic_futex.h +++ b/libc/private/bionic_futex.h @@ -30,8 +30,6 @@ #include -__BEGIN_DECLS - extern int __futex_wait(volatile void *ftx, int val, const struct timespec *timeout); extern int __futex_wake(volatile void *ftx, int count); @@ -56,6 +54,4 @@ extern int __futex_syscall4(volatile void *ftx, int op, int val, const struct ti extern int __futex_wake_ex(volatile void *ftx, int pshared, int val); extern int __futex_wait_ex(volatile void *ftx, int pshared, int val, const struct timespec *timeout); -__END_DECLS - #endif /* _BIONIC_FUTEX_H */ diff --git a/libc/private/bionic_tls.h b/libc/private/bionic_tls.h index 846eb8463..edf878fb7 100644 --- a/libc/private/bionic_tls.h +++ b/libc/private/bionic_tls.h @@ -43,40 +43,28 @@ __BEGIN_DECLS ** pre-allocated slot directly for performance reason). **/ +/* Maximum number of elements in the TLS array. */ +#define BIONIC_TLS_SLOTS 64 + /* Well-known TLS slots. What data goes in which slot is arbitrary unless otherwise noted. */ enum { TLS_SLOT_SELF = 0, /* The kernel requires this specific slot for x86. */ TLS_SLOT_THREAD_ID, TLS_SLOT_ERRNO, - - /* These two aren't used by bionic itself, but allow the graphics code to - * access TLS directly rather than using the pthread API. */ TLS_SLOT_OPENGL_API = 3, TLS_SLOT_OPENGL = 4, - - /* This slot is only used to pass information from the dynamic linker to - * libc.so when the C library is loaded in to memory. The C runtime init - * function will then clear it. Since its use is extremely temporary, - * we reuse an existing location that isn't needed during libc startup. */ - TLS_SLOT_BIONIC_PREINIT = TLS_SLOT_OPENGL_API, - TLS_SLOT_STACK_GUARD = 5, /* GCC requires this specific slot for x86. */ TLS_SLOT_DLERROR, TLS_SLOT_FIRST_USER_SLOT /* Must come last! */ }; -/* - * Maximum number of elements in the TLS array. - * POSIX says this must be at least 128, but Android has traditionally had only 64, minus those - * ones used internally by bionic itself. - * There are two kinds of slot used internally by bionic --- there are the well-known slots - * enumerated above, and then there are those that are allocated during startup by calls to - * pthread_key_create; grep for GLOBAL_INIT_THREAD_LOCAL_BUFFER to find those. We need to manually - * maintain that second number, but pthread_test will fail if we forget. +/* This slot is only used to pass information from the dynamic linker to + * libc.so when the C library is loaded in to memory. The C runtime init + * function will then clear it. Since its use is extremely temporary, + * we reuse an existing location that isn't needed during libc startup. */ -#define GLOBAL_INIT_THREAD_LOCAL_BUFFER_COUNT 4 -#define BIONIC_TLS_SLOTS (64 + TLS_SLOT_FIRST_USER_SLOT + GLOBAL_INIT_THREAD_LOCAL_BUFFER_COUNT) +#define TLS_SLOT_BIONIC_PREINIT TLS_SLOT_OPENGL_API /* set the Thread Local Storage, must contain at least BIONIC_TLS_SLOTS pointers */ extern void __init_tls(void** tls, void* thread_info); diff --git a/tests/pthread_test.cpp b/tests/pthread_test.cpp index 12ebd1e8c..2cf45f30d 100644 --- a/tests/pthread_test.cpp +++ b/tests/pthread_test.cpp @@ -28,14 +28,12 @@ TEST(pthread, pthread_key_create) { ASSERT_EQ(EINVAL, pthread_key_delete(key)); } -#if !defined(__GLIBC__) // glibc uses keys internally that its sysconf value doesn't account for. TEST(pthread, pthread_key_create_lots) { // We can allocate _SC_THREAD_KEYS_MAX keys. std::vector keys; for (int i = 0; i < sysconf(_SC_THREAD_KEYS_MAX); ++i) { pthread_key_t key; - // If this fails, it's likely that GLOBAL_INIT_THREAD_LOCAL_BUFFER_COUNT is wrong. - ASSERT_EQ(0, pthread_key_create(&key, NULL)) << i << " of " << sysconf(_SC_THREAD_KEYS_MAX); + ASSERT_EQ(0, pthread_key_create(&key, NULL)); keys.push_back(key); } @@ -48,7 +46,6 @@ TEST(pthread, pthread_key_create_lots) { ASSERT_EQ(0, pthread_key_delete(keys[i])); } } -#endif static void* IdFn(void* arg) { return arg; @@ -90,15 +87,6 @@ TEST(pthread, pthread_create) { ASSERT_EQ(expected_result, result); } -TEST(pthread, pthread_create_EAGAIN) { - pthread_attr_t attributes; - ASSERT_EQ(0, pthread_attr_init(&attributes)); - ASSERT_EQ(0, pthread_attr_setstacksize(&attributes, static_cast(-1) & ~(getpagesize() - 1))); - - pthread_t t; - ASSERT_EQ(EAGAIN, pthread_create(&t, &attributes, IdFn, NULL)); -} - TEST(pthread, pthread_no_join_after_detach) { pthread_t t1; ASSERT_EQ(0, pthread_create(&t1, NULL, SleepFn, reinterpret_cast(5)));