Merge "Use ENTRY/END in custom x86 assembler too."
diff --git a/libc/Android.mk b/libc/Android.mk
index d21878a..9e6f4dd 100644
--- a/libc/Android.mk
+++ b/libc/Android.mk
@@ -279,6 +279,8 @@
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 \
@@ -407,6 +409,7 @@
libc_static_common_src_files += \
bionic/pthread.c.arm \
+ bionic/pthread_create.cpp.arm \
bionic/pthread_key.cpp.arm \
# these are used by the static and dynamic versions of the libc
@@ -448,6 +451,7 @@
libc_static_common_src_files += \
bionic/pthread.c \
+ bionic/pthread_create.cpp \
bionic/pthread_key.cpp \
libc_arch_static_src_files := \
@@ -494,7 +498,8 @@
bionic/ptrace.c
libc_static_common_src_files += \
- bionic/pthread.c
+ bionic/pthread.c \
+ bionic/pthread_create.cpp \
bionic/pthread_key.cpp \
libc_arch_static_src_files := \
diff --git a/libc/arch-arm/bionic/clone.S b/libc/arch-arm/bionic/clone.S
index 6bd6bdf..39bd79d 100644
--- a/libc/arch-arm/bionic/clone.S
+++ b/libc/arch-arm/bionic/clone.S
@@ -47,7 +47,7 @@
# In parent, reload saved registers then either exit or set errno.
ldmfd sp!, {r4, r7}
- bxne lr
+ bxpl lr
b __set_syscall_errno
1: # The child.
@@ -96,7 +96,7 @@
# In the parent, reload saved registers then either exit or set errno.
ldmfd sp!, {r4, r5, r6, r7}
- bxne lr
+ bxpl lr
b __set_syscall_errno
1: # The child.
diff --git a/libc/bionic/dirent.cpp b/libc/bionic/dirent.cpp
index 3a7b5b4..74297d8 100644
--- a/libc/bionic/dirent.cpp
+++ b/libc/bionic/dirent.cpp
@@ -36,7 +36,8 @@
#include <sys/types.h>
#include <unistd.h>
-#include <private/ScopedPthreadMutexLocker.h>
+#include "private/ErrnoRestorer.h"
+#include "private/ScopedPthreadMutexLocker.h"
struct DIR {
int fd_;
@@ -108,7 +109,7 @@
}
int readdir_r(DIR* d, dirent* entry, dirent** result) {
- int saved_errno = errno;
+ ErrnoRestorer errno_restorer;
*result = NULL;
errno = 0;
@@ -124,7 +125,6 @@
memcpy(entry, next, next->d_reclen);
*result = entry;
}
- errno = saved_errno;
return 0;
}
diff --git a/libc/bionic/libc_init_common.cpp b/libc/bionic/libc_init_common.cpp
index 881b091..266d6fa 100644
--- a/libc/bionic/libc_init_common.cpp
+++ b/libc/bionic/libc_init_common.cpp
@@ -73,12 +73,10 @@
unsigned stack_size = 128 * 1024;
unsigned stack_bottom = stack_top - stack_size;
- pthread_attr_t thread_attr;
- pthread_attr_init(&thread_attr);
- pthread_attr_setstack(&thread_attr, (void*) stack_bottom, stack_size);
-
static pthread_internal_t thread;
- _init_thread(&thread, gettid(), &thread_attr, (void*) stack_bottom, false);
+ pthread_attr_init(&thread.attr);
+ pthread_attr_setstack(&thread.attr, (void*) stack_bottom, stack_size);
+ _init_thread(&thread, gettid(), false);
static void* tls_area[BIONIC_TLS_SLOTS];
__init_tls(tls_area, &thread);
diff --git a/libc/bionic/pthread.c b/libc/bionic/pthread.c
index e1ace7d..d5f8187 100644
--- a/libc/bionic/pthread.c
+++ b/libc/bionic/pthread.c
@@ -26,23 +26,11 @@
* SUCH DAMAGE.
*/
-#include <assert.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <limits.h>
-#include <malloc.h>
-#include <memory.h>
#include <pthread.h>
-#include <signal.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
+
+#include <errno.h>
+#include <limits.h>
#include <sys/atomics.h>
-#include <sys/mman.h>
-#include <sys/prctl.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <time.h>
#include <unistd.h>
#include "bionic_atomic_inline.h"
@@ -50,14 +38,12 @@
#include "bionic_pthread.h"
#include "bionic_ssp.h"
#include "bionic_tls.h"
-#include "debug_format.h"
#include "pthread_internal.h"
#include "thread_private.h"
extern void pthread_debug_mutex_lock_check(pthread_mutex_t *mutex);
extern void pthread_debug_mutex_unlock_check(pthread_mutex_t *mutex);
-extern int __pthread_clone(int (*fn)(void*), void *child_stack, int flags, void *arg);
extern void _exit_with_stack_teardown(void * stackBase, int stackSize, int retCode);
extern void _exit_thread(int retCode);
@@ -74,36 +60,8 @@
#define __likely(cond) __builtin_expect(!!(cond), 1)
#define __unlikely(cond) __builtin_expect(!!(cond), 0)
-#ifdef __i386__
-#define ATTRIBUTES __attribute__((noinline)) __attribute__((fastcall))
-#else
-#define ATTRIBUTES __attribute__((noinline))
-#endif
-
-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;
static void _pthread_internal_remove_locked(pthread_internal_t* thread) {
if (thread->next != NULL) {
@@ -161,370 +119,6 @@
}
-void __init_tls(void** tls, void* thread) {
- ((pthread_internal_t*) thread)->tls = tls;
-
- // Zero-initialize all the slots.
- for (size_t i = 0; i < BIONIC_TLS_SLOTS; ++i) {
- tls[i] = NULL;
- }
-
- // Slot 0 must point to itself. The x86 Linux kernel reads the TLS from %fs:0.
- tls[TLS_SLOT_SELF] = tls;
- tls[TLS_SLOT_THREAD_ID] = thread;
- // GCC looks in the TLS for the stack guard on x86, so copy it there from our global.
- tls[TLS_SLOT_STACK_GUARD] = (void*) __stack_chk_guard;
-
- __set_tls((void*) tls);
-}
-
-
-/*
- * This trampoline is called from the assembly _pthread_clone() function.
- */
-void __thread_entry(int (*func)(void*), void *arg, void **tls)
-{
- // Wait for our creating thread to release us. This lets it have time to
- // notify gdb about this thread before we start doing anything.
- //
- // This also provides the memory barrier needed to ensure that all memory
- // accesses previously made by the creating thread are visible to us.
- pthread_mutex_t* start_mutex = (pthread_mutex_t*) &tls[TLS_SLOT_SELF];
- pthread_mutex_lock(start_mutex);
- pthread_mutex_destroy(start_mutex);
-
- pthread_internal_t* thread = (pthread_internal_t*) tls[TLS_SLOT_THREAD_ID];
- __init_tls(tls, thread);
-
- if ((thread->internal_flags & kPthreadInitFailed) != 0) {
- pthread_exit(NULL);
- }
-
- int result = func(arg);
- pthread_exit((void*) result);
-}
-
-#include <private/logd.h>
-
-__LIBC_ABI_PRIVATE__
-int _init_thread(pthread_internal_t* thread, pid_t kernel_id, const pthread_attr_t* attr,
- void* stack_base, bool add_to_thread_list)
-{
- int error = 0;
-
- thread->attr = *attr;
- thread->attr.stack_base = stack_base;
- thread->kernel_id = kernel_id;
-
- // Make a note of whether the user supplied this stack (so we know whether or not to free it).
- if (attr->stack_base == stack_base) {
- thread->attr.flags |= PTHREAD_ATTR_FLAG_USER_STACK;
- }
-
- // Set the scheduling policy/priority of the thread.
- if (thread->attr.sched_policy != SCHED_NORMAL) {
- struct sched_param param;
- param.sched_priority = thread->attr.sched_priority;
- if (sched_setscheduler(kernel_id, thread->attr.sched_policy, ¶m) == -1) {
- // For backwards compatibility reasons, we just warn about failures here.
- // error = errno;
- const char* msg = "pthread_create sched_setscheduler call failed: %s\n";
- __libc_format_log(ANDROID_LOG_WARN, "libc", msg, strerror(errno));
- }
- }
-
- pthread_cond_init(&thread->join_cond, NULL);
- thread->join_count = 0;
- thread->cleanup_stack = NULL;
-
- if (add_to_thread_list) {
- _pthread_internal_add(thread);
- }
-
- return error;
-}
-
-static void *mkstack(size_t size, size_t guard_size)
-{
- pthread_mutex_lock(&mmap_lock);
-
- int prot = PROT_READ | PROT_WRITE;
- int flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE;
- void* stack = mmap(NULL, size, prot, flags, -1, 0);
- if (stack == MAP_FAILED) {
- stack = NULL;
- goto done;
- }
-
- if (mprotect(stack, guard_size, PROT_NONE) == -1) {
- munmap(stack, size);
- stack = NULL;
- goto done;
- }
-
-done:
- pthread_mutex_unlock(&mmap_lock);
- return stack;
-}
-
-/*
- * Create a new thread. The thread's stack is laid out like so:
- *
- * +---------------------------+
- * | pthread_internal_t |
- * +---------------------------+
- * | |
- * | TLS area |
- * | |
- * +---------------------------+
- * | |
- * . .
- * . stack area .
- * . .
- * | |
- * +---------------------------+
- * | guard page |
- * +---------------------------+
- *
- * note that TLS[0] must be a pointer to itself, this is required
- * by the thread-local storage implementation of the x86 Linux
- * kernel, where the TLS pointer is read by reading fs:[0]
- */
-int pthread_create(pthread_t *thread_out, pthread_attr_t const * attr,
- void *(*start_routine)(void *), void * arg)
-{
- int old_errno = errno;
-
- /* this will inform the rest of the C library that at least one thread
- * was created. this will enforce certain functions to acquire/release
- * locks (e.g. atexit()) to protect shared global structures.
- *
- * this works because pthread_create() is not called by the C library
- * initialization routine that sets up the main thread's data structures.
- */
- __isthreaded = 1;
-
- pthread_internal_t* thread = calloc(sizeof(*thread), 1);
- if (thread == NULL) {
- return ENOMEM;
- }
- thread->allocated_on_heap = true;
-
- if (attr == NULL) {
- attr = &gDefaultPthreadAttr;
- }
-
- // make sure the stack is PAGE_SIZE aligned
- size_t stack_size = (attr->stack_size + (PAGE_SIZE-1)) & ~(PAGE_SIZE-1);
- uint8_t* stack = attr->stack_base;
- if (stack == NULL) {
- stack = mkstack(stack_size, attr->guard_size);
- if (stack == NULL) {
- free(thread);
- return ENOMEM;
- }
- }
-
- // Make room for TLS
- void** tls = (void**)(stack + stack_size - BIONIC_TLS_SLOTS*sizeof(void*));
-
- // Create a mutex for the thread in TLS_SLOT_SELF to wait on once it starts so we can keep
- // it from doing anything until after we notify the debugger about it
- //
- // This also provides the memory barrier we need to ensure that all
- // memory accesses previously performed by this thread are visible to
- // the new thread.
- pthread_mutex_t* start_mutex = (pthread_mutex_t*) &tls[TLS_SLOT_SELF];
- pthread_mutex_init(start_mutex, NULL);
- pthread_mutex_lock(start_mutex);
-
- tls[TLS_SLOT_THREAD_ID] = thread;
-
- int flags = CLONE_FILES | CLONE_FS | CLONE_VM | CLONE_SIGHAND |
- CLONE_THREAD | CLONE_SYSVSEM | CLONE_DETACHED;
- int tid = __pthread_clone((int(*)(void*))start_routine, tls, flags, arg);
-
- if (tid < 0) {
- int clone_errno = errno;
- pthread_mutex_unlock(start_mutex);
- if (stack != attr->stack_base) {
- munmap(stack, stack_size);
- }
- free(thread);
- errno = old_errno;
- return clone_errno;
- }
-
- int init_errno = _init_thread(thread, tid, 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.)
- thread->internal_flags |= kPthreadInitFailed;
- thread->attr.flags |= PTHREAD_ATTR_FLAG_DETACHED;
- pthread_mutex_unlock(start_mutex);
- errno = old_errno;
- return init_errno;
- }
-
- // Notify any debuggers about the new thread.
- pthread_mutex_lock(&gDebuggerNotificationLock);
- _thread_created_hook(tid);
- pthread_mutex_unlock(&gDebuggerNotificationLock);
-
- // Publish the pthread_t and let the thread run.
- *thread_out = (pthread_t) thread;
- pthread_mutex_unlock(start_mutex);
-
- return 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 * 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
*/
@@ -1881,57 +1475,6 @@
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
new file mode 100644
index 0000000..c47f95e
--- /dev/null
+++ b/libc/bionic/pthread_attr.cpp
@@ -0,0 +1,161 @@
+/*
+ * 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 <pthread.h>
+
+#include "pthread_internal.h"
+
+#define DEFAULT_STACK_SIZE (1024 * 1024)
+
+int pthread_attr_init(pthread_attr_t* attr) {
+ attr->flags = 0;
+ attr->stack_base = NULL;
+ attr->stack_size = DEFAULT_STACK_SIZE;
+ attr->guard_size = PAGE_SIZE;
+ attr->sched_policy = SCHED_NORMAL;
+ attr->sched_priority = 0;
+ 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_create.cpp b/libc/bionic/pthread_create.cpp
new file mode 100644
index 0000000..6e4fe45
--- /dev/null
+++ b/libc/bionic/pthread_create.cpp
@@ -0,0 +1,232 @@
+/*
+ * 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 <pthread.h>
+
+#include <errno.h>
+#include <sys/mman.h>
+
+#include "pthread_internal.h"
+
+#include "private/bionic_ssp.h"
+#include "private/bionic_tls.h"
+#include "private/debug_format.h"
+#include "private/logd.h"
+#include "private/thread_private.h"
+#include "private/ErrnoRestorer.h"
+#include "private/ScopedPthreadMutexLocker.h"
+
+extern "C" int __pthread_clone(int (*fn)(void*), void* child_stack, int flags, void* arg);
+
+#ifdef __i386__
+#define ATTRIBUTES __attribute__((noinline)) __attribute__((fastcall))
+#else
+#define ATTRIBUTES __attribute__((noinline))
+#endif
+
+extern "C" void ATTRIBUTES _thread_created_hook(pid_t thread_id);
+
+static const int kPthreadInitFailed = 1;
+
+static pthread_mutex_t gPthreadStackCreationLock = PTHREAD_MUTEX_INITIALIZER;
+
+static pthread_mutex_t gDebuggerNotificationLock = PTHREAD_MUTEX_INITIALIZER;
+
+void __init_tls(void** tls, void* thread) {
+ ((pthread_internal_t*) thread)->tls = tls;
+
+ // Zero-initialize all the slots.
+ for (size_t i = 0; i < BIONIC_TLS_SLOTS; ++i) {
+ tls[i] = NULL;
+ }
+
+ // Slot 0 must point to itself. The x86 Linux kernel reads the TLS from %fs:0.
+ tls[TLS_SLOT_SELF] = tls;
+ tls[TLS_SLOT_THREAD_ID] = thread;
+ // GCC looks in the TLS for the stack guard on x86, so copy it there from our global.
+ tls[TLS_SLOT_STACK_GUARD] = (void*) __stack_chk_guard;
+
+ __set_tls((void*) tls);
+}
+
+// This trampoline is called from the assembly _pthread_clone() function.
+extern "C" void __thread_entry(int (*func)(void*), void *arg, void **tls) {
+ // Wait for our creating thread to release us. This lets it have time to
+ // notify gdb about this thread before we start doing anything.
+ // This also provides the memory barrier needed to ensure that all memory
+ // accesses previously made by the creating thread are visible to us.
+ pthread_mutex_t* start_mutex = (pthread_mutex_t*) &tls[TLS_SLOT_SELF];
+ pthread_mutex_lock(start_mutex);
+ pthread_mutex_destroy(start_mutex);
+
+ pthread_internal_t* thread = (pthread_internal_t*) tls[TLS_SLOT_THREAD_ID];
+ __init_tls(tls, thread);
+
+ if ((thread->internal_flags & kPthreadInitFailed) != 0) {
+ pthread_exit(NULL);
+ }
+
+ int result = func(arg);
+ pthread_exit((void*) result);
+}
+
+__LIBC_ABI_PRIVATE__
+int _init_thread(pthread_internal_t* thread, pid_t kernel_id, bool add_to_thread_list) {
+ int error = 0;
+
+ thread->kernel_id = kernel_id;
+
+ // Set the scheduling policy/priority of the thread.
+ if (thread->attr.sched_policy != SCHED_NORMAL) {
+ struct sched_param param;
+ param.sched_priority = thread->attr.sched_priority;
+ if (sched_setscheduler(kernel_id, thread->attr.sched_policy, ¶m) == -1) {
+ // For backwards compatibility reasons, we just warn about failures here.
+ // error = errno;
+ const char* msg = "pthread_create sched_setscheduler call failed: %s\n";
+ __libc_format_log(ANDROID_LOG_WARN, "libc", msg, strerror(errno));
+ }
+ }
+
+ pthread_cond_init(&thread->join_cond, NULL);
+ thread->join_count = 0;
+ thread->cleanup_stack = NULL;
+
+ if (add_to_thread_list) {
+ _pthread_internal_add(thread);
+ }
+
+ return error;
+}
+
+static void* __create_thread_stack(size_t stack_size, size_t guard_size) {
+ ScopedPthreadMutexLocker lock(&gPthreadStackCreationLock);
+
+ // Create a new private anonymous map.
+ int prot = PROT_READ | PROT_WRITE;
+ int flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE;
+ void* stack = mmap(NULL, stack_size, prot, flags, -1, 0);
+ if (stack == MAP_FAILED) {
+ return NULL;
+ }
+
+ // Set the guard region at the end of the stack to PROT_NONE.
+ if (mprotect(stack, guard_size, PROT_NONE) == -1) {
+ munmap(stack, stack_size);
+ return NULL;
+ }
+
+ return stack;
+}
+
+int pthread_create(pthread_t* thread_out, pthread_attr_t const* attr,
+ void* (*start_routine)(void*), void* arg) {
+ ErrnoRestorer errno_restorer;
+
+ // Inform the rest of the C library that at least one thread
+ // was created. This will enforce certain functions to acquire/release
+ // locks (e.g. atexit()) to protect shared global structures.
+ // This works because pthread_create() is not called by the C library
+ // initialization routine that sets up the main thread's data structures.
+ __isthreaded = 1;
+
+ pthread_internal_t* thread = reinterpret_cast<pthread_internal_t*>(calloc(sizeof(*thread), 1));
+ if (thread == NULL) {
+ return EAGAIN;
+ }
+ thread->allocated_on_heap = true;
+
+ if (attr == NULL) {
+ pthread_attr_init(&thread->attr);
+ } else {
+ thread->attr = *attr;
+ attr = NULL; // Prevent misuse below.
+ }
+
+ // Make sure the stack size is PAGE_SIZE aligned.
+ size_t stack_size = (thread->attr.stack_size + (PAGE_SIZE-1)) & ~(PAGE_SIZE-1);
+
+ if (thread->attr.stack_base == NULL) {
+ // The caller didn't provide a stack, so allocate one.
+ thread->attr.stack_base = __create_thread_stack(stack_size, thread->attr.guard_size);
+ if (thread->attr.stack_base == NULL) {
+ free(thread);
+ return EAGAIN;
+ }
+ } else {
+ // The caller did provide a stack, so remember we're not supposed to free it.
+ thread->attr.flags |= PTHREAD_ATTR_FLAG_USER_STACK;
+ }
+
+ // Make room for TLS.
+ void** tls = (void**)((uint8_t*)(thread->attr.stack_base) + stack_size - BIONIC_TLS_SLOTS * sizeof(void*));
+
+ // Create a mutex for the thread in TLS_SLOT_SELF to wait on once it starts so we can keep
+ // it from doing anything until after we notify the debugger about it
+ //
+ // This also provides the memory barrier we need to ensure that all
+ // memory accesses previously performed by this thread are visible to
+ // the new thread.
+ pthread_mutex_t* start_mutex = (pthread_mutex_t*) &tls[TLS_SLOT_SELF];
+ pthread_mutex_init(start_mutex, NULL);
+ ScopedPthreadMutexLocker start_locker(start_mutex);
+
+ tls[TLS_SLOT_THREAD_ID] = thread;
+
+ int flags = CLONE_FILES | CLONE_FS | CLONE_VM | CLONE_SIGHAND | CLONE_THREAD | CLONE_SYSVSEM | CLONE_DETACHED;
+ int tid = __pthread_clone((int(*)(void*))start_routine, tls, flags, arg);
+
+ if (tid < 0) {
+ int clone_errno = errno;
+ if ((thread->attr.flags & PTHREAD_ATTR_FLAG_USER_STACK) == 0) {
+ munmap(thread->attr.stack_base, stack_size);
+ }
+ free(thread);
+ return clone_errno;
+ }
+
+ int init_errno = _init_thread(thread, tid, 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.)
+ thread->internal_flags |= kPthreadInitFailed;
+ thread->attr.flags |= PTHREAD_ATTR_FLAG_DETACHED;
+ return init_errno;
+ }
+
+ // Notify any debuggers about the new thread.
+ {
+ ScopedPthreadMutexLocker debugger_locker(&gDebuggerNotificationLock);
+ _thread_created_hook(tid);
+ }
+
+ // Publish the pthread_t and let the thread run.
+ *thread_out = (pthread_t) thread;
+
+ return 0;
+}
diff --git a/libc/bionic/pthread_internal.h b/libc/bionic/pthread_internal.h
index 24b420c..a17c37d 100644
--- a/libc/bionic/pthread_internal.h
+++ b/libc/bionic/pthread_internal.h
@@ -55,13 +55,15 @@
char dlerror_buffer[__BIONIC_DLERROR_BUFFER_SIZE];
} pthread_internal_t;
-int _init_thread(pthread_internal_t* thread, pid_t kernel_id, const pthread_attr_t* attr,
- void* stack_base, bool add_to_thread_list);
+int _init_thread(pthread_internal_t* thread, pid_t kernel_id, bool add_to_thread_list);
void _pthread_internal_add( pthread_internal_t* thread );
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 pthread_internal_t* gThreadList;
extern pthread_mutex_t gThreadListLock;
diff --git a/libc/bionic/pthread_key.cpp b/libc/bionic/pthread_key.cpp
index 00dacba..b01f9bd 100644
--- a/libc/bionic/pthread_key.cpp
+++ b/libc/bionic/pthread_key.cpp
@@ -26,33 +26,10 @@
* SUCH DAMAGE.
*/
-#include <assert.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <limits.h>
-#include <malloc.h>
-#include <memory.h>
#include <pthread.h>
-#include <signal.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/atomics.h>
-#include <sys/mman.h>
-#include <sys/prctl.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <time.h>
-#include <unistd.h>
-#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
new file mode 100644
index 0000000..88b86ec
--- /dev/null
+++ b/libc/bionic/pthread_setname_np.cpp
@@ -0,0 +1,79 @@
+/*
+ * 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 <pthread.h>
+
+#include <fcntl.h>
+#include <stdio.h> // For snprintf.
+#include <sys/prctl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#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<pthread_internal_t*>(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 9c9dc3e..e4e1b2b 100644
--- a/libc/bionic/pthread_sigmask.cpp
+++ b/libc/bionic/pthread_sigmask.cpp
@@ -30,12 +30,13 @@
#include <pthread.h>
#include <signal.h>
-#include <private/kernel_sigset_t.h>
+#include "private/ErrnoRestorer.h"
+#include "private/kernel_sigset_t.h"
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) {
- int old_errno = errno;
+ ErrnoRestorer errno_restorer;
// '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
@@ -48,15 +49,13 @@
}
kernel_sigset_t out_set;
- int result = __rt_sigprocmask(how, in_set_ptr, &out_set, sizeof(out_set));
- if (result < 0) {
- result = errno;
+ if (__rt_sigprocmask(how, in_set_ptr, &out_set, sizeof(out_set)) == -1) {
+ return errno;
}
if (oset != NULL) {
*oset = out_set.bionic;
}
- errno = old_errno;
- return result;
+ return 0;
}
diff --git a/libc/bionic/strerror_r.cpp b/libc/bionic/strerror_r.cpp
index 646cc52..81120ec 100644
--- a/libc/bionic/strerror_r.cpp
+++ b/libc/bionic/strerror_r.cpp
@@ -7,6 +7,8 @@
#include <stdio.h>
#include <string.h>
+#include "private/ErrnoRestorer.h"
+
struct Pair {
int code;
const char* msg;
@@ -42,7 +44,7 @@
}
int strerror_r(int error_number, char* buf, size_t buf_len) {
- int saved_errno = errno;
+ ErrnoRestorer errno_restorer;
size_t length;
const char* error_name = __strerror_lookup(error_number);
@@ -52,11 +54,10 @@
length = snprintf(buf, buf_len, "Unknown error %d", error_number);
}
if (length >= buf_len) {
- errno = ERANGE;
+ errno_restorer.override(ERANGE);
return -1;
}
- errno = saved_errno;
return 0;
}
diff --git a/libc/bionic/stubs.cpp b/libc/bionic/stubs.cpp
index 3f24d1b..8ddc326 100644
--- a/libc/bionic/stubs.cpp
+++ b/libc/bionic/stubs.cpp
@@ -31,15 +31,17 @@
#include <grp.h>
#include <mntent.h>
#include <netdb.h>
-#include <private/android_filesystem_config.h>
-#include <private/debug_format.h>
-#include <private/logd.h>
#include <pthread.h>
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
+#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;
@@ -58,7 +60,7 @@
passwd** result) {
// getpwnam_r and getpwuid_r don't modify errno, but library calls we
// make might.
- int old_errno = errno;
+ ErrnoRestorer errno_restorer;
*result = NULL;
// Our implementation of getpwnam(3) and getpwuid(3) use thread-local
@@ -69,9 +71,7 @@
// 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) {
- int rc = (errno == ENOENT) ? 0 : errno;
- errno = old_errno;
- return rc;
+ return (errno == ENOENT) ? 0 : errno;
}
// Work out where our strings will go in 'buf', and whether we've got
@@ -84,13 +84,11 @@
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.
@@ -101,7 +99,6 @@
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 f4845e1..869faef 100644
--- a/libc/bionic/sysconf.cpp
+++ b/libc/bionic/sysconf.cpp
@@ -306,7 +306,7 @@
return _POSIX_THREAD_DESTRUCTOR_ITERATIONS;
case _SC_THREAD_KEYS_MAX:
- return (BIONIC_TLS_SLOTS - TLS_SLOT_FIRST_USER_SLOT);
+ return (BIONIC_TLS_SLOTS - TLS_SLOT_FIRST_USER_SLOT - GLOBAL_INIT_THREAD_LOCAL_BUFFER_COUNT);
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 b97cc6c..8419ff5 100644
--- a/libc/bionic/tmpfile.cpp
+++ b/libc/bionic/tmpfile.cpp
@@ -38,6 +38,8 @@
#include <sys/types.h>
#include <unistd.h>
+#include "private/ErrnoRestorer.h"
+
class ScopedSignalBlocker {
public:
ScopedSignalBlocker() {
@@ -77,9 +79,8 @@
struct stat sb;
int rc = fstat(fd, &sb);
if (rc == -1) {
- int old_errno = errno;
+ ErrnoRestorer errno_restorer;
close(fd);
- errno = old_errno;
return NULL;
}
}
@@ -91,9 +92,8 @@
}
// Failure. Clean up. We already unlinked, so we just need to close.
- int old_errno = errno;
+ ErrnoRestorer errno_restorer;
close(fd);
- errno = old_errno;
return NULL;
}
diff --git a/libc/include/sys/_system_properties.h b/libc/include/sys/_system_properties.h
index 10c0fae..5d2043d 100644
--- a/libc/include/sys/_system_properties.h
+++ b/libc/include/sys/_system_properties.h
@@ -104,6 +104,7 @@
#define PROP_PATH_SYSTEM_BUILD "/system/build.prop"
#define PROP_PATH_SYSTEM_DEFAULT "/system/default.prop"
#define PROP_PATH_LOCAL_OVERRIDE "/data/local.prop"
+#define PROP_PATH_FACTORY "/factory/factory.prop"
#endif
#endif
diff --git a/libc/kernel/common/linux/msm_mdp.h b/libc/kernel/common/linux/msm_mdp.h
index fdb046c..72e9072 100644
--- a/libc/kernel/common/linux/msm_mdp.h
+++ b/libc/kernel/common/linux/msm_mdp.h
@@ -66,434 +66,434 @@
#define MSMFB_VSYNC_CTRL _IOW(MSMFB_IOCTL_MAGIC, 161, unsigned int)
#define MSMFB_BUFFER_SYNC _IOW(MSMFB_IOCTL_MAGIC, 162, struct mdp_buf_sync)
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
-#define MSMFB_OVERLAY_COMMIT _IOW(MSMFB_IOCTL_MAGIC, 163, unsigned int)
#define MSMFB_DISPLAY_COMMIT _IOW(MSMFB_IOCTL_MAGIC, 164, struct mdp_display_commit)
#define FB_TYPE_3D_PANEL 0x10101010
#define MDP_IMGTYPE2_START 0x10000
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#define MSMFB_DRIVER_VERSION 0xF9E8D701
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
enum {
NOTIFY_UPDATE_START,
NOTIFY_UPDATE_STOP,
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
};
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
enum {
MDP_RGB_565,
MDP_XRGB_8888,
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
MDP_Y_CBCR_H2V2,
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
MDP_Y_CBCR_H2V2_ADRENO,
MDP_ARGB_8888,
MDP_RGB_888,
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
MDP_Y_CRCB_H2V2,
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
MDP_YCRYCB_H2V1,
MDP_Y_CRCB_H2V1,
MDP_Y_CBCR_H2V1,
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
MDP_Y_CRCB_H1V2,
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
MDP_Y_CBCR_H1V2,
MDP_RGBA_8888,
MDP_BGRA_8888,
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
MDP_RGBX_8888,
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
MDP_Y_CRCB_H2V2_TILE,
MDP_Y_CBCR_H2V2_TILE,
MDP_Y_CR_CB_H2V2,
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
MDP_Y_CR_CB_GH2V2,
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
MDP_Y_CB_CR_H2V2,
MDP_Y_CRCB_H1V1,
MDP_Y_CBCR_H1V1,
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
MDP_YCRCB_H1V1,
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
MDP_YCBCR_H1V1,
MDP_BGR_565,
MDP_IMGTYPE_LIMIT,
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
MDP_RGB_BORDERFILL,
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
MDP_FB_FORMAT = MDP_IMGTYPE2_START,
MDP_IMGTYPE_LIMIT2
};
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
enum {
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
PMEM_IMG,
FB_IMG,
};
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
enum {
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
HSIC_HUE = 0,
HSIC_SAT,
HSIC_INT,
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
HSIC_CON,
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
NUM_HSIC_PARAM,
};
#define MDSS_MDP_ROT_ONLY 0x80
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#define MDSS_MDP_RIGHT_MIXER 0x100
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#define MDP_ROT_NOP 0
#define MDP_FLIP_LR 0x1
#define MDP_FLIP_UD 0x2
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#define MDP_ROT_90 0x4
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#define MDP_ROT_180 (MDP_FLIP_UD|MDP_FLIP_LR)
#define MDP_ROT_270 (MDP_ROT_90|MDP_FLIP_UD|MDP_FLIP_LR)
#define MDP_DITHER 0x8
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#define MDP_BLUR 0x10
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#define MDP_BLEND_FG_PREMULT 0x20000
#define MDP_DEINTERLACE 0x80000000
#define MDP_SHARPENING 0x40000000
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#define MDP_NO_DMA_BARRIER_START 0x20000000
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#define MDP_NO_DMA_BARRIER_END 0x10000000
#define MDP_NO_BLIT 0x08000000
#define MDP_BLIT_WITH_DMA_BARRIERS 0x000
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#define MDP_BLIT_WITH_NO_DMA_BARRIERS (MDP_NO_DMA_BARRIER_START | MDP_NO_DMA_BARRIER_END)
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#define MDP_BLIT_SRC_GEM 0x04000000
#define MDP_BLIT_DST_GEM 0x02000000
#define MDP_BLIT_NON_CACHED 0x01000000
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#define MDP_OV_PIPE_SHARE 0x00800000
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#define MDP_DEINTERLACE_ODD 0x00400000
#define MDP_OV_PLAY_NOWAIT 0x00200000
#define MDP_SOURCE_ROTATED_90 0x00100000
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#define MDP_OVERLAY_PP_CFG_EN 0x00080000
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#define MDP_BACKEND_COMPOSITION 0x00040000
#define MDP_BORDERFILL_SUPPORTED 0x00010000
#define MDP_SECURE_OVERLAY_SESSION 0x00008000
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#define MDP_MEMORY_ID_TYPE_FB 0x00001000
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#define MDP_TRANSP_NOP 0xffffffff
#define MDP_ALPHA_NOP 0xff
#define MDP_FB_PAGE_PROTECTION_NONCACHED (0)
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#define MDP_FB_PAGE_PROTECTION_WRITECOMBINE (1)
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#define MDP_FB_PAGE_PROTECTION_WRITETHROUGHCACHE (2)
#define MDP_FB_PAGE_PROTECTION_WRITEBACKCACHE (3)
#define MDP_FB_PAGE_PROTECTION_WRITEBACKWACACHE (4)
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#define MDP_FB_PAGE_PROTECTION_INVALID (5)
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#define MDP_NUM_FB_PAGE_PROTECTION_VALUES (5)
struct mdp_rect {
uint32_t x;
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
uint32_t y;
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
uint32_t w;
uint32_t h;
};
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
struct mdp_img {
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
uint32_t width;
uint32_t height;
uint32_t format;
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
uint32_t offset;
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
int memory_id;
uint32_t priv;
};
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#define MDP_CCS_RGB2YUV 0
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#define MDP_CCS_YUV2RGB 1
#define MDP_CCS_SIZE 9
#define MDP_BV_SIZE 3
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
struct mdp_ccs {
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
int direction;
uint16_t ccs[MDP_CCS_SIZE];
uint16_t bv[MDP_BV_SIZE];
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
};
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
struct mdp_csc {
int id;
uint32_t csc_mv[9];
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
uint32_t csc_pre_bv[3];
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
uint32_t csc_post_bv[3];
uint32_t csc_pre_lv[6];
uint32_t csc_post_lv[6];
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
};
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#define MDP_BLIT_REQ_VERSION 2
struct mdp_blit_req {
struct mdp_img src;
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
struct mdp_img dst;
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
struct mdp_rect src_rect;
struct mdp_rect dst_rect;
uint32_t alpha;
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
uint32_t transp_mask;
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
uint32_t flags;
int sharpening_strength;
};
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
struct mdp_blit_req_list {
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
uint32_t count;
struct mdp_blit_req req[];
};
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#define MSMFB_DATA_VERSION 2
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
struct msmfb_data {
uint32_t offset;
int memory_id;
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
int id;
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
uint32_t flags;
uint32_t priv;
uint32_t iova;
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
};
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#define MSMFB_NEW_REQUEST -1
struct msmfb_overlay_data {
uint32_t id;
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
struct msmfb_data data;
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
uint32_t version_key;
struct msmfb_data plane1_data;
struct msmfb_data plane2_data;
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
struct msmfb_data dst_data;
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
};
struct msmfb_img {
uint32_t width;
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
uint32_t height;
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
uint32_t format;
};
#define MSMFB_WRITEBACK_DEQUEUE_BLOCKING 0x1
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
struct msmfb_writeback_data {
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
struct msmfb_data buf_info;
struct msmfb_img img;
};
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#define MDP_PP_OPS_READ 0x2
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#define MDP_PP_OPS_WRITE 0x4
struct mdp_qseed_cfg {
uint32_t table_num;
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
uint32_t ops;
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
uint32_t len;
uint32_t *data;
};
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
struct mdp_qseed_cfg_data {
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
uint32_t block;
struct mdp_qseed_cfg qseed_data;
};
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#define MDP_OVERLAY_PP_CSC_CFG 0x1
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#define MDP_OVERLAY_PP_QSEED_CFG 0x2
#define MDP_CSC_FLAG_ENABLE 0x1
#define MDP_CSC_FLAG_YUV_IN 0x2
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#define MDP_CSC_FLAG_YUV_OUT 0x4
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
struct mdp_csc_cfg {
uint32_t flags;
uint32_t csc_mv[9];
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
uint32_t csc_pre_bv[3];
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
uint32_t csc_post_bv[3];
uint32_t csc_pre_lv[6];
uint32_t csc_post_lv[6];
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
};
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
struct mdp_csc_cfg_data {
uint32_t block;
struct mdp_csc_cfg csc_data;
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
};
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
struct mdp_overlay_pp_params {
uint32_t config_ops;
struct mdp_csc_cfg csc_cfg;
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
struct mdp_qseed_cfg qseed_cfg[2];
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
};
struct mdp_overlay {
struct msmfb_img src;
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
struct mdp_rect src_rect;
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
struct mdp_rect dst_rect;
uint32_t z_order;
uint32_t is_fg;
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
uint32_t alpha;
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
uint32_t transp_mask;
uint32_t flags;
uint32_t id;
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
uint32_t user_data[8];
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
struct mdp_overlay_pp_params overlay_pp_cfg;
};
struct msmfb_overlay_3d {
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
uint32_t is_3d;
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
uint32_t width;
uint32_t height;
};
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
struct msmfb_overlay_blt {
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
uint32_t enable;
uint32_t offset;
uint32_t width;
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
uint32_t height;
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
uint32_t bpp;
};
struct mdp_histogram {
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
uint32_t frame_cnt;
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
uint32_t bin_cnt;
uint32_t *r;
uint32_t *g;
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
uint32_t *b;
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
};
enum {
MDP_BLOCK_RESERVED = 0,
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
MDP_BLOCK_OVERLAY_0,
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
MDP_BLOCK_OVERLAY_1,
MDP_BLOCK_VG_1,
MDP_BLOCK_VG_2,
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
MDP_BLOCK_RGB_1,
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
MDP_BLOCK_RGB_2,
MDP_BLOCK_DMA_P,
MDP_BLOCK_DMA_S,
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
MDP_BLOCK_DMA_E,
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
MDP_BLOCK_OVERLAY_2,
MDP_BLOCK_MAX,
};
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
struct mdp_histogram_start_req {
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
uint32_t block;
uint8_t frame_cnt;
uint8_t bit_mask;
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
uint8_t num_bins;
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
};
struct mdp_histogram_data {
uint32_t block;
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
uint8_t bin_cnt;
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
uint32_t *c0;
uint32_t *c1;
uint32_t *c2;
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
uint32_t *extra_info;
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
};
struct mdp_pcc_coeff {
uint32_t c, r, g, b, rr, gg, bb, rg, gb, rb, rgb_0, rgb_1;
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
};
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
struct mdp_pcc_cfg_data {
uint32_t block;
uint32_t ops;
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
struct mdp_pcc_coeff r, g, b;
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
};
enum {
mdp_lut_igc,
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
mdp_lut_pgc,
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
mdp_lut_hist,
mdp_lut_max,
};
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
struct mdp_igc_lut_data {
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
uint32_t block;
uint32_t len, ops;
uint32_t *c0_c1_data;
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
uint32_t *c2_data;
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
};
struct mdp_ar_gc_lut_data {
uint32_t x_start;
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
uint32_t slope;
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
uint32_t offset;
};
struct mdp_pgc_lut_data {
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
uint32_t block;
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
uint32_t flags;
uint8_t num_r_stages;
uint8_t num_g_stages;
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
uint8_t num_b_stages;
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
struct mdp_ar_gc_lut_data *r_data;
struct mdp_ar_gc_lut_data *g_data;
struct mdp_ar_gc_lut_data *b_data;
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
};
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
struct mdp_hist_lut_data {
uint32_t block;
uint32_t ops;
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
uint32_t len;
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
uint32_t *data;
};
struct mdp_lut_cfg_data {
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
uint32_t lut_type;
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
union {
struct mdp_igc_lut_data igc_lut_data;
struct mdp_pgc_lut_data pgc_lut_data;
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
struct mdp_hist_lut_data hist_lut_data;
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
} data;
};
struct mdp_bl_scale_data {
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
uint32_t min_lvl;
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
uint32_t scale;
};
enum {
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
mdp_op_pcc_cfg,
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
mdp_op_csc_cfg,
mdp_op_lut_cfg,
mdp_op_qseed_cfg,
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
mdp_bl_scale_cfg,
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
mdp_op_max,
};
struct msmfb_mdp_pp {
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
uint32_t op;
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
union {
struct mdp_pcc_cfg_data pcc_cfg_data;
struct mdp_csc_cfg_data csc_cfg_data;
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
struct mdp_lut_cfg_data lut_cfg_data;
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
struct mdp_qseed_cfg_data qseed_cfg_data;
struct mdp_bl_scale_data bl_scale_data;
} data;
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
};
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#define MDP_MAX_FENCE_FD 10
#define MDP_BUF_SYNC_FLAG_WAIT 1
struct mdp_buf_sync {
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
uint32_t flags;
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
uint32_t acq_fen_fd_cnt;
int *acq_fen_fd;
int *rel_fen_fd;
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
};
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
struct mdp_buf_fence {
uint32_t flags;
uint32_t acq_fen_fd_cnt;
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
int acq_fen_fd[MDP_MAX_FENCE_FD];
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
int rel_fen_fd[MDP_MAX_FENCE_FD];
};
+#define MDP_DISPLAY_COMMIT_OVERLAY 0x00000001
struct mdp_display_commit {
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
uint32_t flags;
diff --git a/libc/private/ErrnoRestorer.h b/libc/private/ErrnoRestorer.h
new file mode 100644
index 0000000..ed6ab62
--- /dev/null
+++ b/libc/private/ErrnoRestorer.h
@@ -0,0 +1,43 @@
+/*
+ * 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 <errno.h>
+
+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 1c5e3f4..e5bd28c 100644
--- a/libc/private/ThreadLocalBuffer.h
+++ b/libc/private/ThreadLocalBuffer.h
@@ -36,19 +36,20 @@
// so we make do with macros instead of a C++ class.
// TODO: move __cxa_guard_acquire and __cxa_guard_release into libc.
+// We used to use pthread_once to initialize the keys, but life is more predictable
+// if we allocate them all up front when the C library starts up, via __constructor__.
+
#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); \
} \
- static void __bionic_tls_ ## name ## _key_init() { \
+ __attribute__((constructor)) 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<type>(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 eb49fb7..6c7fdbe 100644
--- a/libc/private/bionic_futex.h
+++ b/libc/private/bionic_futex.h
@@ -30,6 +30,8 @@
#include <linux/futex.h>
+__BEGIN_DECLS
+
extern int __futex_wait(volatile void *ftx, int val, const struct timespec *timeout);
extern int __futex_wake(volatile void *ftx, int count);
@@ -54,4 +56,6 @@
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 edf878f..4dd66c0 100644
--- a/libc/private/bionic_tls.h
+++ b/libc/private/bionic_tls.h
@@ -43,28 +43,40 @@
** 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! */
};
-/* 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.
+/*
+ * 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.
*/
-#define TLS_SLOT_BIONIC_PREINIT TLS_SLOT_OPENGL_API
+#define GLOBAL_INIT_THREAD_LOCAL_BUFFER_COUNT 4
+#define BIONIC_TLS_SLOTS 64
/* 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/Android.mk b/tests/Android.mk
index 3217a4d..8138cff 100644
--- a/tests/Android.mk
+++ b/tests/Android.mk
@@ -124,6 +124,7 @@
# implementation for testing the tests themselves.
ifeq ($(HOST_OS)-$(HOST_ARCH),linux-x86)
include $(CLEAR_VARS)
+LOCAL_CXX := /usr/bin/g++ # Avoid the host prebuilt so we test the real glibc.
LOCAL_MODULE := bionic-unit-tests-glibc
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
LOCAL_CFLAGS += $(test_c_flags)
diff --git a/tests/pthread_test.cpp b/tests/pthread_test.cpp
index 0ccd948..931a4c7 100644
--- a/tests/pthread_test.cpp
+++ b/tests/pthread_test.cpp
@@ -28,12 +28,14 @@
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<pthread_key_t> keys;
for (int i = 0; i < sysconf(_SC_THREAD_KEYS_MAX); ++i) {
pthread_key_t key;
- ASSERT_EQ(0, pthread_key_create(&key, NULL));
+ // 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);
keys.push_back(key);
}
@@ -46,6 +48,7 @@
ASSERT_EQ(0, pthread_key_delete(keys[i]));
}
}
+#endif
static void* IdFn(void* arg) {
return arg;
@@ -87,6 +90,15 @@
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<size_t>(-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<void*>(5)));
@@ -174,7 +186,7 @@
ASSERT_EQ(0, reinterpret_cast<int>(join_result));
}
-#if !defined(__GLIBC__)
+#if __BIONIC__
extern "C" int __pthread_clone(int (*fn)(void*), void* child_stack, int flags, void* arg);
TEST(pthread, __pthread_clone) {
uintptr_t fake_child_stack[16];
@@ -183,3 +195,35 @@
ASSERT_EQ(EINVAL, errno);
}
#endif
+
+#if __BIONIC__ // Not all build servers have a new enough glibc? TODO: remove when they're on gprecise.
+TEST(pthread, pthread_setname_np__too_long) {
+ ASSERT_EQ(ERANGE, pthread_setname_np(pthread_self(), "this name is far too long for linux"));
+}
+#endif
+
+#if __BIONIC__ // Not all build servers have a new enough glibc? TODO: remove when they're on gprecise.
+TEST(pthread, pthread_setname_np__self) {
+ ASSERT_EQ(0, pthread_setname_np(pthread_self(), "short 1"));
+}
+#endif
+
+#if __BIONIC__ // Not all build servers have a new enough glibc? TODO: remove when they're on gprecise.
+TEST(pthread, pthread_setname_np__other) {
+ pthread_t t1;
+ ASSERT_EQ(0, pthread_create(&t1, NULL, SleepFn, reinterpret_cast<void*>(5)));
+ ASSERT_EQ(0, pthread_setname_np(t1, "short 2"));
+}
+#endif
+
+#if __BIONIC__ // Not all build servers have a new enough glibc? TODO: remove when they're on gprecise.
+TEST(pthread, pthread_setname_np__no_such_thread) {
+ pthread_t t1;
+ ASSERT_EQ(0, pthread_create(&t1, NULL, IdFn, NULL));
+ void* result;
+ ASSERT_EQ(0, pthread_join(t1, &result));
+
+ // Call pthread_setname_np after thread has already exited.
+ ASSERT_EQ(ENOENT, pthread_setname_np(t1, "short 3"));
+}
+#endif