diff options
Diffstat (limited to 'libc')
-rw-r--r-- | libc/Android.mk | 17 | ||||
-rw-r--r-- | libc/arch-arm64/bionic/crtbegin.c | 1 | ||||
-rw-r--r-- | libc/arch-common/bionic/crtbegin.c | 1 | ||||
-rw-r--r-- | libc/arch-common/bionic/crtbegin_so.c | 1 | ||||
-rw-r--r-- | libc/arch-common/bionic/pthread_atfork.h | 29 | ||||
-rw-r--r-- | libc/arch-mips/bionic/crtbegin.c | 1 | ||||
-rw-r--r-- | libc/bionic/pthread_atfork.cpp | 122 | ||||
-rw-r--r-- | libc/stdlib/atexit.c (renamed from libc/upstream-openbsd/lib/libc/stdlib/atexit.c) | 16 | ||||
-rw-r--r-- | libc/stdlib/atexit.h (renamed from libc/upstream-openbsd/lib/libc/stdlib/atexit.h) | 0 |
9 files changed, 150 insertions, 38 deletions
diff --git a/libc/Android.mk b/libc/Android.mk index 2175dc4..a9fed2c 100644 --- a/libc/Android.mk +++ b/libc/Android.mk @@ -63,6 +63,7 @@ libc_common_src_files := \ stdio/sprintf.c \ stdio/stdio.c \ stdio/stdio_ext.cpp \ + stdlib/atexit.c \ stdlib/exit.c \ # Fortify implementations of libc functions. @@ -482,7 +483,6 @@ libc_upstream_openbsd_ndk_src_files := \ upstream-openbsd/lib/libc/stdio/wprintf.c \ upstream-openbsd/lib/libc/stdio/wscanf.c \ upstream-openbsd/lib/libc/stdio/wsetup.c \ - upstream-openbsd/lib/libc/stdlib/atexit.c \ upstream-openbsd/lib/libc/stdlib/atoi.c \ upstream-openbsd/lib/libc/stdlib/atol.c \ upstream-openbsd/lib/libc/stdlib/atoll.c \ @@ -1340,10 +1340,13 @@ LOCAL_CPPFLAGS := $(libc_common_cppflags) LOCAL_C_INCLUDES := $(libc_common_c_includes) LOCAL_SRC_FILES := \ + arch-common/bionic/crtbegin_so.c \ + arch-common/bionic/crtbrand.S \ $(libc_arch_dynamic_src_files) \ bionic/malloc_debug_common.cpp \ bionic/libc_init_dynamic.cpp \ bionic/NetdClient.cpp \ + arch-common/bionic/crtend_so.S \ LOCAL_MODULE := libc LOCAL_CLANG := $(use_clang) @@ -1388,15 +1391,15 @@ LOCAL_LDFLAGS_arm := -Wl,--hash-style=sysv $(eval $(call patch-up-arch-specific-flags,LOCAL_CFLAGS,libc_common_cflags)) $(eval $(call patch-up-arch-specific-flags,LOCAL_SRC_FILES,libc_arch_dynamic_src_files)) + +LOCAL_NO_CRT := true +LOCAL_ASFLAGS += $(libc_crt_target_cflags) + # special for arm -LOCAL_NO_CRT_arm := true LOCAL_CFLAGS_arm += -DCRT_LEGACY_WORKAROUND -LOCAL_ASFLAGS_arm += $(libc_crt_target_cflags) LOCAL_SRC_FILES_arm += \ - arch-common/bionic/crtbegin_so.c \ - arch-common/bionic/crtbrand.S \ - arch-arm/bionic/atexit_legacy.c \ - arch-common/bionic/crtend_so.S + arch-arm/bionic/atexit_legacy.c + LOCAL_ADDRESS_SANITIZER := false LOCAL_NATIVE_COVERAGE := $(bionic_coverage) diff --git a/libc/arch-arm64/bionic/crtbegin.c b/libc/arch-arm64/bionic/crtbegin.c index fec0b11..7e2c5d7 100644 --- a/libc/arch-arm64/bionic/crtbegin.c +++ b/libc/arch-arm64/bionic/crtbegin.c @@ -67,3 +67,4 @@ __asm__ ( #include "../../arch-common/bionic/__dso_handle.h" #include "../../arch-common/bionic/atexit.h" +#include "../../arch-common/bionic/pthread_atfork.h" diff --git a/libc/arch-common/bionic/crtbegin.c b/libc/arch-common/bionic/crtbegin.c index fa9f3f3..c46405c 100644 --- a/libc/arch-common/bionic/crtbegin.c +++ b/libc/arch-common/bionic/crtbegin.c @@ -59,6 +59,7 @@ void _start() { #include "__dso_handle.h" #include "atexit.h" +#include "pthread_atfork.h" #ifdef __i386__ # include "../../arch-x86/bionic/__stack_chk_fail_local.h" #endif diff --git a/libc/arch-common/bionic/crtbegin_so.c b/libc/arch-common/bionic/crtbegin_so.c index 641e45a..3754363 100644 --- a/libc/arch-common/bionic/crtbegin_so.c +++ b/libc/arch-common/bionic/crtbegin_so.c @@ -56,6 +56,7 @@ void __on_dlclose() { # include "__dso_handle_so.h" # include "atexit.h" #endif +#include "pthread_atfork.h" #ifdef __i386__ # include "../../arch-x86/bionic/__stack_chk_fail_local.h" #endif diff --git a/libc/arch-common/bionic/pthread_atfork.h b/libc/arch-common/bionic/pthread_atfork.h new file mode 100644 index 0000000..0c48a12 --- /dev/null +++ b/libc/arch-common/bionic/pthread_atfork.h @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2015 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. + */ + +extern void* __dso_handle; + +extern int __register_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void), void* dso); + +#ifndef _LIBC +// Libc used to export this in previous versions, therefore it needs +// to remain global for binary compatibility. +__attribute__ ((visibility ("hidden"))) +#endif +int pthread_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void)) { + return __register_atfork(prepare, parent, child, &__dso_handle); +} + diff --git a/libc/arch-mips/bionic/crtbegin.c b/libc/arch-mips/bionic/crtbegin.c index 50e9eeb..d72ec7b 100644 --- a/libc/arch-mips/bionic/crtbegin.c +++ b/libc/arch-mips/bionic/crtbegin.c @@ -92,3 +92,4 @@ __asm__ ( #include "../../arch-common/bionic/__dso_handle.h" #include "../../arch-common/bionic/atexit.h" +#include "../../arch-common/bionic/pthread_atfork.h" diff --git a/libc/bionic/pthread_atfork.cpp b/libc/bionic/pthread_atfork.cpp index d1c4ad0..093ffd2 100644 --- a/libc/bionic/pthread_atfork.cpp +++ b/libc/bionic/pthread_atfork.cpp @@ -30,6 +30,8 @@ #include <pthread.h> #include <stdlib.h> +#include "private/bionic_macros.h" + struct atfork_t { atfork_t* next; atfork_t* prev; @@ -37,79 +39,143 @@ struct atfork_t { void (*prepare)(void); void (*child)(void); void (*parent)(void); + + void* dso_handle; }; -struct atfork_list_t { - atfork_t* first; - atfork_t* last; +class atfork_list_t { + public: + atfork_list_t() : first_(nullptr), last_(nullptr) {} + + template<typename F> + void walk_forward(F f) { + for (atfork_t* it = first_; it != nullptr; it = it->next) { + f(it); + } + } + + template<typename F> + void walk_backwards(F f) { + for (atfork_t* it = last_; it != nullptr; it = it->prev) { + f(it); + } + } + + void push_back(atfork_t* entry) { + entry->next = nullptr; + entry->prev = last_; + if (entry->prev != nullptr) { + entry->prev->next = entry; + } + if (first_ == nullptr) { + first_ = entry; + } + last_ = entry; + } + + template<typename F> + void remove_if(F predicate) { + atfork_t* it = first_; + while (it != nullptr) { + if (predicate(it)) { + atfork_t* entry = it; + it = it->next; + remove(entry); + } else { + it = it->next; + } + } + } + + private: + void remove(atfork_t* entry) { + if (entry->prev != nullptr) { + entry->prev->next = entry->next; + } else { + first_ = entry->next; + } + + if (entry->next != nullptr) { + entry->next->prev = entry->prev; + } else { + last_ = entry->prev; + } + + free(entry); + } + + atfork_t* first_; + atfork_t* last_; + + DISALLOW_COPY_AND_ASSIGN(atfork_list_t); }; static pthread_mutex_t g_atfork_list_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP; -static atfork_list_t g_atfork_list = { NULL, NULL }; +static atfork_list_t g_atfork_list; void __bionic_atfork_run_prepare() { // We lock the atfork list here, unlock it in the parent, and reset it in the child. // This ensures that nobody can modify the handler array between the calls // to the prepare and parent/child handlers. - // - // TODO: If a handler tries to mutate the list, they'll block. We should probably copy - // the list before forking, and have prepare, parent, and child all work on the consistent copy. pthread_mutex_lock(&g_atfork_list_mutex); // Call pthread_atfork() prepare handlers. POSIX states that the prepare // handlers should be called in the reverse order of the parent/child // handlers, so we iterate backwards. - for (atfork_t* it = g_atfork_list.last; it != NULL; it = it->prev) { - if (it->prepare != NULL) { + g_atfork_list.walk_backwards([](atfork_t* it) { + if (it->prepare != nullptr) { it->prepare(); } - } + }); } void __bionic_atfork_run_child() { - for (atfork_t* it = g_atfork_list.first; it != NULL; it = it->next) { - if (it->child != NULL) { + g_atfork_list.walk_forward([](atfork_t* it) { + if (it->child != nullptr) { it->child(); } - } + }); g_atfork_list_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP; } void __bionic_atfork_run_parent() { - for (atfork_t* it = g_atfork_list.first; it != NULL; it = it->next) { - if (it->parent != NULL) { + g_atfork_list.walk_forward([](atfork_t* it) { + if (it->parent != nullptr) { it->parent(); } - } + }); pthread_mutex_unlock(&g_atfork_list_mutex); } -int pthread_atfork(void (*prepare)(void), void (*parent)(void), void(*child)(void)) { +// __register_atfork is the name used by glibc +extern "C" int __register_atfork(void (*prepare)(void), void (*parent)(void), + void(*child)(void), void* dso) { atfork_t* entry = reinterpret_cast<atfork_t*>(malloc(sizeof(atfork_t))); - if (entry == NULL) { + if (entry == nullptr) { return ENOMEM; } entry->prepare = prepare; entry->parent = parent; entry->child = child; + entry->dso_handle = dso; pthread_mutex_lock(&g_atfork_list_mutex); - // Append 'entry' to the list. - entry->next = NULL; - entry->prev = g_atfork_list.last; - if (entry->prev != NULL) { - entry->prev->next = entry; - } - if (g_atfork_list.first == NULL) { - g_atfork_list.first = entry; - } - g_atfork_list.last = entry; + g_atfork_list.push_back(entry); pthread_mutex_unlock(&g_atfork_list_mutex); return 0; } + +extern "C" __LIBC_HIDDEN__ void __unregister_atfork(void* dso) { + pthread_mutex_lock(&g_atfork_list_mutex); + g_atfork_list.remove_if([&](const atfork_t* entry) { + return entry->dso_handle == dso; + }); + pthread_mutex_unlock(&g_atfork_list_mutex); +} + diff --git a/libc/upstream-openbsd/lib/libc/stdlib/atexit.c b/libc/stdlib/atexit.c index 6532b38..df2b1b5 100644 --- a/libc/upstream-openbsd/lib/libc/stdlib/atexit.c +++ b/libc/stdlib/atexit.c @@ -35,11 +35,15 @@ #include <string.h> #include <unistd.h> #include "atexit.h" -#include "thread_private.h" +#include "private/thread_private.h" struct atexit *__atexit; static int restartloop; +/* BEGIN android-changed: __unregister_atfork is used by __cxa_finalize */ +extern void __unregister_atfork(void* dso); +/* END android-changed */ + /* * Function pointers are stored in a linked list of pages. The list * is initially empty, and pages are allocated on demand. The first @@ -62,7 +66,7 @@ __cxa_atexit(void (*func)(void *), void *arg, void *dso) { struct atexit *p = __atexit; struct atexit_fn *fnp; - int pgsize = getpagesize(); + size_t pgsize = getpagesize(); int ret = -1; if (pgsize < sizeof(*p)) @@ -161,6 +165,12 @@ restart: __atexit = NULL; } _ATEXIT_UNLOCK(); + + /* BEGIN android-changed: call __unregister_atfork if dso is not null */ + if (dso != NULL) { + __unregister_atfork(dso); + } + /* END android-changed */ } /* @@ -170,7 +180,7 @@ void __atexit_register_cleanup(void (*func)(void)) { struct atexit *p; - int pgsize = getpagesize(); + size_t pgsize = getpagesize(); if (pgsize < sizeof(*p)) return; diff --git a/libc/upstream-openbsd/lib/libc/stdlib/atexit.h b/libc/stdlib/atexit.h index 3de2aa3..3de2aa3 100644 --- a/libc/upstream-openbsd/lib/libc/stdlib/atexit.h +++ b/libc/stdlib/atexit.h |