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 <libkern/OSAtomic.h>
27 #include <mach/mach_init.h>
28 #include <mach/mach_vm.h>
29 #include <platform/compat.h>
31 PTHREAD_NOEXPORT
void pthread_workqueue_atfork_child(void);
32 PTHREAD_NOEXPORT
void __pthread_fork_child_internal(pthread_t
);
35 pthread_atfork(void (*prepare
)(void), void (*parent
)(void), void (*child
)(void))
39 pthread_globals_t globals
= _pthread_globals();
41 OSSpinLockLock(&globals
->pthread_atfork_lock
);
42 idx
= globals
->atfork_count
++;
45 // Initialize pointer to inline storage.
46 globals
->atfork
= globals
->atfork_storage
;
47 } else if (idx
== PTHREAD_ATFORK_INLINE_MAX
) {
48 // Migrate to out-of-line storage.
50 mach_vm_address_t storage
= 0;
51 mach_vm_size_t size
= PTHREAD_ATFORK_MAX
* sizeof(struct pthread_atfork_entry
);
52 OSSpinLockUnlock(&globals
->pthread_atfork_lock
);
53 kr
= mach_vm_map(mach_task_self(),
57 VM_MAKE_TAG(VM_MEMORY_OS_ALLOC_ONCE
)| VM_FLAGS_ANYWHERE
,
64 OSSpinLockLock(&globals
->pthread_atfork_lock
);
65 if (kr
== KERN_SUCCESS
) {
66 if (globals
->atfork
== globals
->atfork_storage
) {
67 globals
->atfork
= storage
;
68 memmove(globals
->atfork
, globals
->atfork_storage
, sizeof(globals
->atfork_storage
));
69 bzero(globals
->atfork_storage
, sizeof(globals
->atfork_storage
));
71 // Another thread did vm_map first.
72 OSSpinLockUnlock(&globals
->pthread_atfork_lock
);
73 mach_vm_deallocate(mach_task_self(), storage
, size
);
74 OSSpinLockLock(&globals
->pthread_atfork_lock
);
79 } else if (idx
>= PTHREAD_ATFORK_MAX
) {
84 struct pthread_atfork_entry
*e
= &globals
->atfork
[idx
];
89 OSSpinLockUnlock(&globals
->pthread_atfork_lock
);
94 // Called before the fork(2) system call is made in the parent process.
95 // Iterate pthread_atfork prepare handlers.
97 _pthread_fork_prepare(void)
99 pthread_globals_t globals
= _pthread_globals();
101 OSSpinLockLock(&globals
->pthread_atfork_lock
);
104 for (idx
= globals
->atfork_count
; idx
> 0; --idx
) {
105 struct pthread_atfork_entry
*e
= &globals
->atfork
[idx
-1];
106 if (e
->prepare
!= NULL
) {
111 OSSpinLockLock(&globals
->psaved_self_global_lock
);
112 globals
->psaved_self
= pthread_self();
113 OSSpinLockLock(&globals
->psaved_self
->lock
);
116 // Called after the fork(2) system call returns to the parent process.
117 // Iterate pthread_atfork parent handlers.
119 _pthread_fork_parent(void)
121 pthread_globals_t globals
= _pthread_globals();
123 OSSpinLockUnlock(&globals
->psaved_self
->lock
);
124 OSSpinLockUnlock(&globals
->psaved_self_global_lock
);
127 for (idx
= 0; idx
< globals
->atfork_count
; ++idx
) {
128 struct pthread_atfork_entry
*e
= &globals
->atfork
[idx
];
129 if (e
->parent
!= NULL
) {
133 OSSpinLockUnlock(&globals
->pthread_atfork_lock
);
136 // Called after the fork(2) system call returns to the new child process.
137 // Clean up data structures of other threads which no longer exist in the child.
138 // Make the current thread the main thread.
140 _pthread_fork_child(void)
142 pthread_globals_t globals
= _pthread_globals();
143 globals
->psaved_self_global_lock
= OS_SPINLOCK_INIT
;
144 __pthread_fork_child_internal(globals
->psaved_self
);
146 pthread_workqueue_atfork_child();
149 // Iterate pthread_atfork child handlers.
151 _pthread_fork_child_postinit(void)
153 pthread_globals_t globals
= _pthread_globals();
155 for (idx
= 0; idx
< globals
->atfork_count
; ++idx
) {
156 struct pthread_atfork_entry
*e
= &globals
->atfork
[idx
];
157 if (e
->child
!= NULL
) {
161 globals
->pthread_atfork_lock
= OS_SPINLOCK_INIT
;