1 /* 2 * Copyright (C) 2008 The Android Open Source Project 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in 12 * the documentation and/or other materials provided with the 13 * distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 18 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 19 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 22 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 25 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include <errno.h> 30 #include <pthread.h> 31 #include <stdlib.h> 32 33 #include "private/bionic_macros.h" 34 35 struct atfork_t { 36 atfork_t* next; 37 atfork_t* prev; 38 39 void (*prepare)(void); 40 void (*child)(void); 41 void (*parent)(void); 42 43 void* dso_handle; 44 }; 45 46 class atfork_list_t { 47 public: 48 constexpr atfork_list_t() : first_(nullptr), last_(nullptr) {} 49 50 template<typename F> 51 void walk_forward(F f) { 52 for (atfork_t* it = first_; it != nullptr; it = it->next) { 53 f(it); 54 } 55 } 56 57 template<typename F> 58 void walk_backwards(F f) { 59 for (atfork_t* it = last_; it != nullptr; it = it->prev) { 60 f(it); 61 } 62 } 63 64 void push_back(atfork_t* entry) { 65 entry->next = nullptr; 66 entry->prev = last_; 67 if (entry->prev != nullptr) { 68 entry->prev->next = entry; 69 } 70 if (first_ == nullptr) { 71 first_ = entry; 72 } 73 last_ = entry; 74 } 75 76 template<typename F> 77 void remove_if(F predicate) { 78 atfork_t* it = first_; 79 while (it != nullptr) { 80 if (predicate(it)) { 81 atfork_t* entry = it; 82 it = it->next; 83 remove(entry); 84 } else { 85 it = it->next; 86 } 87 } 88 } 89 90 private: 91 void remove(atfork_t* entry) { 92 if (entry->prev != nullptr) { 93 entry->prev->next = entry->next; 94 } else { 95 first_ = entry->next; 96 } 97 98 if (entry->next != nullptr) { 99 entry->next->prev = entry->prev; 100 } else { 101 last_ = entry->prev; 102 } 103 104 free(entry); 105 } 106 107 atfork_t* first_; 108 atfork_t* last_; 109 110 BIONIC_DISALLOW_COPY_AND_ASSIGN(atfork_list_t); 111 }; 112 113 static pthread_mutex_t g_atfork_list_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP; 114 static atfork_list_t g_atfork_list; 115 116 void __bionic_atfork_run_prepare() { 117 // We lock the atfork list here, unlock it in the parent, and reset it in the child. 118 // This ensures that nobody can modify the handler array between the calls 119 // to the prepare and parent/child handlers. 120 pthread_mutex_lock(&g_atfork_list_mutex); 121 122 // Call pthread_atfork() prepare handlers. POSIX states that the prepare 123 // handlers should be called in the reverse order of the parent/child 124 // handlers, so we iterate backwards. 125 g_atfork_list.walk_backwards([](atfork_t* it) { 126 if (it->prepare != nullptr) { 127 it->prepare(); 128 } 129 }); 130 } 131 132 void __bionic_atfork_run_child() { 133 g_atfork_list_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP; 134 135 pthread_mutex_lock(&g_atfork_list_mutex); 136 g_atfork_list.walk_forward([](atfork_t* it) { 137 if (it->child != nullptr) { 138 it->child(); 139 } 140 }); 141 pthread_mutex_unlock(&g_atfork_list_mutex); 142 } 143 144 void __bionic_atfork_run_parent() { 145 g_atfork_list.walk_forward([](atfork_t* it) { 146 if (it->parent != nullptr) { 147 it->parent(); 148 } 149 }); 150 151 pthread_mutex_unlock(&g_atfork_list_mutex); 152 } 153 154 // __register_atfork is the name used by glibc 155 extern "C" int __register_atfork(void (*prepare)(void), void (*parent)(void), 156 void(*child)(void), void* dso) { 157 atfork_t* entry = reinterpret_cast<atfork_t*>(malloc(sizeof(atfork_t))); 158 if (entry == nullptr) { 159 return ENOMEM; 160 } 161 162 entry->prepare = prepare; 163 entry->parent = parent; 164 entry->child = child; 165 entry->dso_handle = dso; 166 167 pthread_mutex_lock(&g_atfork_list_mutex); 168 169 g_atfork_list.push_back(entry); 170 171 pthread_mutex_unlock(&g_atfork_list_mutex); 172 173 return 0; 174 } 175 176 extern "C" __LIBC_HIDDEN__ void __unregister_atfork(void* dso) { 177 pthread_mutex_lock(&g_atfork_list_mutex); 178 g_atfork_list.remove_if([&](const atfork_t* entry) { 179 return entry->dso_handle == dso; 180 }); 181 pthread_mutex_unlock(&g_atfork_list_mutex); 182 } 183