Merge "Ensure <fcntl.h> defines the S_* constants from <sys/stat.h>."
diff --git a/benchmarks/pthread_benchmark.cpp b/benchmarks/pthread_benchmark.cpp
index 92e5998..42023e0 100644
--- a/benchmarks/pthread_benchmark.cpp
+++ b/benchmarks/pthread_benchmark.cpp
@@ -47,6 +47,21 @@
}
BENCHMARK(BM_pthread_getspecific);
+static void BM_pthread_setspecific(int iters) {
+ StopBenchmarkTiming();
+ pthread_key_t key;
+ pthread_key_create(&key, NULL);
+ StartBenchmarkTiming();
+
+ for (int i = 0; i < iters; ++i) {
+ pthread_setspecific(key, NULL);
+ }
+
+ StopBenchmarkTiming();
+ pthread_key_delete(key);
+}
+BENCHMARK(BM_pthread_setspecific);
+
static void DummyPthreadOnceInitFunction() {
}
@@ -137,3 +152,80 @@
pthread_rwlock_destroy(&lock);
}
BENCHMARK(BM_pthread_rw_lock_write);
+
+static void* IdleThread(void*) {
+ return NULL;
+}
+
+static void BM_pthread_create(int iters) {
+ StopBenchmarkTiming();
+ pthread_t thread;
+
+ for (int i = 0; i < iters; ++i) {
+ StartBenchmarkTiming();
+ pthread_create(&thread, NULL, IdleThread, NULL);
+ StopBenchmarkTiming();
+ pthread_join(thread, NULL);
+ }
+}
+BENCHMARK(BM_pthread_create);
+
+static void* RunThread(void*) {
+ StopBenchmarkTiming();
+ return NULL;
+}
+
+static void BM_pthread_create_and_run(int iters) {
+ StopBenchmarkTiming();
+ pthread_t thread;
+
+ for (int i = 0; i < iters; ++i) {
+ StartBenchmarkTiming();
+ pthread_create(&thread, NULL, RunThread, NULL);
+ pthread_join(thread, NULL);
+ }
+}
+BENCHMARK(BM_pthread_create_and_run);
+
+static void* ExitThread(void*) {
+ StartBenchmarkTiming();
+ pthread_exit(NULL);
+}
+
+static void BM_pthread_exit_and_join(int iters) {
+ StopBenchmarkTiming();
+ pthread_t thread;
+
+ for (int i = 0; i < iters; ++i) {
+ pthread_create(&thread, NULL, ExitThread, NULL);
+ pthread_join(thread, NULL);
+ StopBenchmarkTiming();
+ }
+}
+BENCHMARK(BM_pthread_exit_and_join);
+
+static void BM_pthread_key_create(int iters) {
+ StopBenchmarkTiming();
+ pthread_key_t key;
+
+ for (int i = 0; i < iters; ++i) {
+ StartBenchmarkTiming();
+ pthread_key_create(&key, NULL);
+ StopBenchmarkTiming();
+ pthread_key_delete(key);
+ }
+}
+BENCHMARK(BM_pthread_key_create);
+
+static void BM_pthread_key_delete(int iters) {
+ StopBenchmarkTiming();
+ pthread_key_t key;
+
+ for (int i = 0; i < iters; ++i) {
+ pthread_key_create(&key, NULL);
+ StartBenchmarkTiming();
+ pthread_key_delete(key);
+ StopBenchmarkTiming();
+ }
+}
+BENCHMARK(BM_pthread_key_delete);
diff --git a/libc/NOTICE b/libc/NOTICE
index 697b8fc..1fa31c2 100644
--- a/libc/NOTICE
+++ b/libc/NOTICE
@@ -1679,35 +1679,6 @@
-------------------------------------------------------------------
-Copyright (c) 1990 Regents of the University of California.
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions
-are met:
-1. Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
-2. 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.
-3. Neither the name of the University nor the names of its contributors
- may be used to endorse or promote products derived from this software
- without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
-
--------------------------------------------------------------------
-
Copyright (c) 1990 The Regents of the University of California.
All rights reserved.
@@ -2539,33 +2510,6 @@
-------------------------------------------------------------------
-Copyright (c) 1993 Christopher G. Demetriou
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions
-are met:
-1. Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
-2. 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.
-3. The name of the author may not be used to endorse or promote products
- derived from this software without specific prior written permission
-
-THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
-
--------------------------------------------------------------------
-
Copyright (c) 1993 Martin Birgmeier
All rights reserved.
@@ -2685,63 +2629,6 @@
-------------------------------------------------------------------
-Copyright (c) 1996-2004 Per Fogelstrom, Opsycon AB
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions
-are met:
-1. Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
-2. 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 AUTHOR ``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 AUTHOR 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.
-
--------------------------------------------------------------------
-
-Copyright (c) 1997 Mark Brinicombe
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions
-are met:
-1. Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
-2. 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.
-3. All advertising materials mentioning features or use of this software
- must display the following acknowledgement:
- This product includes software developed by Mark Brinicombe
-4. Neither the name of the University nor the names of its contributors
- may be used to endorse or promote products derived from this software
- without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
-
--------------------------------------------------------------------
-
Copyright (c) 1997 Mark Brinicombe
Copyright (c) 2010 Android Open Source Project.
All rights reserved.
@@ -3365,34 +3252,6 @@
-------------------------------------------------------------------
-Copyright (c) 2002 Opsycon AB (www.opsycon.se / www.opsycon.com)
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions
-are met:
-1. Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
-2. 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.
-3. Neither the name of Opsycon AB nor the names of its contributors
- may be used to endorse or promote products derived from this software
- without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
-
--------------------------------------------------------------------
-
Copyright (c) 2002 The NetBSD Foundation, Inc.
All rights reserved.
@@ -4025,6 +3884,22 @@
-------------------------------------------------------------------
+Copyright (c) 2008 Otto Moerbeek <otto@drijf.net>
+
+Permission to use, copy, modify, and distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+-------------------------------------------------------------------
+
Copyright (c) 2008 Todd C. Miller <millert@openbsd.org>
Permission to use, copy, modify, and distribute this software for any
@@ -4611,35 +4486,32 @@
-------------------------------------------------------------------
-Copyright (c) 2013, Linaro Limited
- All rights reserved.
+Copyright (c) 2013 The NetBSD Foundation, Inc.
+All rights reserved.
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions
- are met:
+This code is derived from software contributed to The NetBSD Foundation
+by Christos Zoulas.
- * Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. 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.
- * 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.
-
- * Neither the name of Linaro Limited nor the names of its
- contributors may be used to endorse or promote products derived
- from this software without specific prior written permission.
-
- 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
- HOLDER 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.
+THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
-------------------------------------------------------------------
diff --git a/libc/arch-mips/include/machine/elf_machdep.h b/libc/arch-mips/include/machine/elf_machdep.h
index d27d431..0aacedf 100644
--- a/libc/arch-mips/include/machine/elf_machdep.h
+++ b/libc/arch-mips/include/machine/elf_machdep.h
@@ -121,6 +121,7 @@
#define DT_MIPS_GOTSYM 0x70000013 /* first dynamic sym in got */
#define DT_MIPS_HIPAGENO 0x70000014
#define DT_MIPS_RLD_MAP 0x70000016 /* address of loader map */
+#define DT_MIPS_RLD_MAP2 0x70000035 /* offset of loader map, used for PIE */
/*
* ELF Flags
diff --git a/libc/bionic/libc_init_common.cpp b/libc/bionic/libc_init_common.cpp
index 2a6a03b..15b3fd5 100644
--- a/libc/bionic/libc_init_common.cpp
+++ b/libc/bionic/libc_init_common.cpp
@@ -74,9 +74,7 @@
void __libc_init_tls(KernelArgumentBlock& args) {
__libc_auxv = args.auxv;
- static void* tls[BIONIC_TLS_SLOTS];
static pthread_internal_t main_thread;
- main_thread.tls = tls;
// 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).
@@ -96,7 +94,7 @@
__init_thread(&main_thread, false);
__init_tls(&main_thread);
__set_tls(main_thread.tls);
- tls[TLS_SLOT_BIONIC_PREINIT] = &args;
+ main_thread.tls[TLS_SLOT_BIONIC_PREINIT] = &args;
__init_alternate_signal_stack(&main_thread);
}
diff --git a/libc/bionic/pthread_create.cpp b/libc/bionic/pthread_create.cpp
index c99e69c..c47b750 100644
--- a/libc/bionic/pthread_create.cpp
+++ b/libc/bionic/pthread_create.cpp
@@ -35,6 +35,7 @@
#include "pthread_internal.h"
#include "private/bionic_macros.h"
+#include "private/bionic_prctl.h"
#include "private/bionic_ssp.h"
#include "private/bionic_tls.h"
#include "private/libc_logging.h"
@@ -72,6 +73,10 @@
ss.ss_flags = 0;
sigaltstack(&ss, NULL);
thread->alternate_signal_stack = ss.ss_sp;
+
+ // We can only use const static allocated string for mapped region name, as Android kernel
+ // uses the string pointer directly when dumping /proc/pid/maps.
+ prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, ss.ss_sp, ss.ss_size, "thread signal stack");
}
}
@@ -101,31 +106,64 @@
return error;
}
-static void* __create_thread_stack(pthread_internal_t* thread) {
+static void* __create_thread_stack(const pthread_attr_t& attr) {
// Create a new private anonymous map.
int prot = PROT_READ | PROT_WRITE;
int flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE;
- void* stack = mmap(NULL, thread->attr.stack_size, prot, flags, -1, 0);
+ void* stack = mmap(NULL, attr.stack_size, prot, flags, -1, 0);
if (stack == MAP_FAILED) {
__libc_format_log(ANDROID_LOG_WARN,
"libc",
"pthread_create failed: couldn't allocate %zd-byte stack: %s",
- thread->attr.stack_size, strerror(errno));
+ attr.stack_size, strerror(errno));
return NULL;
}
// Set the guard region at the end of the stack to PROT_NONE.
- if (mprotect(stack, thread->attr.guard_size, PROT_NONE) == -1) {
+ if (mprotect(stack, attr.guard_size, PROT_NONE) == -1) {
__libc_format_log(ANDROID_LOG_WARN, "libc",
"pthread_create failed: couldn't mprotect PROT_NONE %zd-byte stack guard region: %s",
- thread->attr.guard_size, strerror(errno));
- munmap(stack, thread->attr.stack_size);
+ attr.guard_size, strerror(errno));
+ munmap(stack, attr.stack_size);
return NULL;
}
return stack;
}
+static int __allocate_thread(pthread_attr_t* attr, pthread_internal_t** threadp, void** child_stack) {
+ if (attr->stack_base == NULL) {
+ // The caller didn't provide a stack, so allocate one.
+ // Make sure the stack size and guard size are multiples of PAGE_SIZE.
+ attr->stack_size = BIONIC_ALIGN(attr->stack_size, PAGE_SIZE);
+ attr->guard_size = BIONIC_ALIGN(attr->guard_size, PAGE_SIZE);
+ attr->stack_base = __create_thread_stack(*attr);
+ if (attr->stack_base == NULL) {
+ return EAGAIN;
+ }
+ } else {
+ // The caller did provide a stack, so remember we're not supposed to free it.
+ attr->flags |= PTHREAD_ATTR_FLAG_USER_ALLOCATED_STACK;
+ }
+
+ // Thread stack is used for two sections:
+ // pthread_internal_t.
+ // regular stack, from top to down.
+ uint8_t* stack_top = reinterpret_cast<uint8_t*>(attr->stack_base) + attr->stack_size;
+ stack_top -= sizeof(pthread_internal_t);
+ pthread_internal_t* thread = reinterpret_cast<pthread_internal_t*>(stack_top);
+
+ // No need to check stack_top alignment. The size of pthread_internal_t is 16-bytes aligned,
+ // and user allocated stack is guaranteed by pthread_attr_setstack.
+
+ thread->attr = *attr;
+ __init_tls(thread);
+
+ *threadp = thread;
+ *child_stack = stack_top;
+ return 0;
+}
+
static int __pthread_start(void* arg) {
pthread_internal_t* thread = reinterpret_cast<pthread_internal_t*>(arg);
@@ -158,43 +196,21 @@
// Inform the rest of the C library that at least one thread was created.
__isthreaded = 1;
- pthread_internal_t* thread = __create_thread_struct();
- if (thread == NULL) {
- return EAGAIN;
- }
-
+ pthread_attr_t thread_attr;
if (attr == NULL) {
- pthread_attr_init(&thread->attr);
+ pthread_attr_init(&thread_attr);
} else {
- thread->attr = *attr;
+ thread_attr = *attr;
attr = NULL; // Prevent misuse below.
}
- // Make sure the stack size and guard size are multiples of PAGE_SIZE.
- thread->attr.stack_size = BIONIC_ALIGN(thread->attr.stack_size, PAGE_SIZE);
- thread->attr.guard_size = BIONIC_ALIGN(thread->attr.guard_size, PAGE_SIZE);
-
- if (thread->attr.stack_base == NULL) {
- // The caller didn't provide a stack, so allocate one.
- thread->attr.stack_base = __create_thread_stack(thread);
- if (thread->attr.stack_base == NULL) {
- __free_thread_struct(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_ALLOCATED_STACK;
+ pthread_internal_t* thread = NULL;
+ void* child_stack = NULL;
+ int result = __allocate_thread(&thread_attr, &thread, &child_stack);
+ if (result != 0) {
+ return result;
}
- // Make room for the TLS area.
- // The child stack is the same address, just growing in the opposite direction.
- // At offsets >= 0, we have the TLS slots.
- // At offsets < 0, we have the child stack.
- thread->tls = reinterpret_cast<void**>(reinterpret_cast<uint8_t*>(thread->attr.stack_base) +
- thread->attr.stack_size - BIONIC_ALIGN(BIONIC_TLS_SLOTS * sizeof(void*), 16));
- void* child_stack = thread->tls;
- __init_tls(thread);
-
// Create a mutex for the thread in TLS to wait on once it starts so we can keep
// it from doing anything until after we notify the debugger about it
//
@@ -211,7 +227,7 @@
int flags = CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_THREAD | CLONE_SYSVSEM |
CLONE_SETTLS | CLONE_PARENT_SETTID | CLONE_CHILD_CLEARTID;
- void* tls = thread->tls;
+ void* tls = reinterpret_cast<void*>(thread->tls);
#if defined(__i386__)
// On x86 (but not x86-64), CLONE_SETTLS takes a pointer to a struct user_desc rather than
// a pointer to the TLS itself.
@@ -229,7 +245,6 @@
if (!thread->user_allocated_stack()) {
munmap(thread->attr.stack_base, thread->attr.stack_size);
}
- __free_thread_struct(thread);
__libc_format_log(ANDROID_LOG_WARN, "libc", "pthread_create failed: clone failed: %s", strerror(errno));
return clone_errno;
}
diff --git a/libc/bionic/pthread_detach.cpp b/libc/bionic/pthread_detach.cpp
index a8608e3..715acf1 100644
--- a/libc/bionic/pthread_detach.cpp
+++ b/libc/bionic/pthread_detach.cpp
@@ -46,7 +46,7 @@
if (thread->tid == 0) {
// Already exited; clean up.
- _pthread_internal_remove_locked(thread.get());
+ _pthread_internal_remove_locked(thread.get(), true);
return 0;
}
diff --git a/libc/bionic/pthread_exit.cpp b/libc/bionic/pthread_exit.cpp
index a6bb363..e04cf8e 100644
--- a/libc/bionic/pthread_exit.cpp
+++ b/libc/bionic/pthread_exit.cpp
@@ -90,7 +90,7 @@
// Keep track of what we need to know about the stack before we lose the pthread_internal_t.
void* stack_base = thread->attr.stack_base;
size_t stack_size = thread->attr.stack_size;
- bool user_allocated_stack = thread->user_allocated_stack();
+ bool free_stack = false;
pthread_mutex_lock(&g_thread_list_lock);
if ((thread->attr.flags & PTHREAD_ATTR_FLAG_DETACHED) != 0) {
@@ -98,24 +98,18 @@
// First make sure that the kernel does not try to clear the tid field
// because we'll have freed the memory before the thread actually exits.
__set_tid_address(NULL);
- _pthread_internal_remove_locked(thread);
- } else {
- // Make sure that the pthread_internal_t doesn't have stale pointers to a stack that
- // will be unmapped after the exit call below.
- if (!user_allocated_stack) {
- thread->attr.stack_base = NULL;
- thread->attr.stack_size = 0;
- thread->tls = NULL;
+
+ // pthread_internal_t is freed below with stack, not here.
+ _pthread_internal_remove_locked(thread, false);
+ if (!thread->user_allocated_stack()) {
+ free_stack = true;
}
- // pthread_join is responsible for destroying the pthread_internal_t for non-detached threads.
- // The kernel will futex_wake on the pthread_internal_t::tid field to wake pthread_join.
}
pthread_mutex_unlock(&g_thread_list_lock);
- if (user_allocated_stack) {
- // Cleaning up this thread's stack is the creator's responsibility, not ours.
- __exit(0);
- } else {
+ // Detached threads exit with stack teardown, and everything deallocated here.
+ // Threads that can be joined exit but leave their stacks for the pthread_join caller to clean up.
+ if (free_stack) {
// We need to munmap the stack we're running on before calling exit.
// That's not something we can do in C.
@@ -126,5 +120,7 @@
sigprocmask(SIG_SETMASK, &mask, NULL);
_exit_with_stack_teardown(stack_base, stack_size);
+ } else {
+ __exit(0);
}
}
diff --git a/libc/bionic/pthread_internal.h b/libc/bionic/pthread_internal.h
index c5136c9..95097b7 100644
--- a/libc/bionic/pthread_internal.h
+++ b/libc/bionic/pthread_internal.h
@@ -30,6 +30,8 @@
#include <pthread.h>
+#include "private/bionic_tls.h"
+
/* Has the thread been detached by a pthread_join or pthread_detach call? */
#define PTHREAD_ATTR_FLAG_DETACHED 0x00000001
@@ -72,8 +74,6 @@
return (attr.flags & PTHREAD_ATTR_FLAG_USER_ALLOCATED_STACK) != 0;
}
- void** tls;
-
pthread_attr_t attr;
__pthread_cleanup_t* cleanup_stack;
@@ -86,16 +86,16 @@
pthread_mutex_t startup_handshake_mutex;
+ void* tls[BIONIC_TLS_SLOTS];
+
/*
* The dynamic linker implements dlerror(3), which makes it hard for us to implement this
* per-thread buffer by simply using malloc(3) and free(3).
*/
#define __BIONIC_DLERROR_BUFFER_SIZE 512
char dlerror_buffer[__BIONIC_DLERROR_BUFFER_SIZE];
-};
+} __attribute__((aligned(16))); // Align it as thread stack top below it should be aligned.
-__LIBC_HIDDEN__ pthread_internal_t* __create_thread_struct();
-__LIBC_HIDDEN__ void __free_thread_struct(pthread_internal_t*);
__LIBC_HIDDEN__ int __init_thread(pthread_internal_t* thread, bool add_to_thread_list);
__LIBC_HIDDEN__ void __init_tls(pthread_internal_t* thread);
__LIBC_HIDDEN__ void __init_alternate_signal_stack(pthread_internal_t*);
@@ -105,7 +105,7 @@
extern "C" __LIBC64_HIDDEN__ pthread_internal_t* __get_thread(void);
__LIBC_HIDDEN__ void pthread_key_clean_all(void);
-__LIBC_HIDDEN__ void _pthread_internal_remove_locked(pthread_internal_t* thread);
+__LIBC_HIDDEN__ void _pthread_internal_remove_locked(pthread_internal_t* thread, bool free_thread);
/*
* Traditionally we gave threads a 1MiB stack. When we started
diff --git a/libc/bionic/pthread_internals.cpp b/libc/bionic/pthread_internals.cpp
index 33cddd7..7c30e6e 100644
--- a/libc/bionic/pthread_internals.cpp
+++ b/libc/bionic/pthread_internals.cpp
@@ -41,26 +41,7 @@
pthread_internal_t* g_thread_list = NULL;
pthread_mutex_t g_thread_list_lock = PTHREAD_MUTEX_INITIALIZER;
-pthread_internal_t* __create_thread_struct() {
- void* result = mmap(NULL, sizeof(pthread_internal_t), PROT_READ | PROT_WRITE,
- MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0);
- if (result == MAP_FAILED) {
- __libc_format_log(ANDROID_LOG_WARN, "libc",
- "__create_thread_struct() failed: %s", strerror(errno));
- return NULL;
- }
- return reinterpret_cast<pthread_internal_t*>(result);
-}
-
-void __free_thread_struct(pthread_internal_t* thread) {
- int result = munmap(thread, sizeof(pthread_internal_t));
- if (result != 0) {
- __libc_format_log(ANDROID_LOG_WARN, "libc",
- "__free_thread_struct() failed: %s", strerror(errno));
- }
-}
-
-void _pthread_internal_remove_locked(pthread_internal_t* thread) {
+void _pthread_internal_remove_locked(pthread_internal_t* thread, bool free_thread) {
if (thread->next != NULL) {
thread->next->prev = thread->prev;
}
@@ -70,10 +51,11 @@
g_thread_list = thread->next;
}
- // The main thread is not heap-allocated. See __libc_init_tls for the declaration,
- // and __libc_init_common for the point where it's added to the thread list.
- if ((thread->attr.flags & PTHREAD_ATTR_FLAG_MAIN_THREAD) == 0) {
- __free_thread_struct(thread);
+ // For threads using user allocated stack (including the main thread), the pthread_internal_t
+ // can't be freed since it is on the stack.
+ if (free_thread && !(thread->attr.flags & PTHREAD_ATTR_FLAG_USER_ALLOCATED_STACK)) {
+ // Use one munmap to free the whole thread stack, including pthread_internal_t.
+ munmap(thread->attr.stack_base, thread->attr.stack_size);
}
}
diff --git a/libc/bionic/pthread_join.cpp b/libc/bionic/pthread_join.cpp
index 0cbed62..e3350ef 100644
--- a/libc/bionic/pthread_join.cpp
+++ b/libc/bionic/pthread_join.cpp
@@ -74,6 +74,6 @@
*return_value = thread->return_value;
}
- _pthread_internal_remove_locked(thread.get());
+ _pthread_internal_remove_locked(thread.get(), true);
return 0;
}
diff --git a/libc/bionic/pthread_key.cpp b/libc/bionic/pthread_key.cpp
index b47ef22..49b72e9 100644
--- a/libc/bionic/pthread_key.cpp
+++ b/libc/bionic/pthread_key.cpp
@@ -213,16 +213,6 @@
// Clear value in all threads.
pthread_mutex_lock(&g_thread_list_lock);
for (pthread_internal_t* t = g_thread_list; t != NULL; t = t->next) {
- // Skip zombie threads. They don't have a valid TLS area any more.
- // Similarly, it is possible to have t->tls == NULL for threads that
- // were just recently created through pthread_create() but whose
- // startup trampoline (__pthread_start) hasn't been run yet by the
- // scheduler. t->tls will also be NULL after a thread's stack has been
- // unmapped but before the ongoing pthread_join() is finished.
- if (t->tid == 0 || t->tls == NULL) {
- continue;
- }
-
t->tls[key] = NULL;
}
tls_map.DeleteKey(key);
diff --git a/libc/bionic/stubs.cpp b/libc/bionic/stubs.cpp
index 88e5ac5..ab67935 100644
--- a/libc/bionic/stubs.cpp
+++ b/libc/bionic/stubs.cpp
@@ -42,18 +42,44 @@
#include "private/libc_logging.h"
#include "private/ThreadLocalBuffer.h"
-GLOBAL_INIT_THREAD_LOCAL_BUFFER(stubs);
+// POSIX seems to envisage an implementation where the <pwd.h> functions are
+// implemented by brute-force searching with getpwent(3), and the <grp.h>
+// functions are implemented similarly with getgrent(3). This means that it's
+// okay for all the <grp.h> functions to share state, and all the <passwd.h>
+// functions to share state, but <grp.h> functions can't clobber <passwd.h>
+// functions' state and vice versa.
-struct stubs_state_t {
- passwd passwd_;
+GLOBAL_INIT_THREAD_LOCAL_BUFFER(group);
+
+struct group_state_t {
group group_;
char* group_members_[2];
- char app_name_buffer_[32];
char group_name_buffer_[32];
+};
+
+static group_state_t* __group_state() {
+ LOCAL_INIT_THREAD_LOCAL_BUFFER(group_state_t*, group, sizeof(group_state_t));
+ if (group_tls_buffer != NULL) {
+ memset(group_tls_buffer, 0, sizeof(group_state_t));
+ group_tls_buffer->group_.gr_mem = group_tls_buffer->group_members_;
+ }
+ return group_tls_buffer;
+}
+
+GLOBAL_INIT_THREAD_LOCAL_BUFFER(passwd);
+
+struct passwd_state_t {
+ passwd passwd_;
+ char app_name_buffer_[32];
char dir_buffer_[32];
char sh_buffer_[32];
};
+static passwd_state_t* __passwd_state() {
+ LOCAL_INIT_THREAD_LOCAL_BUFFER(passwd_state_t*, passwd, sizeof(passwd_state_t));
+ return passwd_tls_buffer;
+}
+
static int do_getpw_r(int by_name, const char* name, uid_t uid,
passwd* dst, char* buf, size_t byte_count,
passwd** result) {
@@ -91,7 +117,7 @@
// pw_passwd and pw_gecos are non-POSIX and unused (always NULL) in bionic.
dst->pw_passwd = NULL;
-#ifdef __LP64__
+#if defined(__LP64__)
dst->pw_gecos = NULL;
#endif
@@ -113,17 +139,7 @@
return do_getpw_r(0, NULL, uid, pwd, buf, byte_count, result);
}
-static stubs_state_t* __stubs_state() {
- LOCAL_INIT_THREAD_LOCAL_BUFFER(stubs_state_t*, stubs, sizeof(stubs_state_t));
-
- if (stubs_tls_buffer != NULL) {
- memset(stubs_tls_buffer, 0, sizeof(stubs_state_t));
- stubs_tls_buffer->group_.gr_mem = stubs_tls_buffer->group_members_;
- }
- return stubs_tls_buffer;
-}
-
-static passwd* android_iinfo_to_passwd(stubs_state_t* state,
+static passwd* android_iinfo_to_passwd(passwd_state_t* state,
const android_id_info* iinfo) {
snprintf(state->dir_buffer_, sizeof(state->dir_buffer_), "/");
snprintf(state->sh_buffer_, sizeof(state->sh_buffer_), "/system/bin/sh");
@@ -145,7 +161,7 @@
return gr;
}
-static passwd* android_id_to_passwd(stubs_state_t* state, unsigned id) {
+static passwd* android_id_to_passwd(passwd_state_t* state, unsigned id) {
for (size_t n = 0; n < android_id_count; ++n) {
if (android_ids[n].aid == id) {
return android_iinfo_to_passwd(state, android_ids + n);
@@ -154,7 +170,7 @@
return NULL;
}
-static passwd* android_name_to_passwd(stubs_state_t* state, const char* name) {
+static passwd* android_name_to_passwd(passwd_state_t* state, const char* name) {
for (size_t n = 0; n < android_id_count; ++n) {
if (!strcmp(android_ids[n].name, name)) {
return android_iinfo_to_passwd(state, android_ids + n);
@@ -297,9 +313,7 @@
// AID_ISOLATED_START to AID_USER-1 -> u0_i1234
// AID_USER+ -> u1_radio, u1_a1234, u2_i1234, etc.
// returns a passwd structure (sets errno to ENOENT on failure).
-static passwd* app_id_to_passwd(uid_t uid, stubs_state_t* state) {
- passwd* pw = &state->passwd_;
-
+static passwd* app_id_to_passwd(uid_t uid, passwd_state_t* state) {
if (uid < AID_APP) {
errno = ENOENT;
return NULL;
@@ -316,18 +330,18 @@
snprintf(state->sh_buffer_, sizeof(state->sh_buffer_), "/system/bin/sh");
+ passwd* pw = &state->passwd_;
pw->pw_name = state->app_name_buffer_;
pw->pw_dir = state->dir_buffer_;
pw->pw_shell = state->sh_buffer_;
pw->pw_uid = uid;
pw->pw_gid = uid;
-
return pw;
}
// Translate a gid into the corresponding app_<gid>
// group structure (sets errno to ENOENT on failure).
-static group* app_id_to_group(gid_t gid, stubs_state_t* state) {
+static group* app_id_to_group(gid_t gid, group_state_t* state) {
if (gid < AID_APP) {
errno = ENOENT;
return NULL;
@@ -339,13 +353,11 @@
gr->gr_name = state->group_name_buffer_;
gr->gr_gid = gid;
gr->gr_mem[0] = gr->gr_name;
-
return gr;
}
-
passwd* getpwuid(uid_t uid) { // NOLINT: implementing bad function.
- stubs_state_t* state = __stubs_state();
+ passwd_state_t* state = __passwd_state();
if (state == NULL) {
return NULL;
}
@@ -358,7 +370,7 @@
}
passwd* getpwnam(const char* login) { // NOLINT: implementing bad function.
- stubs_state_t* state = __stubs_state();
+ passwd_state_t* state = __passwd_state();
if (state == NULL) {
return NULL;
}
@@ -372,12 +384,12 @@
// All users are in just one group, the one passed in.
int getgrouplist(const char* /*user*/, gid_t group, gid_t* groups, int* ngroups) {
- if (*ngroups < 1) {
- *ngroups = 1;
- return -1;
- }
- groups[0] = group;
- return (*ngroups = 1);
+ if (*ngroups < 1) {
+ *ngroups = 1;
+ return -1;
+ }
+ groups[0] = group;
+ return (*ngroups = 1);
}
char* getlogin() { // NOLINT: implementing bad function.
@@ -386,7 +398,7 @@
}
group* getgrgid(gid_t gid) { // NOLINT: implementing bad function.
- stubs_state_t* state = __stubs_state();
+ group_state_t* state = __group_state();
if (state == NULL) {
return NULL;
}
@@ -399,7 +411,7 @@
}
group* getgrnam(const char* name) { // NOLINT: implementing bad function.
- stubs_state_t* state = __stubs_state();
+ group_state_t* state = __group_state();
if (state == NULL) {
return NULL;
}
diff --git a/libc/dns/gethnamaddr.c b/libc/dns/net/gethnamaddr.c
similarity index 99%
rename from libc/dns/gethnamaddr.c
rename to libc/dns/net/gethnamaddr.c
index 63a6a60..8f5800a 100644
--- a/libc/dns/gethnamaddr.c
+++ b/libc/dns/net/gethnamaddr.c
@@ -1208,7 +1208,7 @@
free(buf);
__res_put_state(res);
if (hp == NULL)
- switch (h_errno) {
+ switch (*info->he) {
case HOST_NOT_FOUND:
return NS_NOTFOUND;
case TRY_AGAIN:
@@ -1326,6 +1326,7 @@
*info->he = NETDB_SUCCESS;
return NS_SUCCESS;
nospc:
+ errno = ENOSPC;
*info->he = NETDB_INTERNAL;
return NS_UNAVAIL;
}
diff --git a/libc/dns/net/nsdispatch.c b/libc/dns/net/nsdispatch.c
index fb6d8f6..d025592 100644
--- a/libc/dns/net/nsdispatch.c
+++ b/libc/dns/net/nsdispatch.c
@@ -71,6 +71,7 @@
#include <sys/cdefs.h>
#include <assert.h>
+#include <errno.h>
#include <nsswitch.h>
#include <stdarg.h>
#include <strings.h>
@@ -133,6 +134,10 @@
continue;
if (result & srclist[i].flags)
break;
+ /* Stop trying next resolver when there is a memory space fatal error. */
+ if ((result & NS_UNAVAIL) != 0 && errno == ENOSPC) {
+ break;
+ }
}
}
result &= NS_STATUSMASK; /* clear private flags in result */
diff --git a/libc/dns/net/sethostent.c b/libc/dns/net/sethostent.c
index f501c8b..916421e 100644
--- a/libc/dns/net/sethostent.c
+++ b/libc/dns/net/sethostent.c
@@ -116,7 +116,9 @@
hp = _hf_gethtbyname2(name, af, info);
#endif
if (hp == NULL) {
- *info->he = HOST_NOT_FOUND;
+ if (*info->he == NETDB_INTERNAL && errno == ENOSPC) {
+ return NS_UNAVAIL;
+ }
return NS_NOTFOUND;
}
return NS_SUCCESS;
@@ -159,8 +161,12 @@
hp = netbsd_gethostent_r(hf, info->hp, info->buf, info->buflen,
info->he);
- if (hp == NULL)
+ if (hp == NULL) {
+ if (*info->he == NETDB_INTERNAL && errno == ENOSPC) {
+ goto nospc;
+ }
break;
+ }
if (strcasecmp(hp->h_name, name) != 0) {
char **cp;
@@ -259,6 +265,9 @@
endhostent_r(&hf);
if (hp == NULL) {
+ if (errno == ENOSPC) {
+ return NS_UNAVAIL;
+ }
*info->he = HOST_NOT_FOUND;
return NS_NOTFOUND;
}
diff --git a/libc/include/sys/cdefs.h b/libc/include/sys/cdefs.h
index 6f238a9..21d59fa 100644
--- a/libc/include/sys/cdefs.h
+++ b/libc/include/sys/cdefs.h
@@ -77,7 +77,9 @@
#define __GNUC_PREREQ(x, y) 0
#endif
-#include <sys/cdefs_elf.h>
+#define __strong_alias(alias, sym) \
+ __asm__(".global " #alias "\n" \
+ #alias " = " #sym);
#if defined(__cplusplus)
#define __BEGIN_DECLS extern "C" {
@@ -263,13 +265,6 @@
#endif
#endif /* !(__STDC_VERSION__ >= 199901L) */
-#if defined(_KERNEL)
-#if defined(NO_KERNEL_RCSIDS)
-#undef __KERNEL_RCSID
-#define __KERNEL_RCSID(_n, _s) /* nothing */
-#endif /* NO_KERNEL_RCSIDS */
-#endif /* _KERNEL */
-
/*
* A barrier to stop the optimizer from moving code or assume live
* register values. This is gcc specific, the version is more or less
diff --git a/libc/include/sys/cdefs_elf.h b/libc/include/sys/cdefs_elf.h
deleted file mode 100644
index a40a867..0000000
--- a/libc/include/sys/cdefs_elf.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/* $NetBSD: cdefs_elf.h,v 1.22 2005/02/26 22:25:34 perry Exp $ */
-
-/*
- * Copyright (c) 1995, 1996 Carnegie-Mellon University.
- * All rights reserved.
- *
- * Author: Chris G. Demetriou
- *
- * Permission to use, copy, modify and distribute this software and
- * its documentation is hereby granted, provided that both the copyright
- * notice and this permission notice appear in all copies of the
- * software, derivative works or modified versions, and any portions
- * thereof, and that both notices appear in supporting documentation.
- *
- * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
- * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
- * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
- *
- * Carnegie Mellon requests users of this software to return to
- *
- * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
- * School of Computer Science
- * Carnegie Mellon University
- * Pittsburgh PA 15213-3890
- *
- * any improvements or extensions that they make and grant Carnegie the
- * rights to redistribute these changes.
- */
-
-#ifndef _SYS_CDEFS_ELF_H_
-#define _SYS_CDEFS_ELF_H_
-
-#define __strong_alias(alias, sym) \
- __asm__(".global " #alias "\n" \
- #alias " = " #sym);
-
-/* We use __warnattr instead of __warn_references.
- * TODO: remove this and put an empty definition in one of the upstream-* compatibility headers.
- */
-#define __warn_references(sym,msg) \
- /*__asm__(".section .gnu.warning." #sym "\n\t.ascii \"" msg "\"\n\t.text");*/
-
-#endif /* !_SYS_CDEFS_ELF_H_ */
diff --git a/libc/include/sys/stat.h b/libc/include/sys/stat.h
index 5c82a5b..7017865 100644
--- a/libc/include/sys/stat.h
+++ b/libc/include/sys/stat.h
@@ -29,7 +29,6 @@
#ifndef _SYS_STAT_H_
#define _SYS_STAT_H_
-#include <endian.h>
#include <linux/stat.h>
#include <machine/timespec.h>
#include <sys/cdefs.h>
@@ -39,15 +38,15 @@
#if defined(__aarch64__)
#define __STAT64_BODY \
- unsigned long st_dev; \
- unsigned long st_ino; \
- unsigned int st_mode; \
- unsigned int st_nlink; \
+ dev_t st_dev; \
+ ino_t st_ino; \
+ mode_t st_mode; \
+ nlink_t st_nlink; \
uid_t st_uid; \
gid_t st_gid; \
- unsigned long st_rdev; \
+ dev_t st_rdev; \
unsigned long __pad1; \
- long st_size; \
+ off_t st_size; \
int st_blksize; \
int __pad2; \
long st_blocks; \
@@ -57,13 +56,13 @@
unsigned int __unused4; \
unsigned int __unused5; \
-#elif defined(__mips__)
+#elif defined(__mips__) /* and mips64 */
#define __STAT64_BODY \
unsigned int st_dev; \
unsigned int __pad0[3]; \
unsigned long long st_ino; \
- unsigned int st_mode; \
- unsigned int st_nlink; \
+ mode_t st_mode; \
+ nlink_t st_nlink; \
uid_t st_uid; \
gid_t st_gid; \
unsigned int st_rdev; \
@@ -94,13 +93,13 @@
struct timespec st_ctim; \
long __pad3[3]; \
-#else
+#else /* __arm__ || __i386__ */
#define __STAT64_BODY \
unsigned long long st_dev; \
unsigned char __pad0[4]; \
unsigned long __st_ino; \
unsigned int st_mode; \
- unsigned int st_nlink; \
+ nlink_t st_nlink; \
uid_t st_uid; \
gid_t st_gid; \
unsigned long long st_rdev; \
diff --git a/libc/private/bionic_tls.h b/libc/private/bionic_tls.h
index 4a35166..944f957 100644
--- a/libc/private/bionic_tls.h
+++ b/libc/private/bionic_tls.h
@@ -85,7 +85,8 @@
* ttyname libc (GLOBAL_INIT_THREAD_LOCAL_BUFFER)
* strerror libc (GLOBAL_INIT_THREAD_LOCAL_BUFFER)
* strsignal libc (GLOBAL_INIT_THREAD_LOCAL_BUFFER)
- * stubs libc (GLOBAL_INIT_THREAD_LOCAL_BUFFER)
+ * passwd libc (GLOBAL_INIT_THREAD_LOCAL_BUFFER)
+ * group libc (GLOBAL_INIT_THREAD_LOCAL_BUFFER)
* _res_key libc
* je_thread_allocated_tsd jemalloc
* je_arenas_tsd jemalloc
@@ -95,7 +96,7 @@
*
*/
-#define LIBC_TLS_RESERVED_SLOTS 11
+#define LIBC_TLS_RESERVED_SLOTS 12
#if defined(USE_JEMALLOC)
/* jemalloc uses 5 keys for itself. */
diff --git a/libc/tools/generate-NOTICE.py b/libc/tools/generate-NOTICE.py
index 3edc299..79b4ea9 100755
--- a/libc/tools/generate-NOTICE.py
+++ b/libc/tools/generate-NOTICE.py
@@ -1,7 +1,7 @@
#!/usr/bin/python
# Run with directory arguments from any directory, with no special setup required.
# Or:
-# for i in libc libdl libm linker libstdc++ libthread_db ; do ./libc/tools/generate-NOTICE.py $i > $i/NOTICE ; done
+# for i in libc libdl libm linker libstdc++ ; do ./libc/tools/generate-NOTICE.py $i > $i/NOTICE ; done
import ftplib
import hashlib
diff --git a/libc/upstream-openbsd/android/include/openbsd-compat.h b/libc/upstream-openbsd/android/include/openbsd-compat.h
index 8386ba5..8783467 100644
--- a/libc/upstream-openbsd/android/include/openbsd-compat.h
+++ b/libc/upstream-openbsd/android/include/openbsd-compat.h
@@ -35,6 +35,9 @@
/* Ignore all __weak_alias in OpenBSD. */
#define __weak_alias(alias,sym)
+/* Ignore all __warn_references in OpenBSD. */
+#define __warn_references(sym,msg)
+
/* OpenBSD's <ctype.h> uses these names, which conflicted with stlport.
* Additionally, we changed the numeric/digit type from N to D for libcxx.
*/
diff --git a/libc/upstream-openbsd/lib/libc/stdio/vfprintf.c b/libc/upstream-openbsd/lib/libc/stdio/vfprintf.c
index 7f8ff31..5f4fb7f 100644
--- a/libc/upstream-openbsd/lib/libc/stdio/vfprintf.c
+++ b/libc/upstream-openbsd/lib/libc/stdio/vfprintf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: vfprintf.c,v 1.66 2014/05/03 12:36:45 deraadt Exp $ */
+/* $OpenBSD: vfprintf.c,v 1.67 2014/12/21 00:23:30 daniel Exp $ */
/*-
* Copyright (c) 1990 The Regents of the University of California.
* All rights reserved.
@@ -753,10 +753,9 @@
if (signflag)
sign = '-';
if (expt == INT_MAX) { /* inf or nan */
- if (*cp == 'N') {
+ if (*cp == 'N')
cp = (ch >= 'a') ? "nan" : "NAN";
- sign = '\0';
- } else
+ else
cp = (ch >= 'a') ? "inf" : "INF";
size = 3;
flags &= ~ZEROPAD;
diff --git a/libc/upstream-openbsd/lib/libc/stdio/vfwprintf.c b/libc/upstream-openbsd/lib/libc/stdio/vfwprintf.c
index ef0ca43..a6f4123 100644
--- a/libc/upstream-openbsd/lib/libc/stdio/vfwprintf.c
+++ b/libc/upstream-openbsd/lib/libc/stdio/vfwprintf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: vfwprintf.c,v 1.11 2014/06/04 07:45:25 stsp Exp $ */
+/* $OpenBSD: vfwprintf.c,v 1.12 2014/12/21 00:23:30 daniel Exp $ */
/*-
* Copyright (c) 1990 The Regents of the University of California.
* All rights reserved.
@@ -731,10 +731,9 @@
if (signflag)
sign = '-';
if (expt == INT_MAX) { /* inf or nan */
- if (*cp == 'N') {
+ if (*cp == 'N')
cp = (ch >= 'a') ? L"nan" : L"NAN";
- sign = '\0';
- } else
+ else
cp = (ch >= 'a') ? L"inf" : L"INF";
size = 3;
flags &= ~ZEROPAD;
diff --git a/libm/NOTICE b/libm/NOTICE
index 5be60db..70f2f46 100644
--- a/libm/NOTICE
+++ b/libm/NOTICE
@@ -549,32 +549,6 @@
-------------------------------------------------------------------
-Copyright (c) 2004-2011 David Schultz <das@FreeBSD.ORG>
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions
-are met:
-1. Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
-2. 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 AUTHOR 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 AUTHOR 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.
-
--------------------------------------------------------------------
-
Copyright (c) 2005 Bruce D. Evans and Steven G. Kargl
All rights reserved.
@@ -976,6 +950,32 @@
-------------------------------------------------------------------
+Copyright (c) 2012 Stephen Montgomery-Smith <stephen@FreeBSD.ORG>
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. 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 AUTHOR 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 AUTHOR 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.
+
+-------------------------------------------------------------------
+
Copyright (c) 2013 David Chisnall
All rights reserved.
diff --git a/libm/freebsd-compat.h b/libm/freebsd-compat.h
index 1481cc2..a4dd6c2 100644
--- a/libm/freebsd-compat.h
+++ b/libm/freebsd-compat.h
@@ -26,6 +26,8 @@
#define __strong_reference(sym,aliassym) \
extern __typeof (sym) aliassym __attribute__ ((__alias__ (#sym)))
+#define __warn_references(sym,msg) /* ignored */
+
/* digittoint is in BSD's <ctype.h>. */
int digittoint(char ch);
diff --git a/linker/Android.mk b/linker/Android.mk
index d6e0095..0383e7b 100644
--- a/linker/Android.mk
+++ b/linker/Android.mk
@@ -19,6 +19,13 @@
LOCAL_SRC_FILES_mips := arch/mips/begin.S
LOCAL_SRC_FILES_mips64 := arch/mips64/begin.S
+# GNU assembler aborted with clang's output for linker.cpp:
+# Assertion failure in get_line_subseg at
+# /s/ndk-toolchain/src/build/../binutils/binutils-2.24/gas/dwarf2dbg.c line 271.
+ifeq ($(TARGET_ARCH),mips)
+ LOCAL_CLANG_CFLAGS += -integrated-as
+endif
+
LOCAL_LDFLAGS := \
-shared \
-Wl,-Bsymbolic \
diff --git a/linker/linker.cpp b/linker/linker.cpp
index 3409931..babefeb 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -2402,6 +2402,13 @@
*dp = &_r_debug;
}
break;
+ case DT_MIPS_RLD_MAP2:
+ // Set the DT_MIPS_RLD_MAP2 entry to the address of _r_debug for GDB.
+ {
+ r_debug** dp = reinterpret_cast<r_debug**>(reinterpret_cast<ElfW(Addr)>(d) + d->d_un.d_val);
+ *dp = &_r_debug;
+ }
+ break;
case DT_MIPS_RLD_VERSION:
case DT_MIPS_FLAGS:
diff --git a/tests/stdio_test.cpp b/tests/stdio_test.cpp
index 854fc7b..de5eea3 100644
--- a/tests/stdio_test.cpp
+++ b/tests/stdio_test.cpp
@@ -364,22 +364,52 @@
EXPECT_STREQ("print_me_twice print_me_twice", buf);
}
-TEST(stdio, snprintf_f_special) {
- char buf[BUFSIZ];
- snprintf(buf, sizeof(buf), "%f", nanf(""));
- EXPECT_STRCASEEQ("NaN", buf);
+template <typename T>
+void CheckInfNan(int snprintf_fn(T*, size_t, const T*, ...),
+ const T* fmt, const T* fmt_plus,
+ const T* minus_inf, const T* inf_, const T* plus_inf,
+ const T* minus_nan, const T* nan_, const T* plus_nan) {
+ T buf[BUFSIZ];
- snprintf(buf, sizeof(buf), "%f", HUGE_VALF);
- EXPECT_STRCASEEQ("Inf", buf);
+ snprintf_fn(buf, sizeof(buf), fmt, nan(""));
+ EXPECT_STREQ(nan_, buf) << fmt;
+ snprintf_fn(buf, sizeof(buf), fmt, -nan(""));
+ EXPECT_STREQ(minus_nan, buf) << fmt;
+ snprintf_fn(buf, sizeof(buf), fmt_plus, nan(""));
+ EXPECT_STREQ(plus_nan, buf) << fmt_plus;
+ snprintf_fn(buf, sizeof(buf), fmt_plus, -nan(""));
+ EXPECT_STREQ(minus_nan, buf) << fmt_plus;
+
+ snprintf_fn(buf, sizeof(buf), fmt, HUGE_VAL);
+ EXPECT_STREQ(inf_, buf) << fmt;
+ snprintf_fn(buf, sizeof(buf), fmt, -HUGE_VAL);
+ EXPECT_STREQ(minus_inf, buf) << fmt;
+ snprintf_fn(buf, sizeof(buf), fmt_plus, HUGE_VAL);
+ EXPECT_STREQ(plus_inf, buf) << fmt_plus;
+ snprintf_fn(buf, sizeof(buf), fmt_plus, -HUGE_VAL);
+ EXPECT_STREQ(minus_inf, buf) << fmt_plus;
}
-TEST(stdio, snprintf_g_special) {
- char buf[BUFSIZ];
- snprintf(buf, sizeof(buf), "%g", nan(""));
- EXPECT_STRCASEEQ("NaN", buf);
+TEST(stdio, snprintf_inf_nan) {
+ CheckInfNan(snprintf, "%a", "%+a", "-inf", "inf", "+inf", "-nan", "nan", "+nan");
+ CheckInfNan(snprintf, "%A", "%+A", "-INF", "INF", "+INF", "-NAN", "NAN", "+NAN");
+ CheckInfNan(snprintf, "%e", "%+e", "-inf", "inf", "+inf", "-nan", "nan", "+nan");
+ CheckInfNan(snprintf, "%E", "%+E", "-INF", "INF", "+INF", "-NAN", "NAN", "+NAN");
+ CheckInfNan(snprintf, "%f", "%+f", "-inf", "inf", "+inf", "-nan", "nan", "+nan");
+ CheckInfNan(snprintf, "%F", "%+F", "-INF", "INF", "+INF", "-NAN", "NAN", "+NAN");
+ CheckInfNan(snprintf, "%g", "%+g", "-inf", "inf", "+inf", "-nan", "nan", "+nan");
+ CheckInfNan(snprintf, "%G", "%+G", "-INF", "INF", "+INF", "-NAN", "NAN", "+NAN");
+}
- snprintf(buf, sizeof(buf), "%g", HUGE_VAL);
- EXPECT_STRCASEEQ("Inf", buf);
+TEST(stdio, wsprintf_inf_nan) {
+ CheckInfNan(swprintf, L"%a", L"%+a", L"-inf", L"inf", L"+inf", L"-nan", L"nan", L"+nan");
+ CheckInfNan(swprintf, L"%A", L"%+A", L"-INF", L"INF", L"+INF", L"-NAN", L"NAN", L"+NAN");
+ CheckInfNan(swprintf, L"%e", L"%+e", L"-inf", L"inf", L"+inf", L"-nan", L"nan", L"+nan");
+ CheckInfNan(swprintf, L"%E", L"%+E", L"-INF", L"INF", L"+INF", L"-NAN", L"NAN", L"+NAN");
+ CheckInfNan(swprintf, L"%f", L"%+f", L"-inf", L"inf", L"+inf", L"-nan", L"nan", L"+nan");
+ CheckInfNan(swprintf, L"%F", L"%+F", L"-INF", L"INF", L"+INF", L"-NAN", L"NAN", L"+NAN");
+ CheckInfNan(swprintf, L"%g", L"%+g", L"-inf", L"inf", L"+inf", L"-nan", L"nan", L"+nan");
+ CheckInfNan(swprintf, L"%G", L"%+G", L"-INF", L"INF", L"+INF", L"-NAN", L"NAN", L"+NAN");
}
TEST(stdio, snprintf_d_INT_MAX) {
@@ -439,8 +469,22 @@
TEST(stdio, snprintf_negative_zero_5084292) {
char buf[BUFSIZ];
+ snprintf(buf, sizeof(buf), "%e", -0.0);
+ EXPECT_STREQ("-0.000000e+00", buf);
+ snprintf(buf, sizeof(buf), "%E", -0.0);
+ EXPECT_STREQ("-0.000000E+00", buf);
snprintf(buf, sizeof(buf), "%f", -0.0);
EXPECT_STREQ("-0.000000", buf);
+ snprintf(buf, sizeof(buf), "%F", -0.0);
+ EXPECT_STREQ("-0.000000", buf);
+ snprintf(buf, sizeof(buf), "%g", -0.0);
+ EXPECT_STREQ("-0", buf);
+ snprintf(buf, sizeof(buf), "%G", -0.0);
+ EXPECT_STREQ("-0", buf);
+ snprintf(buf, sizeof(buf), "%a", -0.0);
+ EXPECT_STREQ("-0x0p+0", buf);
+ snprintf(buf, sizeof(buf), "%A", -0.0);
+ EXPECT_STREQ("-0X0P+0", buf);
}
TEST(stdio, snprintf_utf8_15439554) {