]> git.saurik.com Git - apple/libpthread.git/blame - src/pthread_atfork.c
libpthread-301.30.1.tar.gz
[apple/libpthread.git] / src / pthread_atfork.c
CommitLineData
f1a1da6c
A
1/*
2 * Copyright (c) 1999, 2012 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
a0619f9c 5 *
f1a1da6c
A
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.
a0619f9c 12 *
f1a1da6c
A
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.
a0619f9c 20 *
f1a1da6c
A
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24#include "internal.h"
25
f1a1da6c
A
26#include <mach/mach_init.h>
27#include <mach/mach_vm.h>
28#include <platform/compat.h>
29
f1a1da6c
A
30int
31pthread_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();
a0619f9c 36
2546420a 37 _PTHREAD_LOCK(globals->pthread_atfork_lock);
f1a1da6c
A
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);
2546420a 48 _PTHREAD_UNLOCK(globals->pthread_atfork_lock);
f1a1da6c
A
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);
2546420a 60 _PTHREAD_LOCK(globals->pthread_atfork_lock);
f1a1da6c
A
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.
2546420a 68 _PTHREAD_UNLOCK(globals->pthread_atfork_lock);
f1a1da6c 69 mach_vm_deallocate(mach_task_self(), storage, size);
2546420a 70 _PTHREAD_LOCK(globals->pthread_atfork_lock);
f1a1da6c
A
71 }
72 } else {
73 res = ENOMEM;
74 }
75 } else if (idx >= PTHREAD_ATFORK_MAX) {
76 res = ENOMEM;
77 }
a0619f9c 78
f1a1da6c
A
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 }
2546420a 85 _PTHREAD_UNLOCK(globals->pthread_atfork_lock);
f1a1da6c
A
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.
010efe49 92// Called first in libSystem_atfork_prepare().
f1a1da6c 93void
010efe49 94_pthread_atfork_prepare_handlers(void)
f1a1da6c
A
95{
96 pthread_globals_t globals = _pthread_globals();
97
2546420a 98 _PTHREAD_LOCK(globals->pthread_atfork_lock);
f1a1da6c
A
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 }
010efe49
A
106}
107
108// Take pthread-internal locks.
109// Called last in libSystem_atfork_prepare().
110void
24d1ef94 111_pthread_atfork_prepare(void)
010efe49
A
112{
113 pthread_globals_t globals = _pthread_globals();
f1a1da6c 114
2546420a 115 _PTHREAD_LOCK(globals->psaved_self_global_lock);
f1a1da6c 116 globals->psaved_self = pthread_self();
2546420a 117 _PTHREAD_LOCK(globals->psaved_self->lock);
f1a1da6c
A
118}
119
120// Called after the fork(2) system call returns to the parent process.
010efe49
A
121// Release pthread-internal locks
122// Called first in libSystem_atfork_parent().
f1a1da6c 123void
24d1ef94 124_pthread_atfork_parent(void)
f1a1da6c
A
125{
126 pthread_globals_t globals = _pthread_globals();
127
2546420a
A
128 _PTHREAD_UNLOCK(globals->psaved_self->lock);
129 _PTHREAD_UNLOCK(globals->psaved_self_global_lock);
010efe49
A
130}
131
132// Iterate pthread_atfork parent handlers.
133// Called last in libSystem_atfork_parent().
134void
135_pthread_atfork_parent_handlers(void)
136{
137 pthread_globals_t globals = _pthread_globals();
f1a1da6c
A
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 }
2546420a 146 _PTHREAD_UNLOCK(globals->pthread_atfork_lock);
f1a1da6c
A
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.
010efe49 152// Called first in libSystem_atfork_child() (after _dyld_fork_child)
f1a1da6c 153void
24d1ef94 154_pthread_atfork_child(void)
f1a1da6c
A
155{
156 pthread_globals_t globals = _pthread_globals();
2546420a 157 _PTHREAD_LOCK_INIT(globals->psaved_self_global_lock);
f1a1da6c 158 __is_threaded = 0;
a0619f9c
A
159 _pthread_main_thread_init(globals->psaved_self);
160 _pthread_bsdthread_init();
f1a1da6c
A
161}
162
163// Iterate pthread_atfork child handlers.
010efe49 164// Called last in libSystem_atfork_child().
f1a1da6c 165void
010efe49 166_pthread_atfork_child_handlers(void)
f1a1da6c
A
167{
168 pthread_globals_t globals = _pthread_globals();
169 size_t idx;
170 for (idx = 0; idx < globals->atfork_count; ++idx) {
171 struct pthread_atfork_entry *e = &globals->atfork[idx];
172 if (e->child != NULL) {
173 e->child();
174 }
175 }
2546420a 176 _PTHREAD_LOCK_INIT(globals->pthread_atfork_lock);
f1a1da6c 177}
010efe49 178
24d1ef94
A
179// Preserve legacy symbols for older iOS simulators
180void
181_pthread_fork_prepare(void)
182{
183 _pthread_atfork_prepare_handlers();
184 _pthread_atfork_prepare();
185}
186
187void
188_pthread_fork_parent(void)
189{
190 _pthread_atfork_parent();
191 _pthread_atfork_parent_handlers();
192}
193
194void
195_pthread_fork_child(void)
196{
197 _pthread_atfork_child();
198}
199
010efe49
A
200void
201_pthread_fork_child_postinit(void)
202{
203 _pthread_atfork_child_handlers();
204}