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, &param) == -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, &param) == -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