]> git.saurik.com Git - apple/libpthread.git/blob - src/pthread_atfork.c
libpthread-301.50.1.tar.gz
[apple/libpthread.git] / src / pthread_atfork.c
1 /*
2 * Copyright (c) 1999, 2012 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 #include "internal.h"
25
26 #include <mach/mach_init.h>
27 #include <mach/mach_vm.h>
28 #include <platform/compat.h>
29
30 int
31 pthread_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void))
32 {
33 int res = 0;
34 size_t idx;
35 pthread_globals_t globals = _pthread_globals();
36
37 _PTHREAD_LOCK(globals->pthread_atfork_lock);
38 idx = globals->atfork_count++;
39
40 if (idx == 0) {
41 // Initialize pointer to inline storage.
42 globals->atfork = globals->atfork_storage;
43 } else if (idx == PTHREAD_ATFORK_INLINE_MAX) {
44 // Migrate to out-of-line storage.
45 kern_return_t kr;
46 mach_vm_address_t storage = 0;
47 mach_vm_size_t size = PTHREAD_ATFORK_MAX * sizeof(struct pthread_atfork_entry);
48 _PTHREAD_UNLOCK(globals->pthread_atfork_lock);
49 kr = mach_vm_map(mach_task_self(),
50 &storage,
51 size,
52 vm_page_size - 1,
53 VM_MAKE_TAG(VM_MEMORY_OS_ALLOC_ONCE)| VM_FLAGS_ANYWHERE,
54 MEMORY_OBJECT_NULL,
55 0,
56 FALSE,
57 VM_PROT_DEFAULT,
58 VM_PROT_ALL,
59 VM_INHERIT_DEFAULT);
60 _PTHREAD_LOCK(globals->pthread_atfork_lock);
61 if (kr == KERN_SUCCESS) {
62 if (globals->atfork == globals->atfork_storage) {
63 globals->atfork = storage;
64 memmove(globals->atfork, globals->atfork_storage, sizeof(globals->atfork_storage));
65 bzero(globals->atfork_storage, sizeof(globals->atfork_storage));
66 } else {
67 // Another thread did vm_map first.
68 _PTHREAD_UNLOCK(globals->pthread_atfork_lock);
69 mach_vm_deallocate(mach_task_self(), storage, size);
70 _PTHREAD_LOCK(globals->pthread_atfork_lock);
71 }
72 } else {
73 res = ENOMEM;
74 }
75 } else if (idx >= PTHREAD_ATFORK_MAX) {
76 res = ENOMEM;
77 }
78
79 if (res == 0) {
80 struct pthread_atfork_entry *e = &globals->atfork[idx];
81 e->prepare = prepare;
82 e->parent = parent;
83 e->child = child;
84 }
85 _PTHREAD_UNLOCK(globals->pthread_atfork_lock);
86
87 return res;
88 }
89
90 // Called before the fork(2) system call is made in the parent process.
91 // Iterate pthread_atfork prepare handlers.
92 // Called first in libSystem_atfork_prepare().
93 void
94 _pthread_atfork_prepare_handlers(void)
95 {
96 pthread_globals_t globals = _pthread_globals();
97
98 _PTHREAD_LOCK(globals->pthread_atfork_lock);
99 size_t idx;
100 for (idx = globals->atfork_count; idx > 0; --idx) {
101 struct pthread_atfork_entry *e = &globals->atfork[idx-1];
102 if (e->prepare != NULL) {
103 e->prepare();
104 }
105 }
106 }
107
108 // Take pthread-internal locks.
109 // Called last in libSystem_atfork_prepare().
110 void
111 _pthread_atfork_prepare(void)
112 {
113 pthread_globals_t globals = _pthread_globals();
114
115 _PTHREAD_LOCK(globals->psaved_self_global_lock);
116 globals->psaved_self = pthread_self();
117 _PTHREAD_LOCK(globals->psaved_self->lock);
118 }
119
120 // Called after the fork(2) system call returns to the parent process.
121 // Release pthread-internal locks
122 // Called first in libSystem_atfork_parent().
123 void
124 _pthread_atfork_parent(void)
125 {
126 pthread_globals_t globals = _pthread_globals();
127
128 _PTHREAD_UNLOCK(globals->psaved_self->lock);
129 _PTHREAD_UNLOCK(globals->psaved_self_global_lock);
130 }
131
132 // Iterate pthread_atfork parent handlers.
133 // Called last in libSystem_atfork_parent().
134 void
135 _pthread_atfork_parent_handlers(void)
136 {
137 pthread_globals_t globals = _pthread_globals();
138
139 size_t idx;
140 for (idx = 0; idx < globals->atfork_count; ++idx) {
141 struct pthread_atfork_entry *e = &globals->atfork[idx];
142 if (e->parent != NULL) {
143 e->parent();
144 }
145 }
146 _PTHREAD_UNLOCK(globals->pthread_atfork_lock);
147 }
148
149 // Called after the fork(2) system call returns to the new child process.
150 // Clean up data structures of other threads which no longer exist in the child.
151 // Make the current thread the main thread.
152 // Called first in libSystem_atfork_child() (after _dyld_fork_child)
153 void
154 _pthread_atfork_child(void)
155 {
156 pthread_globals_t globals = _pthread_globals();
157 _PTHREAD_LOCK_INIT(globals->psaved_self_global_lock);
158 __is_threaded = 0;
159 _pthread_main_thread_init(globals->psaved_self);
160
161 struct _pthread_registration_data registration_data;
162 _pthread_bsdthread_init(&registration_data);
163 }
164
165 // Iterate pthread_atfork child handlers.
166 // Called last in libSystem_atfork_child().
167 void
168 _pthread_atfork_child_handlers(void)
169 {
170 pthread_globals_t globals = _pthread_globals();
171 size_t idx;
172 for (idx = 0; idx < globals->atfork_count; ++idx) {
173 struct pthread_atfork_entry *e = &globals->atfork[idx];
174 if (e->child != NULL) {
175 e->child();
176 }
177 }
178 _PTHREAD_LOCK_INIT(globals->pthread_atfork_lock);
179 }
180
181 // Preserve legacy symbols for older iOS simulators
182 void
183 _pthread_fork_prepare(void)
184 {
185 _pthread_atfork_prepare_handlers();
186 _pthread_atfork_prepare();
187 }
188
189 void
190 _pthread_fork_parent(void)
191 {
192 _pthread_atfork_parent();
193 _pthread_atfork_parent_handlers();
194 }
195
196 void
197 _pthread_fork_child(void)
198 {
199 _pthread_atfork_child();
200 }
201
202 void
203 _pthread_fork_child_postinit(void)
204 {
205 _pthread_atfork_child_handlers();
206 }