summaryrefslogtreecommitdiffstats
path: root/libc/bionic
diff options
context:
space:
mode:
authorDimitry Ivanov <dimitry@google.com>2015-04-24 03:49:30 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2015-04-24 03:49:30 +0000
commit6c63ee41ac5a246fb46c51753cd4d50ccae0dd8f (patch)
tree3ed0595fe98662464ea1ad7d6d5e75af9ff851b5 /libc/bionic
parent41ebceaf3ad392b4a3f40d96d5750d95ef206546 (diff)
parent094f58fb2a57d1ed5736ae3588bf0355618f915b (diff)
downloadbionic-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.cpp122
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);
-}
-