aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorandroid-build-team Robot <android-build-team-robot@google.com>2017-10-03 07:29:46 +0000
committerandroid-build-team Robot <android-build-team-robot@google.com>2017-10-03 07:29:46 +0000
commitfcabaf45b7a17a2b67b3a7cc019da4b396966bce (patch)
treed9e4a3e7a14293d7397d1f5d9690703d55f195f4
parent1ec3ea35f4bda556f8a2201ce4573a859271769a (diff)
parent854556c41e20c37b210498b0374415b640104785 (diff)
downloadbionic-oreo-mr1-wear-release.tar.gz
Change-Id: Ic1e94cd5376d06b8cf7b4c26d3f1aec31311159d
-rw-r--r--libc/async_safe/async_safe_log.cpp15
-rw-r--r--libc/bionic/__libc_init_main_thread.cpp2
-rw-r--r--libc/bionic/pthread_create.cpp22
-rw-r--r--libc/bionic/pthread_internal.h2
-rwxr-xr-xtests/pthread_test.cpp46
5 files changed, 66 insertions, 21 deletions
diff --git a/libc/async_safe/async_safe_log.cpp b/libc/async_safe/async_safe_log.cpp
index 99ff0c7f9..bc2a7999a 100644
--- a/libc/async_safe/async_safe_log.cpp
+++ b/libc/async_safe/async_safe_log.cpp
@@ -477,19 +477,6 @@ static int open_log_socket() {
return log_fd;
}
-static clockid_t log_clockid() {
- static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
- ScopedPthreadMutexLocker locker(&mutex);
-
- static CachedProperty ro_logd_timestamp("ro.logd.timestamp");
- static CachedProperty persist_logd_timestamp("persist.logd.timestamp");
-
- char ch = persist_logd_timestamp.Get()[0];
- if (ch == '\0') ch = ro_logd_timestamp.Get()[0];
-
- return (tolower(ch) == 'm') ? CLOCK_MONOTONIC : CLOCK_REALTIME;
-}
-
struct log_time { // Wire format
uint32_t tv_sec;
uint32_t tv_nsec;
@@ -510,7 +497,7 @@ int async_safe_write_log(int priority, const char* tag, const char* msg) {
vec[1].iov_base = &tid;
vec[1].iov_len = sizeof(tid);
timespec ts;
- clock_gettime(log_clockid(), &ts);
+ clock_gettime(CLOCK_REALTIME, &ts);
log_time realtime_ts;
realtime_ts.tv_sec = ts.tv_sec;
realtime_ts.tv_nsec = ts.tv_nsec;
diff --git a/libc/bionic/__libc_init_main_thread.cpp b/libc/bionic/__libc_init_main_thread.cpp
index f3dbfa537..9cbff11af 100644
--- a/libc/bionic/__libc_init_main_thread.cpp
+++ b/libc/bionic/__libc_init_main_thread.cpp
@@ -70,7 +70,7 @@ void __libc_init_main_thread(KernelArgumentBlock& args) {
// set up before we call any function that might get a stack check inserted.
// TLS also needs to be set up before errno (and therefore syscalls) can be used.
__set_tls(main_thread.tls);
- __init_tls(&main_thread);
+ if (!__init_tls(&main_thread)) async_safe_fatal("failed to initialize TLS: %s", strerror(errno));
// Tell the kernel to clear our tid field when we exit, so we're like any other pthread.
// As a side-effect, this tells us our pid (which is the same as the main thread's tid).
diff --git a/libc/bionic/pthread_create.cpp b/libc/bionic/pthread_create.cpp
index ff972c3ec..7a266501d 100644
--- a/libc/bionic/pthread_create.cpp
+++ b/libc/bionic/pthread_create.cpp
@@ -50,7 +50,7 @@ void __init_user_desc(struct user_desc*, bool, void*);
#endif
// This code is used both by each new pthread and the code that initializes the main thread.
-void __init_tls(pthread_internal_t* thread) {
+bool __init_tls(pthread_internal_t* thread) {
// Slot 0 must point to itself. The x86 Linux kernel reads the TLS from %fs:0.
thread->tls[TLS_SLOT_SELF] = thread->tls;
thread->tls[TLS_SLOT_THREAD_ID] = thread;
@@ -59,15 +59,24 @@ void __init_tls(pthread_internal_t* thread) {
size_t allocation_size = BIONIC_TLS_SIZE + 2 * PAGE_SIZE;
void* allocation = mmap(nullptr, allocation_size, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (allocation == MAP_FAILED) {
- async_safe_fatal("failed to allocate TLS: %s", strerror(errno));
+ async_safe_format_log(ANDROID_LOG_WARN, "libc",
+ "pthread_create failed: couldn't allocate TLS: %s", strerror(errno));
+ return false;
}
- prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, allocation, allocation_size, "bionic TLS guard page");
+ prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, allocation, allocation_size, "bionic TLS guard");
+
+ // Carve out the writable TLS section.
thread->bionic_tls = reinterpret_cast<bionic_tls*>(static_cast<char*>(allocation) + PAGE_SIZE);
if (mprotect(thread->bionic_tls, BIONIC_TLS_SIZE, PROT_READ | PROT_WRITE) != 0) {
- async_safe_fatal("failed to mprotect TLS: %s", strerror(errno));
+ async_safe_format_log(ANDROID_LOG_WARN, "libc",
+ "pthread_create failed: couldn't mprotect TLS: %s", strerror(errno));
+ munmap(allocation, allocation_size);
+ return false;
}
+
prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, thread->bionic_tls, BIONIC_TLS_SIZE, "bionic TLS");
+ return true;
}
void __init_thread_stack_guard(pthread_internal_t* thread) {
@@ -192,7 +201,10 @@ static int __allocate_thread(pthread_attr_t* attr, pthread_internal_t** threadp,
thread->mmap_size = mmap_size;
thread->attr = *attr;
- __init_tls(thread);
+ if (!__init_tls(thread)) {
+ if (thread->mmap_size != 0) munmap(thread->attr.stack_base, thread->mmap_size);
+ return EAGAIN;
+ }
__init_thread_stack_guard(thread);
*threadp = thread;
diff --git a/libc/bionic/pthread_internal.h b/libc/bionic/pthread_internal.h
index 6faf5a4ff..4ba6ee059 100644
--- a/libc/bionic/pthread_internal.h
+++ b/libc/bionic/pthread_internal.h
@@ -115,7 +115,7 @@ class pthread_internal_t {
};
__LIBC_HIDDEN__ int __init_thread(pthread_internal_t* thread);
-__LIBC_HIDDEN__ void __init_tls(pthread_internal_t* thread);
+__LIBC_HIDDEN__ bool __init_tls(pthread_internal_t* thread);
__LIBC_HIDDEN__ void __init_thread_stack_guard(pthread_internal_t* thread);
__LIBC_HIDDEN__ void __init_alternate_signal_stack(pthread_internal_t*);
diff --git a/tests/pthread_test.cpp b/tests/pthread_test.cpp
index d64bc48bc..bf6ed9a56 100755
--- a/tests/pthread_test.cpp
+++ b/tests/pthread_test.cpp
@@ -2076,3 +2076,49 @@ TEST(pthread, pthread_spinlock_smoke) {
ASSERT_EQ(0, pthread_spin_unlock(&lock));
ASSERT_EQ(0, pthread_spin_destroy(&lock));
}
+
+TEST(pthread, pthread_attr_setdetachstate) {
+ pthread_attr_t attr;
+ ASSERT_EQ(0, pthread_attr_init(&attr));
+
+ ASSERT_EQ(0, pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED));
+ ASSERT_EQ(0, pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE));
+ ASSERT_EQ(EINVAL, pthread_attr_setdetachstate(&attr, 123));
+}
+
+TEST(pthread, pthread_create__mmap_failures) {
+ pthread_attr_t attr;
+ ASSERT_EQ(0, pthread_attr_init(&attr));
+ ASSERT_EQ(0, pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED));
+
+ const auto kPageSize = sysconf(_SC_PAGE_SIZE);
+
+ // Use up all the VMAs. By default this is 64Ki.
+ std::vector<void*> pages;
+ int prot = PROT_NONE;
+ while (true) {
+ void* page = mmap(nullptr, kPageSize, prot, MAP_ANON|MAP_PRIVATE, -1, 0);
+ if (page == MAP_FAILED) break;
+ pages.push_back(page);
+ prot = (prot == PROT_NONE) ? PROT_READ : PROT_NONE;
+ }
+
+ // Try creating threads, freeing up a page each time we fail.
+ size_t EAGAIN_count = 0;
+ size_t i = 0;
+ for (; i < pages.size(); ++i) {
+ pthread_t t;
+ int status = pthread_create(&t, &attr, IdFn, nullptr);
+ if (status != EAGAIN) break;
+ ++EAGAIN_count;
+ ASSERT_EQ(0, munmap(pages[i], kPageSize));
+ }
+
+ // Creating a thread uses at least six VMAs: the stack, the TLS, and a guard each side of both.
+ // So we should have seen at least six failures.
+ ASSERT_GE(EAGAIN_count, 6U);
+
+ for (; i < pages.size(); ++i) {
+ ASSERT_EQ(0, munmap(pages[i], kPageSize));
+ }
+}