blob: 093ffd240b40fec948b60a8f65fe704b111da326 [file] [log] [blame]
Elliott Hughesc3f11402013-10-30 14:40:09 -07001/*
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>
Dan Albert75ef63d2014-11-21 00:18:07 -080031#include <stdlib.h>
Elliott Hughesc3f11402013-10-30 14:40:09 -070032
Dmitriy Ivanovea295f62014-11-20 20:47:02 -080033#include "private/bionic_macros.h"
34
Elliott Hughesc3f11402013-10-30 14:40:09 -070035struct atfork_t {
36 atfork_t* next;
37 atfork_t* prev;
38
39 void (*prepare)(void);
40 void (*child)(void);
41 void (*parent)(void);
Dmitriy Ivanovea295f62014-11-20 20:47:02 -080042
43 void* dso_handle;
Elliott Hughesc3f11402013-10-30 14:40:09 -070044};
45
Dmitriy Ivanovea295f62014-11-20 20:47:02 -080046class atfork_list_t {
47 public:
48 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 DISALLOW_COPY_AND_ASSIGN(atfork_list_t);
Elliott Hughesc3f11402013-10-30 14:40:09 -0700111};
112
Elliott Hughes212e0e32014-12-01 16:43:51 -0800113static pthread_mutex_t g_atfork_list_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
Dmitriy Ivanovea295f62014-11-20 20:47:02 -0800114static atfork_list_t g_atfork_list;
Elliott Hughesc3f11402013-10-30 14:40:09 -0700115
116void __bionic_atfork_run_prepare() {
Elliott Hughes4b558f52014-03-04 15:58:02 -0800117 // We lock the atfork list here, unlock it in the parent, and reset it in the child.
Elliott Hughesc3f11402013-10-30 14:40:09 -0700118 // This ensures that nobody can modify the handler array between the calls
119 // to the prepare and parent/child handlers.
Elliott Hughes1728b232014-05-14 10:02:03 -0700120 pthread_mutex_lock(&g_atfork_list_mutex);
Elliott Hughesc3f11402013-10-30 14:40:09 -0700121
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.
Dmitriy Ivanovea295f62014-11-20 20:47:02 -0800125 g_atfork_list.walk_backwards([](atfork_t* it) {
126 if (it->prepare != nullptr) {
Elliott Hughesc3f11402013-10-30 14:40:09 -0700127 it->prepare();
128 }
Dmitriy Ivanovea295f62014-11-20 20:47:02 -0800129 });
Elliott Hughesc3f11402013-10-30 14:40:09 -0700130}
131
132void __bionic_atfork_run_child() {
Dmitriy Ivanovea295f62014-11-20 20:47:02 -0800133 g_atfork_list.walk_forward([](atfork_t* it) {
134 if (it->child != nullptr) {
Elliott Hughesc3f11402013-10-30 14:40:09 -0700135 it->child();
136 }
Dmitriy Ivanovea295f62014-11-20 20:47:02 -0800137 });
Elliott Hughesc3f11402013-10-30 14:40:09 -0700138
Elliott Hughes212e0e32014-12-01 16:43:51 -0800139 g_atfork_list_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
Elliott Hughesc3f11402013-10-30 14:40:09 -0700140}
141
142void __bionic_atfork_run_parent() {
Dmitriy Ivanovea295f62014-11-20 20:47:02 -0800143 g_atfork_list.walk_forward([](atfork_t* it) {
144 if (it->parent != nullptr) {
Elliott Hughesc3f11402013-10-30 14:40:09 -0700145 it->parent();
146 }
Dmitriy Ivanovea295f62014-11-20 20:47:02 -0800147 });
Elliott Hughesc3f11402013-10-30 14:40:09 -0700148
Elliott Hughes1728b232014-05-14 10:02:03 -0700149 pthread_mutex_unlock(&g_atfork_list_mutex);
Elliott Hughesc3f11402013-10-30 14:40:09 -0700150}
151
Dmitriy Ivanovea295f62014-11-20 20:47:02 -0800152// __register_atfork is the name used by glibc
153extern "C" int __register_atfork(void (*prepare)(void), void (*parent)(void),
154 void(*child)(void), void* dso) {
Elliott Hughesc3f11402013-10-30 14:40:09 -0700155 atfork_t* entry = reinterpret_cast<atfork_t*>(malloc(sizeof(atfork_t)));
Dmitriy Ivanovea295f62014-11-20 20:47:02 -0800156 if (entry == nullptr) {
Elliott Hughesc3f11402013-10-30 14:40:09 -0700157 return ENOMEM;
158 }
159
160 entry->prepare = prepare;
161 entry->parent = parent;
162 entry->child = child;
Dmitriy Ivanovea295f62014-11-20 20:47:02 -0800163 entry->dso_handle = dso;
Elliott Hughesc3f11402013-10-30 14:40:09 -0700164
Elliott Hughes1728b232014-05-14 10:02:03 -0700165 pthread_mutex_lock(&g_atfork_list_mutex);
Elliott Hughesc3f11402013-10-30 14:40:09 -0700166
Dmitriy Ivanovea295f62014-11-20 20:47:02 -0800167 g_atfork_list.push_back(entry);
Elliott Hughesc3f11402013-10-30 14:40:09 -0700168
Elliott Hughes1728b232014-05-14 10:02:03 -0700169 pthread_mutex_unlock(&g_atfork_list_mutex);
Elliott Hughesc3f11402013-10-30 14:40:09 -0700170
171 return 0;
172}
Dmitriy Ivanovea295f62014-11-20 20:47:02 -0800173
174extern "C" __LIBC_HIDDEN__ void __unregister_atfork(void* dso) {
175 pthread_mutex_lock(&g_atfork_list_mutex);
176 g_atfork_list.remove_if([&](const atfork_t* entry) {
177 return entry->dso_handle == dso;
178 });
179 pthread_mutex_unlock(&g_atfork_list_mutex);
180}
181