2 * Copyright (c) 1999 Apple Computer, 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@
24 * cthreads.c - by Eric Cooper
26 * Implementation of cthread_fork, cthread_join, cthread_exit, etc.
28 * 22-July-93 Blaine Garst
29 * fixed association of read_thread info
30 * fixed kernel cache set up of cproc info
33 #include "pthread_internals.h"
35 #include <sys/queue.h>
37 #include "cthread_internals.h"
41 extern void cproc_init();
42 extern thread_port_t
cproc_create();
43 extern void mig_init();
44 extern void _pthread_set_self(pthread_t
);
49 extern void mig_fork_child();
54 extern int _setjmp(jmp_buf env
);
55 extern void _longjmp(jmp_buf env
, int val
);
61 #define T_RETURNED 0x2
62 #define T_DETACHED 0x4
65 int cthread_debug
= FALSE
;
66 #endif /* CTHREADS_DEBUG */
69 * Routines for supporting fork() of multi-threaded programs.
73 extern void _malloc_fork_prepare(), _malloc_fork_parent();
74 extern void _malloc_fork_child();
75 extern void fork_mach_init();
76 extern void _cproc_fork_child(), _stack_fork_child();
77 extern void _lu_fork_child(void);
78 extern void _pthread_fork_child(pthread_t
);
79 extern void _notify_fork_child(void);
81 static pthread_t psaved_self
= 0;
82 static pthread_lock_t psaved_self_global_lock
= LOCK_INITIALIZER
;
83 static pthread_lock_t pthread_atfork_lock
= LOCK_INITIALIZER
;
84 struct pthread_atfork_entry
{
85 TAILQ_ENTRY(pthread_atfork_entry
) qentry
;
86 void (*prepare
)(void);
90 static TAILQ_HEAD(pthread_atfork_queue_head
, pthread_atfork_entry
) pthread_atfork_queue
= TAILQ_HEAD_INITIALIZER(pthread_atfork_queue
);
92 int pthread_atfork(void (*prepare
)(void), void (*parent
)(void), void (*child
)(void))
94 struct pthread_atfork_entry
*e
;
96 e
= malloc(sizeof(struct pthread_atfork_entry
));
100 e
->prepare
= prepare
;
104 _spin_lock(&pthread_atfork_lock
);
105 TAILQ_INSERT_TAIL(&pthread_atfork_queue
, e
, qentry
);
106 _spin_unlock(&pthread_atfork_lock
);
111 void _cthread_fork_prepare()
113 * Prepare cthreads library to fork() a multi-threaded program. All cthread
114 * library critical section locks are acquired before a fork() and released
115 * afterwards to insure no cthread data structure is left in an inconsistent
116 * state in the child, which comes up with only the forking thread running.
119 struct pthread_atfork_entry
*e
;
121 _spin_lock(&pthread_atfork_lock
);
122 TAILQ_FOREACH_REVERSE(e
, &pthread_atfork_queue
, qentry
, pthread_atfork_queue_head
) {
123 if (e
->prepare
!= NULL
)
127 _spin_lock(&psaved_self_global_lock
);
128 psaved_self
= pthread_self();
129 _spin_lock(&psaved_self
->lock
);
130 _malloc_fork_prepare();
133 void _cthread_fork_parent()
135 * Called in the parent process after a fork syscall.
136 * Releases locks acquired by cthread_fork_prepare().
139 struct pthread_atfork_entry
*e
;
141 _malloc_fork_parent();
142 _spin_unlock(&psaved_self
->lock
);
143 _spin_unlock(&psaved_self_global_lock
);
145 TAILQ_FOREACH(e
, &pthread_atfork_queue
, qentry
) {
146 if (e
->parent
!= NULL
)
149 _spin_unlock(&pthread_atfork_lock
);
153 void _cthread_fork_child()
155 * Called in the child process after a fork syscall. Releases locks acquired
156 * by cthread_fork_prepare(). Deallocates cthread data structures which
157 * described other threads in our parent. Makes this thread the main thread.
160 pthread_t p
= psaved_self
;
161 struct pthread_atfork_entry
*e
;
163 _pthread_set_self(p
);
164 _spin_unlock(&psaved_self_global_lock
);
166 _malloc_fork_child();
167 p
->kernel_thread
= mach_thread_self();
168 p
->reply_port
= mach_reply_port();
170 p
->__cleanup_stack
= NULL
;
171 p
->death
= MACH_PORT_NULL
;
173 p
->detached
|= _PTHREAD_CREATE_PARENT
;
174 _spin_unlock(&p
->lock
);
177 _pthread_fork_child(p
);
183 _notify_fork_child();
187 mig_init(1); /* enable multi-threaded mig interfaces */
189 TAILQ_FOREACH(e
, &pthread_atfork_queue
, qentry
) {
190 if (e
->child
!= NULL
)
193 LOCK_INIT(pthread_atfork_lock
);