2 * Copyright (c) 1999, 2012 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
26 #include <mach/mach_init.h>
27 #include <mach/mach_vm.h>
28 #include <platform/compat.h>
31 pthread_atfork(void (*prepare
)(void), void (*parent
)(void), void (*child
)(void))
35 pthread_globals_t globals
= _pthread_globals();
37 _PTHREAD_LOCK(globals
->pthread_atfork_lock
);
38 idx
= globals
->atfork_count
++;
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.
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(),
53 VM_MAKE_TAG(VM_MEMORY_OS_ALLOC_ONCE
)| VM_FLAGS_ANYWHERE
,
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
));
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
);
75 } else if (idx
>= PTHREAD_ATFORK_MAX
) {
80 struct pthread_atfork_entry
*e
= &globals
->atfork
[idx
];
85 _PTHREAD_UNLOCK(globals
->pthread_atfork_lock
);
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().
94 _pthread_atfork_prepare_handlers(void)
96 pthread_globals_t globals
= _pthread_globals();
98 _PTHREAD_LOCK(globals
->pthread_atfork_lock
);
100 for (idx
= globals
->atfork_count
; idx
> 0; --idx
) {
101 struct pthread_atfork_entry
*e
= &globals
->atfork
[idx
-1];
102 if (e
->prepare
!= NULL
) {
108 // Take pthread-internal locks.
109 // Called last in libSystem_atfork_prepare().
111 _pthread_atfork_prepare(void)
113 pthread_globals_t globals
= _pthread_globals();
115 _PTHREAD_LOCK(globals
->psaved_self_global_lock
);
116 globals
->psaved_self
= pthread_self();
117 _PTHREAD_LOCK(globals
->psaved_self
->lock
);
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().
124 _pthread_atfork_parent(void)
126 pthread_globals_t globals
= _pthread_globals();
128 _PTHREAD_UNLOCK(globals
->psaved_self
->lock
);
129 _PTHREAD_UNLOCK(globals
->psaved_self_global_lock
);
132 // Iterate pthread_atfork parent handlers.
133 // Called last in libSystem_atfork_parent().
135 _pthread_atfork_parent_handlers(void)
137 pthread_globals_t globals
= _pthread_globals();
140 for (idx
= 0; idx
< globals
->atfork_count
; ++idx
) {
141 struct pthread_atfork_entry
*e
= &globals
->atfork
[idx
];
142 if (e
->parent
!= NULL
) {
146 _PTHREAD_UNLOCK(globals
->pthread_atfork_lock
);
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)
154 _pthread_atfork_child(void)
156 pthread_globals_t globals
= _pthread_globals();
157 _PTHREAD_LOCK_INIT(globals
->psaved_self_global_lock
);
159 _pthread_main_thread_init(globals
->psaved_self
);
161 struct _pthread_registration_data registration_data
;
162 _pthread_bsdthread_init(®istration_data
);
165 // Iterate pthread_atfork child handlers.
166 // Called last in libSystem_atfork_child().
168 _pthread_atfork_child_handlers(void)
170 pthread_globals_t globals
= _pthread_globals();
172 for (idx
= 0; idx
< globals
->atfork_count
; ++idx
) {
173 struct pthread_atfork_entry
*e
= &globals
->atfork
[idx
];
174 if (e
->child
!= NULL
) {
178 _PTHREAD_LOCK_INIT(globals
->pthread_atfork_lock
);
181 // Preserve legacy symbols for older iOS simulators
183 _pthread_fork_prepare(void)
185 _pthread_atfork_prepare_handlers();
186 _pthread_atfork_prepare();
190 _pthread_fork_parent(void)
192 _pthread_atfork_parent();
193 _pthread_atfork_parent_handlers();
197 _pthread_fork_child(void)
199 _pthread_atfork_child();
203 _pthread_fork_child_postinit(void)
205 _pthread_atfork_child_handlers();