kernel/genassym: Remove some unneeded assyms.
[dragonfly.git] / lib / libthread_xu / thread / thr_fork.c
CommitLineData
71b3fa15
DX
1/*
2 * Copyright (c) 2005 David Xu <davidxu@freebsd.org>
3 * Copyright (c) 2003 Daniel Eischen <deischen@freebsd.org>
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Neither the name of the author nor the names of any co-contributors
12 * may be used to endorse or promote products derived from this software
13 * without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
fcf53d9b 27 * $FreeBSD: head/lib/libthr/thread/thr_fork.c 213096 2010-08-23 $
71b3fa15
DX
28 */
29
30/*
31 * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>
32 * All rights reserved.
33 *
34 * Redistribution and use in source and binary forms, with or without
35 * modification, are permitted provided that the following conditions
36 * are met:
37 * 1. Redistributions of source code must retain the above copyright
38 * notice, this list of conditions and the following disclaimer.
39 * 2. Redistributions in binary form must reproduce the above copyright
40 * notice, this list of conditions and the following disclaimer in the
41 * documentation and/or other materials provided with the distribution.
fcf53d9b 42 * 3. Neither the name of the author nor the names of any co-contributors
71b3fa15
DX
43 * may be used to endorse or promote products derived from this software
44 * without specific prior written permission.
45 *
46 * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
47 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
48 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
49 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
50 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
51 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
52 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
53 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
54 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
55 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
56 * SUCH DAMAGE.
57 *
71b3fa15 58 */
9e2ee207 59
82657471 60#include <sys/syscall.h>
f049c502 61#include "namespace.h"
9e2ee207 62#include <machine/tls.h>
71b3fa15 63#include <errno.h>
fcf53d9b 64#include <link.h>
71b3fa15
DX
65#include <string.h>
66#include <stdlib.h>
67#include <unistd.h>
68#include <fcntl.h>
69#include <pthread.h>
70#include <spinlock.h>
98247283 71#include <sys/file.h>
fc71f871 72#include "un-namespace.h"
71b3fa15
DX
73
74#include "libc_private.h"
75#include "thr_private.h"
76
e8382b15 77struct atfork_head _thr_atfork_list;
fcaa7a3a 78struct atfork_head _thr_atfork_kern_list;
e8382b15
DX
79umtx_t _thr_atfork_lock;
80
fcaa7a3a
MD
81/*
82 * Execute a function in parent before and after the fork, and
83 * in the child.
84 */
71b3fa15
DX
85int
86_pthread_atfork(void (*prepare)(void), void (*parent)(void),
fcaa7a3a 87 void (*child)(void))
71b3fa15
DX
88{
89 struct pthread *curthread;
90 struct pthread_atfork *af;
91
71b3fa15
DX
92 if ((af = malloc(sizeof(struct pthread_atfork))) == NULL)
93 return (ENOMEM);
94
9e2ee207 95 curthread = tls_get_curthread();
71b3fa15
DX
96 af->prepare = prepare;
97 af->parent = parent;
98 af->child = child;
99 THR_UMTX_LOCK(curthread, &_thr_atfork_lock);
100 TAILQ_INSERT_TAIL(&_thr_atfork_list, af, qe);
101 THR_UMTX_UNLOCK(curthread, &_thr_atfork_lock);
102 return (0);
103}
104
fcaa7a3a
MD
105/*
106 * Private at-fork used by the rtld and sem code, guaranteed to order
107 * after user fork handlers in prepare, and before user fork handlers
108 * in the post-fork parent and in the child.
109 *
110 * This is used to ensure no interference between internal and user
111 * fork handlers, in particular we do not want to lock-out rtld or
112 * semaphores before user fork handlers run, and we want to recover
113 * before any user post-fork handlers run.
114 */
115void
116_thr_atfork_kern(void (*prepare)(void), void (*parent)(void),
117 void (*child)(void))
118{
119 struct pthread *curthread;
120 struct pthread_atfork *af;
121
122 af = malloc(sizeof(struct pthread_atfork));
123
124 curthread = tls_get_curthread();
125 af->prepare = prepare;
126 af->parent = parent;
127 af->child = child;
128 THR_UMTX_LOCK(curthread, &_thr_atfork_lock);
129 TAILQ_INSERT_TAIL(&_thr_atfork_kern_list, af, qe);
130 THR_UMTX_UNLOCK(curthread, &_thr_atfork_lock);
131}
132
fcf53d9b
JM
133void
134__pthread_cxa_finalize(struct dl_phdr_info *phdr_info)
135{
136 struct pthread *curthread;
137 struct pthread_atfork *af, *af1;
138
fcf53d9b
JM
139 curthread = tls_get_curthread();
140 THR_UMTX_LOCK(curthread, &_thr_atfork_lock);
141 TAILQ_FOREACH_MUTABLE(af, &_thr_atfork_list, qe, af1) {
142 if (__elf_phdr_match_addr(phdr_info, af->prepare) ||
143 __elf_phdr_match_addr(phdr_info, af->parent) ||
144 __elf_phdr_match_addr(phdr_info, af->child)) {
145 TAILQ_REMOVE(&_thr_atfork_list, af, qe);
146 free(af);
147 }
148 }
149 THR_UMTX_UNLOCK(curthread, &_thr_atfork_lock);
150}
151
71b3fa15
DX
152/*
153 * For a while, allow libpthread to work with a libc that doesn't
154 * export the malloc lock.
155 */
156#pragma weak __malloc_lock
157
fc71f871
DX
158pid_t _fork(void);
159
71b3fa15
DX
160pid_t
161_fork(void)
162{
163 static umtx_t inprogress;
164 static int waiters;
165 umtx_t tmp;
166
167 struct pthread *curthread;
168 struct pthread_atfork *af;
169 pid_t ret;
170 int errsave;
171#ifndef __DragonFly__
172 int unlock_malloc;
173#endif
174
175 if (!_thr_is_inited())
82657471 176 return (__syscall(SYS_fork));
71b3fa15 177
98247283 178 errsave = errno;
9e2ee207 179 curthread = tls_get_curthread();
71b3fa15
DX
180
181 THR_UMTX_LOCK(curthread, &_thr_atfork_lock);
182 tmp = inprogress;
183 while (tmp) {
184 waiters++;
185 THR_UMTX_UNLOCK(curthread, &_thr_atfork_lock);
9219c44c 186 _thr_umtx_wait(&inprogress, tmp, NULL, 0);
71b3fa15
DX
187 THR_UMTX_LOCK(curthread, &_thr_atfork_lock);
188 waiters--;
189 tmp = inprogress;
190 }
191 inprogress = 1;
192 THR_UMTX_UNLOCK(curthread, &_thr_atfork_lock);
193
194 /* Run down atfork prepare handlers. */
195 TAILQ_FOREACH_REVERSE(af, &_thr_atfork_list, atfork_head, qe) {
196 if (af->prepare != NULL)
197 af->prepare();
198 }
199
200#ifndef __DragonFly__
201 /*
202 * Try our best to protect memory from being corrupted in
203 * child process because another thread in malloc code will
204 * simply be kill by fork().
205 */
206 if ((_thr_isthreaded() != 0) && (__malloc_lock != NULL)) {
207 unlock_malloc = 1;
208 _spinlock(__malloc_lock);
209 } else {
210 unlock_malloc = 0;
211 }
212#endif
213
fcaa7a3a
MD
214#ifdef _PTHREADS_DEBUGGING
215 _thr_log("fork-parent\n", 12);
216#endif
71b3fa15 217
98247283
MD
218 _thr_signal_block(curthread);
219
220 /*
221 * Must be executed Just before the fork.
222 */
223 TAILQ_FOREACH_REVERSE(af, &_thr_atfork_kern_list, atfork_head, qe) {
224 if (af->prepare != NULL)
225 af->prepare();
226 }
227
71b3fa15 228 /* Fork a new process: */
82657471 229 if ((ret = __syscall(SYS_fork)) == 0) {
98247283
MD
230 /*
231 * Child process.
232 *
233 * NOTE: We are using the saved errno from above. Do not
234 * reload errno here.
235 */
71b3fa15 236 inprogress = 0;
98247283
MD
237
238 /*
239 * Internal child fork handlers must be run immediately.
240 */
241 TAILQ_FOREACH(af, &_thr_atfork_kern_list, qe) {
242 if (af->child != NULL)
243 af->child();
244 }
245
71b3fa15
DX
246 curthread->cancelflags &= ~THR_CANCEL_NEEDED;
247 /*
248 * Thread list will be reinitialized, and later we call
249 * _libpthread_init(), it will add us back to list.
250 */
251 curthread->tlflags &= ~(TLFLAGS_IN_TDLIST | TLFLAGS_DETACHED);
252
253 /* child is a new kernel thread. */
254 curthread->tid = _thr_get_tid();
255
256 /* clear other threads locked us. */
257 _thr_umtx_init(&curthread->lock);
258 _thr_umtx_init(&_thr_atfork_lock);
259 _thr_setthreaded(0);
260
261 /* reinitialize libc spinlocks, this includes __malloc_lock. */
262 _thr_spinlock_init();
fcaa7a3a
MD
263#ifdef _PTHREADS_DEBUGGING
264 _thr_log("fork-child\n", 11);
265#endif
71b3fa15
DX
266 _mutex_fork(curthread);
267
268 /* reinitalize library. */
269 _libpthread_init(curthread);
270
19451dc5 271 /* Ready to continue, unblock signals. */
71b3fa15
DX
272 _thr_signal_unblock(curthread);
273
274 /* Run down atfork child handlers. */
275 TAILQ_FOREACH(af, &_thr_atfork_list, qe) {
276 if (af->child != NULL)
277 af->child();
278 }
279 } else {
280 /* Parent process */
281 errsave = errno;
282
283#ifndef __DragonFly__
284 if (unlock_malloc)
285 _spinunlock(__malloc_lock);
286#endif
fcaa7a3a
MD
287#ifdef _PTHREADS_DEBUGGING
288 _thr_log("fork-done\n", 10);
289#endif
71b3fa15 290 /* Run down atfork parent handlers. */
fcaa7a3a
MD
291 TAILQ_FOREACH(af, &_thr_atfork_kern_list, qe) {
292 if (af->parent != NULL)
293 af->parent();
294 }
98247283
MD
295
296 /* Ready to continue, unblock signals. */
297 _thr_signal_unblock(curthread);
298
71b3fa15
DX
299 TAILQ_FOREACH(af, &_thr_atfork_list, qe) {
300 if (af->parent != NULL)
301 af->parent();
302 }
303
304 THR_UMTX_LOCK(curthread, &_thr_atfork_lock);
305 inprogress = 0;
306 if (waiters)
98247283 307 _thr_umtx_wake(&inprogress, 0);
71b3fa15
DX
308 THR_UMTX_UNLOCK(curthread, &_thr_atfork_lock);
309 }
310 errno = errsave;
311
312 /* Return the process ID: */
313 return (ret);
314}
5a1048c8
DX
315
316__strong_reference(_fork, fork);
317__strong_reference(_pthread_atfork, pthread_atfork);