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 "platform/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:
atfork_list_t()48 constexpr atfork_list_t() : first_(nullptr), last_(nullptr) {}
49
50 template<typename F>
walk_forward(F 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>
walk_backwards(F f)58 void walk_backwards(F f) {
59 for (atfork_t* it = last_; it != nullptr; it = it->prev) {
60 f(it);
61 }
62 }
63
push_back(atfork_t * entry)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>
remove_if(F predicate)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:
remove(atfork_t * entry)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
__bionic_atfork_run_prepare()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
__bionic_atfork_run_child()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
__bionic_atfork_run_parent()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
__register_atfork(void (* prepare)(void),void (* parent)(void),void (* child)(void),void * dso)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
__unregister_atfork(void * dso)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