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         _PTHREAD_LOCK(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                 _PTHREAD_UNLOCK(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                 _PTHREAD_LOCK(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                                 _PTHREAD_UNLOCK(globals
->pthread_atfork_lock
); 
  73                                 mach_vm_deallocate(mach_task_self(), storage
, size
); 
  74                                 _PTHREAD_LOCK(globals
->pthread_atfork_lock
); 
  79         } else if (idx 
>= PTHREAD_ATFORK_MAX
) { 
  84                 struct pthread_atfork_entry 
*e 
= &globals
->atfork
[idx
]; 
  89         _PTHREAD_UNLOCK(globals
->pthread_atfork_lock
); 
  94 // Called before the fork(2) system call is made in the parent process. 
  95 // Iterate pthread_atfork prepare handlers. 
  96 // Called first in libSystem_atfork_prepare(). 
  98 _pthread_atfork_prepare_handlers(void) 
 100         pthread_globals_t globals 
= _pthread_globals(); 
 102         _PTHREAD_LOCK(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
) { 
 112 // Take pthread-internal locks. 
 113 // Called last in libSystem_atfork_prepare(). 
 115 _pthread_atfork_prepare(void) 
 117         pthread_globals_t globals 
= _pthread_globals(); 
 119         _PTHREAD_LOCK(globals
->psaved_self_global_lock
); 
 120         globals
->psaved_self 
= pthread_self(); 
 121         _PTHREAD_LOCK(globals
->psaved_self
->lock
); 
 124 // Called after the fork(2) system call returns to the parent process. 
 125 // Release pthread-internal locks 
 126 // Called first in libSystem_atfork_parent(). 
 128 _pthread_atfork_parent(void) 
 130         pthread_globals_t globals 
= _pthread_globals(); 
 132         _PTHREAD_UNLOCK(globals
->psaved_self
->lock
); 
 133         _PTHREAD_UNLOCK(globals
->psaved_self_global_lock
); 
 136 // Iterate pthread_atfork parent handlers. 
 137 // Called last in libSystem_atfork_parent(). 
 139 _pthread_atfork_parent_handlers(void) 
 141         pthread_globals_t globals 
= _pthread_globals(); 
 144         for (idx 
= 0; idx 
< globals
->atfork_count
; ++idx
) { 
 145                 struct pthread_atfork_entry 
*e 
= &globals
->atfork
[idx
]; 
 146                 if (e
->parent 
!= NULL
) { 
 150         _PTHREAD_UNLOCK(globals
->pthread_atfork_lock
); 
 153 // Called after the fork(2) system call returns to the new child process. 
 154 // Clean up data structures of other threads which no longer exist in the child. 
 155 // Make the current thread the main thread. 
 156 // Called first in libSystem_atfork_child() (after _dyld_fork_child) 
 158 _pthread_atfork_child(void) 
 160         pthread_globals_t globals 
= _pthread_globals(); 
 161         _PTHREAD_LOCK_INIT(globals
->psaved_self_global_lock
); 
 162         __pthread_fork_child_internal(globals
->psaved_self
); 
 164         pthread_workqueue_atfork_child(); 
 167 // Iterate pthread_atfork child handlers. 
 168 // Called last in libSystem_atfork_child(). 
 170 _pthread_atfork_child_handlers(void) 
 172         pthread_globals_t globals 
= _pthread_globals(); 
 174         for (idx 
= 0; idx 
< globals
->atfork_count
; ++idx
) { 
 175                 struct pthread_atfork_entry 
*e 
= &globals
->atfork
[idx
]; 
 176                 if (e
->child 
!= NULL
) { 
 180         _PTHREAD_LOCK_INIT(globals
->pthread_atfork_lock
); 
 183 // Preserve legacy symbols for older iOS simulators 
 185 _pthread_fork_prepare(void) 
 187         _pthread_atfork_prepare_handlers(); 
 188         _pthread_atfork_prepare(); 
 192 _pthread_fork_parent(void) 
 194         _pthread_atfork_parent(); 
 195         _pthread_atfork_parent_handlers(); 
 199 _pthread_fork_child(void) 
 201         _pthread_atfork_child(); 
 205 _pthread_fork_child_postinit(void) 
 207         _pthread_atfork_child_handlers();