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 \
#include <sys/types.h>
#include <unistd.h>
-#include "private/ErrnoRestorer.h"
-#include "private/ScopedPthreadMutexLocker.h"
+#include <private/ScopedPthreadMutexLocker.h>
struct DIR {
int fd_;
}
int readdir_r(DIR* d, dirent* entry, dirent** result) {
- ErrnoRestorer errno_restorer;
+ int saved_errno = errno;
*result = NULL;
errno = 0;
memcpy(entry, next, next->d_reclen);
*result = entry;
}
+ errno = saved_errno;
return 0;
}
* SUCH DAMAGE.
*/
-#include <pthread.h>
-
+#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"
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;
pthread_internal_t* thread = calloc(sizeof(*thread), 1);
if (thread == NULL) {
- return EAGAIN;
+ return ENOMEM;
}
thread->allocated_on_heap = true;
stack = mkstack(stack_size, attr->guard_size);
if (stack == NULL) {
free(thread);
- return EAGAIN;
+ return ENOMEM;
}
}
}
+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
*/
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.
+++ /dev/null
-/*
- * 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_STACKSIZE (1024 * 1024)
-
-const pthread_attr_t gDefaultPthreadAttr = {
- .flags = 0,
- .stack_base = NULL,
- .stack_size = DEFAULT_STACKSIZE,
- .guard_size = PAGE_SIZE,
- .sched_policy = SCHED_NORMAL,
- .sched_priority = 0
-};
-
-int pthread_attr_init(pthread_attr_t* attr) {
- *attr = gDefaultPthreadAttr;
- return 0;
-}
-
-int pthread_attr_destroy(pthread_attr_t* attr) {
- memset(attr, 0x42, sizeof(pthread_attr_t));
- return 0;
-}
-
-int pthread_attr_setdetachstate(pthread_attr_t* attr, int state) {
- if (state == PTHREAD_CREATE_DETACHED) {
- attr->flags |= PTHREAD_ATTR_FLAG_DETACHED;
- } else if (state == PTHREAD_CREATE_JOINABLE) {
- attr->flags &= ~PTHREAD_ATTR_FLAG_DETACHED;
- } else {
- return EINVAL;
- }
- return 0;
-}
-
-int pthread_attr_getdetachstate(pthread_attr_t const* attr, int* state) {
- *state = (attr->flags & PTHREAD_ATTR_FLAG_DETACHED) ? PTHREAD_CREATE_DETACHED : PTHREAD_CREATE_JOINABLE;
- return 0;
-}
-
-int pthread_attr_setschedpolicy(pthread_attr_t* attr, int policy) {
- attr->sched_policy = policy;
- return 0;
-}
-
-int pthread_attr_getschedpolicy(pthread_attr_t const* attr, int* policy) {
- *policy = attr->sched_policy;
- return 0;
-}
-
-int pthread_attr_setschedparam(pthread_attr_t * attr, struct sched_param const* param) {
- attr->sched_priority = param->sched_priority;
- return 0;
-}
-
-int pthread_attr_getschedparam(pthread_attr_t const* attr, struct sched_param* param) {
- param->sched_priority = attr->sched_priority;
- return 0;
-}
-
-int pthread_attr_setstacksize(pthread_attr_t* attr, size_t stack_size) {
- if ((stack_size & (PAGE_SIZE - 1) || stack_size < PTHREAD_STACK_MIN)) {
- return EINVAL;
- }
- attr->stack_size = stack_size;
- return 0;
-}
-
-int pthread_attr_getstacksize(pthread_attr_t const* attr, size_t* stack_size) {
- *stack_size = attr->stack_size;
- return 0;
-}
-
-int pthread_attr_setstackaddr(pthread_attr_t*, void*) {
- // This was removed from POSIX.1-2008, and is not implemented on bionic.
- // Needed for ABI compatibility with the NDK.
- return ENOSYS;
-}
-
-int pthread_attr_getstackaddr(pthread_attr_t const* attr, void** stack_addr) {
- // This was removed from POSIX.1-2008.
- // Needed for ABI compatibility with the NDK.
- *stack_addr = (char*)attr->stack_base + attr->stack_size;
- return 0;
-}
-
-int pthread_attr_setstack(pthread_attr_t* attr, void* stack_base, size_t stack_size) {
- if ((stack_size & (PAGE_SIZE - 1) || stack_size < PTHREAD_STACK_MIN)) {
- return EINVAL;
- }
- if ((uint32_t)stack_base & (PAGE_SIZE - 1)) {
- return EINVAL;
- }
- attr->stack_base = stack_base;
- attr->stack_size = stack_size;
- return 0;
-}
-
-int pthread_attr_getstack(pthread_attr_t const* attr, void** stack_base, size_t* stack_size) {
- *stack_base = attr->stack_base;
- *stack_size = attr->stack_size;
- return 0;
-}
-
-int pthread_attr_setguardsize(pthread_attr_t* attr, size_t guard_size) {
- if (guard_size & (PAGE_SIZE - 1) || guard_size < PAGE_SIZE) {
- return EINVAL;
- }
- attr->guard_size = guard_size;
- return 0;
-}
-
-int pthread_attr_getguardsize(pthread_attr_t const* attr, size_t* guard_size) {
- *guard_size = attr->guard_size;
- return 0;
-}
-
-int pthread_getattr_np(pthread_t thid, pthread_attr_t* attr) {
- pthread_internal_t* thread = (pthread_internal_t*) thid;
- *attr = thread->attr;
- return 0;
-}
-
-int pthread_attr_setscope(pthread_attr_t* , int scope) {
- if (scope == PTHREAD_SCOPE_SYSTEM) {
- return 0;
- }
- if (scope == PTHREAD_SCOPE_PROCESS) {
- return ENOTSUP;
- }
- return EINVAL;
-}
-
-int pthread_attr_getscope(pthread_attr_t const*) {
- return PTHREAD_SCOPE_SYSTEM;
-}
__LIBC_HIDDEN__ void pthread_key_clean_all(void);
-#define PTHREAD_ATTR_FLAG_DETACHED 0x00000001
-#define PTHREAD_ATTR_FLAG_USER_STACK 0x00000002
-
-extern __LIBC_HIDDEN__ const pthread_attr_t gDefaultPthreadAttr;
extern pthread_internal_t* gThreadList;
extern pthread_mutex_t gThreadListLock;
* 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:
*
+++ /dev/null
-/*
- * 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;
-}
#include <pthread.h>
#include <signal.h>
-#include "private/ErrnoRestorer.h"
-#include "private/kernel_sigset_t.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) {
- ErrnoRestorer errno_restorer;
+ int old_errno = errno;
// 'in_set_ptr' is the second parameter to __rt_sigprocmask. It must be NULL
// if 'set' is NULL to ensure correct semantics (which in this case would
}
kernel_sigset_t out_set;
- if (__rt_sigprocmask(how, in_set_ptr, &out_set, sizeof(out_set)) == -1) {
- return errno;
+ int result = __rt_sigprocmask(how, in_set_ptr, &out_set, sizeof(out_set));
+ if (result < 0) {
+ result = errno;
}
if (oset != NULL) {
*oset = out_set.bionic;
}
- return 0;
+ errno = old_errno;
+ return result;
}
#include <stdio.h>
#include <string.h>
-#include "private/ErrnoRestorer.h"
-
struct Pair {
int code;
const char* msg;
}
int strerror_r(int error_number, char* buf, size_t buf_len) {
- ErrnoRestorer errno_restorer;
+ int saved_errno = errno;
size_t length;
const char* error_name = __strerror_lookup(error_number);
length = snprintf(buf, buf_len, "Unknown error %d", error_number);
}
if (length >= buf_len) {
- errno_restorer.override(ERANGE);
+ errno = ERANGE;
return -1;
}
+ errno = saved_errno;
return 0;
}
#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;
passwd** result) {
// getpwnam_r and getpwuid_r don't modify errno, but library calls we
// make might.
- ErrnoRestorer errno_restorer;
+ int old_errno = errno;
*result = NULL;
// Our implementation of getpwnam(3) and getpwuid(3) use thread-local
// POSIX allows failure to find a match to be considered a non-error.
// Reporting success (0) but with *result NULL is glibc's behavior.
if (src == NULL) {
- return (errno == ENOENT) ? 0 : errno;
+ int rc = (errno == ENOENT) ? 0 : errno;
+ errno = old_errno;
+ return rc;
}
// Work out where our strings will go in 'buf', and whether we've got
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.
dst->pw_uid = src->pw_uid;
*result = dst;
+ errno = old_errno;
return 0;
}
return _POSIX_THREAD_DESTRUCTOR_ITERATIONS;
case _SC_THREAD_KEYS_MAX:
- return (BIONIC_TLS_SLOTS - TLS_SLOT_FIRST_USER_SLOT - GLOBAL_INIT_THREAD_LOCAL_BUFFER_COUNT);
+ return (BIONIC_TLS_SLOTS - TLS_SLOT_FIRST_USER_SLOT);
case _SC_THREAD_STACK_MIN: return SYSTEM_THREAD_STACK_MIN;
case _SC_THREAD_THREADS_MAX: return SYSTEM_THREAD_THREADS_MAX;
#include <sys/types.h>
#include <unistd.h>
-#include "private/ErrnoRestorer.h"
-
class ScopedSignalBlocker {
public:
ScopedSignalBlocker() {
struct stat sb;
int rc = fstat(fd, &sb);
if (rc == -1) {
- ErrnoRestorer errno_restorer;
+ int old_errno = errno;
close(fd);
+ errno = old_errno;
return NULL;
}
}
}
// Failure. Clean up. We already unlinked, so we just need to close.
- ErrnoRestorer errno_restorer;
+ int old_errno = errno;
close(fd);
+ errno = old_errno;
return NULL;
}
+++ /dev/null
-/*
- * 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
// TODO: move __cxa_guard_acquire and __cxa_guard_release into libc.
#define GLOBAL_INIT_THREAD_LOCAL_BUFFER(name) \
+ static pthread_once_t __bionic_tls_ ## name ## _once; \
static pthread_key_t __bionic_tls_ ## name ## _key; \
static void __bionic_tls_ ## name ## _key_destroy(void* buffer) { \
free(buffer); \
} \
- /* Run automatically when libc.so is opened by the dynamic linker. */ \
- __attribute__((constructor)) static void __bionic_tls_ ## name ## _key_init() { \
+ static void __bionic_tls_ ## name ## _key_init() { \
pthread_key_create(&__bionic_tls_ ## name ## _key, __bionic_tls_ ## name ## _key_destroy); \
}
// Leaves "name_tls_buffer" and "name_tls_buffer_size" defined and initialized.
#define LOCAL_INIT_THREAD_LOCAL_BUFFER(type, name, byte_count) \
+ pthread_once(&__bionic_tls_ ## name ## _once, __bionic_tls_ ## name ## _key_init); \
type name ## _tls_buffer = \
reinterpret_cast<type>(pthread_getspecific(__bionic_tls_ ## name ## _key)); \
if (name ## _tls_buffer == NULL) { \
#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);
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 */
** pre-allocated slot directly for performance reason).
**/
+/* Maximum number of elements in the TLS array. */
+#define BIONIC_TLS_SLOTS 64
+
/* Well-known TLS slots. What data goes in which slot is arbitrary unless otherwise noted. */
enum {
TLS_SLOT_SELF = 0, /* The kernel requires this specific slot for x86. */
TLS_SLOT_THREAD_ID,
TLS_SLOT_ERRNO,
-
- /* These two aren't used by bionic itself, but allow the graphics code to
- * access TLS directly rather than using the pthread API. */
TLS_SLOT_OPENGL_API = 3,
TLS_SLOT_OPENGL = 4,
-
- /* This slot is only used to pass information from the dynamic linker to
- * libc.so when the C library is loaded in to memory. The C runtime init
- * function will then clear it. Since its use is extremely temporary,
- * we reuse an existing location that isn't needed during libc startup. */
- TLS_SLOT_BIONIC_PREINIT = TLS_SLOT_OPENGL_API,
-
TLS_SLOT_STACK_GUARD = 5, /* GCC requires this specific slot for x86. */
TLS_SLOT_DLERROR,
TLS_SLOT_FIRST_USER_SLOT /* Must come last! */
};
-/*
- * Maximum number of elements in the TLS array.
- * POSIX says this must be at least 128, but Android has traditionally had only 64, minus those
- * ones used internally by bionic itself.
- * There are two kinds of slot used internally by bionic --- there are the well-known slots
- * enumerated above, and then there are those that are allocated during startup by calls to
- * pthread_key_create; grep for GLOBAL_INIT_THREAD_LOCAL_BUFFER to find those. We need to manually
- * maintain that second number, but pthread_test will fail if we forget.
+/* This slot is only used to pass information from the dynamic linker to
+ * libc.so when the C library is loaded in to memory. The C runtime init
+ * function will then clear it. Since its use is extremely temporary,
+ * we reuse an existing location that isn't needed during libc startup.
*/
-#define GLOBAL_INIT_THREAD_LOCAL_BUFFER_COUNT 4
-#define BIONIC_TLS_SLOTS (64 + TLS_SLOT_FIRST_USER_SLOT + GLOBAL_INIT_THREAD_LOCAL_BUFFER_COUNT)
+#define TLS_SLOT_BIONIC_PREINIT TLS_SLOT_OPENGL_API
/* set the Thread Local Storage, must contain at least BIONIC_TLS_SLOTS pointers */
extern void __init_tls(void** tls, void* thread_info);
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;
- // If this fails, it's likely that GLOBAL_INIT_THREAD_LOCAL_BUFFER_COUNT is wrong.
- ASSERT_EQ(0, pthread_key_create(&key, NULL)) << i << " of " << sysconf(_SC_THREAD_KEYS_MAX);
+ ASSERT_EQ(0, pthread_key_create(&key, NULL));
keys.push_back(key);
}
ASSERT_EQ(0, pthread_key_delete(keys[i]));
}
}
-#endif
static void* IdFn(void* arg) {
return arg;
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)));