diff options
author | Dimitry Ivanov <dimitry@google.com> | 2015-04-24 03:49:30 +0000 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2015-04-24 03:49:30 +0000 |
commit | 6c63ee41ac5a246fb46c51753cd4d50ccae0dd8f (patch) | |
tree | 3ed0595fe98662464ea1ad7d6d5e75af9ff851b5 /libc/bionic | |
parent | 41ebceaf3ad392b4a3f40d96d5750d95ef206546 (diff) | |
parent | 094f58fb2a57d1ed5736ae3588bf0355618f915b (diff) | |
download | bionic-6c63ee41ac5a246fb46c51753cd4d50ccae0dd8f.zip bionic-6c63ee41ac5a246fb46c51753cd4d50ccae0dd8f.tar.gz bionic-6c63ee41ac5a246fb46c51753cd4d50ccae0dd8f.tar.bz2 |
Merge "Revert "Unregister pthread_atfork handlers on dlclose()""
Diffstat (limited to 'libc/bionic')
-rw-r--r-- | libc/bionic/pthread_atfork.cpp | 122 |
1 files changed, 28 insertions, 94 deletions
diff --git a/libc/bionic/pthread_atfork.cpp b/libc/bionic/pthread_atfork.cpp index 093ffd2..d1c4ad0 100644 --- a/libc/bionic/pthread_atfork.cpp +++ b/libc/bionic/pthread_atfork.cpp @@ -30,8 +30,6 @@ #include <pthread.h> #include <stdlib.h> -#include "private/bionic_macros.h" - struct atfork_t { atfork_t* next; atfork_t* prev; @@ -39,143 +37,79 @@ struct atfork_t { void (*prepare)(void); void (*child)(void); void (*parent)(void); - - void* dso_handle; }; -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); +struct atfork_list_t { + atfork_t* first; + atfork_t* last; }; static pthread_mutex_t g_atfork_list_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP; -static atfork_list_t g_atfork_list; +static atfork_list_t g_atfork_list = { NULL, NULL }; 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. - g_atfork_list.walk_backwards([](atfork_t* it) { - if (it->prepare != nullptr) { + for (atfork_t* it = g_atfork_list.last; it != NULL; it = it->prev) { + if (it->prepare != NULL) { it->prepare(); } - }); + } } void __bionic_atfork_run_child() { - g_atfork_list.walk_forward([](atfork_t* it) { - if (it->child != nullptr) { + for (atfork_t* it = g_atfork_list.first; it != NULL; it = it->next) { + if (it->child != NULL) { it->child(); } - }); + } g_atfork_list_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP; } void __bionic_atfork_run_parent() { - g_atfork_list.walk_forward([](atfork_t* it) { - if (it->parent != nullptr) { + for (atfork_t* it = g_atfork_list.first; it != NULL; it = it->next) { + if (it->parent != NULL) { it->parent(); } - }); + } pthread_mutex_unlock(&g_atfork_list_mutex); } -// __register_atfork is the name used by glibc -extern "C" int __register_atfork(void (*prepare)(void), void (*parent)(void), - void(*child)(void), void* dso) { +int pthread_atfork(void (*prepare)(void), void (*parent)(void), void(*child)(void)) { atfork_t* entry = reinterpret_cast<atfork_t*>(malloc(sizeof(atfork_t))); - if (entry == nullptr) { + if (entry == NULL) { return ENOMEM; } entry->prepare = prepare; entry->parent = parent; entry->child = child; - entry->dso_handle = dso; pthread_mutex_lock(&g_atfork_list_mutex); - g_atfork_list.push_back(entry); + // 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; 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); -} - |