]> git.saurik.com Git - apple/libc.git/blame - threads/cthreads.c
Libc-825.40.1.tar.gz
[apple/libc.git] / threads / cthreads.c
CommitLineData
e9ce8d39
A
1/*
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
734aad71
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.
12 *
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
e9ce8d39
A
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
734aad71
A
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.
e9ce8d39
A
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23/*
24 * cthreads.c - by Eric Cooper
25 *
26 * Implementation of cthread_fork, cthread_join, cthread_exit, etc.
27 * HISTORY
28 * 22-July-93 Blaine Garst
29 * fixed association of read_thread info
30 * fixed kernel cache set up of cproc info
31 *
32 */
3d9156a7 33#include "pthread_internals.h"
e9ce8d39 34#include <stdlib.h>
3d9156a7 35#include <sys/queue.h>
e9ce8d39
A
36#include "cthreads.h"
37#include "cthread_internals.h"
e9ce8d39
A
38/*
39 * C Threads imports:
40 */
41extern void cproc_init();
42extern thread_port_t cproc_create();
43extern void mig_init();
44extern void _pthread_set_self(pthread_t);
45
34e8f829
A
46extern void pthread_workqueue_atfork_prepare(void);
47extern void pthread_workqueue_atfork_parent(void);
48extern void pthread_workqueue_atfork_child(void);
e9ce8d39
A
49/*
50 * Mach imports:
51 */
52extern void mig_fork_child();
53
54/*
55 * C library imports:
56 */
57extern int _setjmp(jmp_buf env);
58extern void _longjmp(jmp_buf env, int val);
59
60/*
61 * Thread status bits.
62 */
63#define T_MAIN 0x1
64#define T_RETURNED 0x2
65#define T_DETACHED 0x4
66
67#ifdef CTHREADS_DEBUG
68int cthread_debug = FALSE;
9385eb3d 69#endif /* CTHREADS_DEBUG */
e9ce8d39
A
70
71/*
72 * Routines for supporting fork() of multi-threaded programs.
73 */
74
75
76extern void _malloc_fork_prepare(), _malloc_fork_parent();
77extern void _malloc_fork_child();
9385eb3d 78extern void fork_mach_init();
e9ce8d39 79extern void _cproc_fork_child(), _stack_fork_child();
34e8f829 80extern void _asl_fork_child(void);
9385eb3d 81extern void _pthread_fork_child(pthread_t);
1f2f436a 82extern void _pthread_fork_child_postinit();
9385eb3d 83extern void _notify_fork_child(void);
e9ce8d39
A
84
85static pthread_t psaved_self = 0;
86static pthread_lock_t psaved_self_global_lock = LOCK_INITIALIZER;
3d9156a7
A
87static pthread_lock_t pthread_atfork_lock = LOCK_INITIALIZER;
88struct pthread_atfork_entry {
89 TAILQ_ENTRY(pthread_atfork_entry) qentry;
90 void (*prepare)(void);
91 void (*parent)(void);
92 void (*child)(void);
93};
94static TAILQ_HEAD(pthread_atfork_queue_head, pthread_atfork_entry) pthread_atfork_queue = TAILQ_HEAD_INITIALIZER(pthread_atfork_queue);
95
96int pthread_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void))
97{
98 struct pthread_atfork_entry *e;
99
100 e = malloc(sizeof(struct pthread_atfork_entry));
101 if (e == NULL)
102 return (ENOMEM);
103
104 e->prepare = prepare;
105 e->parent = parent;
106 e->child = child;
107
108 _spin_lock(&pthread_atfork_lock);
109 TAILQ_INSERT_TAIL(&pthread_atfork_queue, e, qentry);
110 _spin_unlock(&pthread_atfork_lock);
111
112 return 0;
113}
e9ce8d39
A
114
115void _cthread_fork_prepare()
116/*
117 * Prepare cthreads library to fork() a multi-threaded program. All cthread
118 * library critical section locks are acquired before a fork() and released
119 * afterwards to insure no cthread data structure is left in an inconsistent
120 * state in the child, which comes up with only the forking thread running.
121 */
122{
3d9156a7
A
123 struct pthread_atfork_entry *e;
124
125 _spin_lock(&pthread_atfork_lock);
224c7076
A
126#ifdef TAILQ_FOREACH_REVERSE_LEGACY_ORDER
127 TAILQ_FOREACH_REVERSE(e, &pthread_atfork_queue, qentry, pthread_atfork_queue_head)
128#else /* !TAILQ_FOREACH_REVERSE_LEGACY_ORDER */
129 TAILQ_FOREACH_REVERSE(e, &pthread_atfork_queue, pthread_atfork_queue_head, qentry)
130#endif /* TAILQ_FOREACH_REVERSE_LEGACY_ORDER */
131 {
3d9156a7
A
132 if (e->prepare != NULL)
133 e->prepare();
134 }
135
136 _spin_lock(&psaved_self_global_lock);
137 psaved_self = pthread_self();
138 _spin_lock(&psaved_self->lock);
e9ce8d39 139 _malloc_fork_prepare();
34e8f829
A
140
141 pthread_workqueue_atfork_prepare();
e9ce8d39
A
142}
143
144void _cthread_fork_parent()
145/*
146 * Called in the parent process after a fork syscall.
147 * Releases locks acquired by cthread_fork_prepare().
148 */
149{
3d9156a7
A
150 struct pthread_atfork_entry *e;
151
e9ce8d39
A
152 _malloc_fork_parent();
153 _spin_unlock(&psaved_self->lock);
154 _spin_unlock(&psaved_self_global_lock);
155
3d9156a7
A
156 TAILQ_FOREACH(e, &pthread_atfork_queue, qentry) {
157 if (e->parent != NULL)
158 e->parent();
159 }
160 _spin_unlock(&pthread_atfork_lock);
161
34e8f829 162 pthread_workqueue_atfork_parent();
e9ce8d39
A
163}
164
165void _cthread_fork_child()
166/*
167 * Called in the child process after a fork syscall. Releases locks acquired
168 * by cthread_fork_prepare(). Deallocates cthread data structures which
169 * described other threads in our parent. Makes this thread the main thread.
e9ce8d39
A
170 */
171{
172 pthread_t p = psaved_self;
173
174 _pthread_set_self(p);
175 _spin_unlock(&psaved_self_global_lock);
176 mig_fork_child();
177 _malloc_fork_child();
178 p->kernel_thread = mach_thread_self();
9385eb3d 179 p->reply_port = mach_reply_port();
3d9156a7 180 p->__cleanup_stack = NULL;
e9ce8d39 181 p->death = MACH_PORT_NULL;
5b2abdfb
A
182 p->joiner = NULL;
183 p->detached |= _PTHREAD_CREATE_PARENT;
e9ce8d39
A
184 _spin_unlock(&p->lock);
185
9385eb3d 186 _pthread_fork_child(p);
1f2f436a 187}
9385eb3d 188
1f2f436a
A
189void _cthread_fork_child_postinit()
190{
191 struct pthread_atfork_entry *e;
e9ce8d39
A
192
193 __is_threaded = 0;
5b2abdfb 194
1f2f436a 195 _pthread_fork_child_postinit();
e9ce8d39 196 mig_init(1); /* enable multi-threaded mig interfaces */
3d9156a7 197
34e8f829
A
198 pthread_workqueue_atfork_child();
199
3d9156a7
A
200 TAILQ_FOREACH(e, &pthread_atfork_queue, qentry) {
201 if (e->child != NULL)
202 e->child();
203 }
1f2f436a 204 LOCK_INIT(pthread_atfork_lock);
e9ce8d39 205}