xref: /openbsd-src/lib/librthread/rthread_fork.c (revision 9f79a69831e4879318a9c62b1da26ebbbfc9edc0)
1*9f79a698Smpi /*	$OpenBSD: rthread_fork.c,v 1.23 2017/10/29 08:45:53 mpi Exp $ */
2dc989ac6Skurt 
3dc989ac6Skurt /*
4dc989ac6Skurt  * Copyright (c) 2008 Kurt Miller <kurt@openbsd.org>
5514a545fSguenther  * Copyright (c) 2008 Philip Guenther <guenther@openbsd.org>
6dc989ac6Skurt  * Copyright (c) 2003 Daniel Eischen <deischen@freebsd.org>
7dc989ac6Skurt  * All rights reserved.
8dc989ac6Skurt  *
9dc989ac6Skurt  * Redistribution and use in source and binary forms, with or without
10dc989ac6Skurt  * modification, are permitted provided that the following conditions
11dc989ac6Skurt  * are met:
12dc989ac6Skurt  * 1. Redistributions of source code must retain the above copyright
13dc989ac6Skurt  *    notice, this list of conditions and the following disclaimer.
14dc989ac6Skurt  * 2. Neither the name of the author nor the names of any co-contributors
15dc989ac6Skurt  *    may be used to endorse or promote products derived from this software
16dc989ac6Skurt  *    without specific prior written permission.
17dc989ac6Skurt  *
18dc989ac6Skurt  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19dc989ac6Skurt  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20dc989ac6Skurt  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21dc989ac6Skurt  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22dc989ac6Skurt  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23dc989ac6Skurt  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24dc989ac6Skurt  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25dc989ac6Skurt  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26dc989ac6Skurt  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27dc989ac6Skurt  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28dc989ac6Skurt  * SUCH DAMAGE.
29dc989ac6Skurt  *
30dc989ac6Skurt  * $FreeBSD: /repoman/r/ncvs/src/lib/libc_r/uthread/uthread_atfork.c,v 1.1 2004/12/10 03:36:45 grog Exp $
31dc989ac6Skurt  */
32dc989ac6Skurt 
33b8ec2dbdSguenther #ifndef NO_PIC
3428e55baeSmatthew #include <sys/types.h>
35*9f79a698Smpi #include <elf.h>
3628e55baeSmatthew #pragma weak _DYNAMIC
3728e55baeSmatthew #endif
3828e55baeSmatthew 
39dc989ac6Skurt #include <errno.h>
40dc989ac6Skurt #include <pthread.h>
41a5511fa9Sguenther #include <stdio.h>
42dc989ac6Skurt #include <stdlib.h>
43fe38b55cSguenther #include <tib.h>
44dc989ac6Skurt #include <unistd.h>
45dc989ac6Skurt 
46dc989ac6Skurt #include "rthread.h"
47fe38b55cSguenther #include "rthread_cb.h"
48dc989ac6Skurt 
49fe38b55cSguenther /* make {fork,vfork,getthrid} call _thread_sys_{fork,vfork,getthrid} */
50fe38b55cSguenther REDIRECT_SYSCALL(fork);
51fe38b55cSguenther REDIRECT_SYSCALL(vfork);
5229088be8Sguenther REDIRECT_SYSCALL(getthrid);
5329088be8Sguenther 
54fe38b55cSguenther static pid_t
_dofork(pid_t (* sys_fork)(void))55fe38b55cSguenther _dofork(pid_t (*sys_fork)(void))
56dc989ac6Skurt {
57dc989ac6Skurt 	pthread_t me;
58dc989ac6Skurt 	pid_t newid;
59a9128774Stedu 	extern int _post_threaded;
60dc989ac6Skurt 
61dc989ac6Skurt 	if (!_threads_ready)
62dc989ac6Skurt 		return sys_fork();
63dc989ac6Skurt 
64dc989ac6Skurt 	me = pthread_self();
65dc989ac6Skurt 
66dc989ac6Skurt 	/*
67dc989ac6Skurt 	 * Protect important libc/ld.so critical areas across the fork call.
68dc989ac6Skurt 	 * dlclose() will grab the atexit lock via __cxa_finalize() so lock
695f82dc8bSguenther 	 * the dl_lock first. malloc()/free() can use arc4random(), so lock
705f82dc8bSguenther 	 * malloc_lock before arc4_lock
71dc989ac6Skurt 	 */
72dc989ac6Skurt 
73b8ec2dbdSguenther #ifndef NO_PIC
7428e55baeSmatthew 	if (_DYNAMIC)
75dc989ac6Skurt 		_rthread_dl_lock(0);
76dc989ac6Skurt #endif
77dc989ac6Skurt 
78a5511fa9Sguenther 	newid = _thread_dofork(sys_fork);
79dc989ac6Skurt 
80dc989ac6Skurt 	if (newid == 0) {
81fe38b55cSguenther 		struct tib *tib = me->tib;
82b8ec2dbdSguenther #ifndef NO_PIC
83e0ad4b33Sguenther 		/* reinitialize the lock in the child */
84e0ad4b33Sguenther 		if (_DYNAMIC)
85e0ad4b33Sguenther 			_rthread_dl_lock(2);
86e0ad4b33Sguenther #endif
87dc989ac6Skurt 		/* update this thread's structure */
88fe38b55cSguenther 		tib->tib_tid = getthrid();
89f050dd83Sakfaew 		me->donesem.lock = _SPINLOCK_UNLOCKED;
90f050dd83Sakfaew 		me->flags_lock = _SPINLOCK_UNLOCKED;
91dc989ac6Skurt 
92dc989ac6Skurt 		/* reinit the thread list */
93dc989ac6Skurt 		LIST_INIT(&_thread_list);
94cd0b4b49Sguenther 		LIST_INSERT_HEAD(&_thread_list, me, threads);
95f050dd83Sakfaew 		_thread_lock = _SPINLOCK_UNLOCKED;
96d049d58eSguenther 
97d049d58eSguenther 		/* single threaded now */
98d049d58eSguenther 		__isthreaded = 0;
99c85623dfStedu 		_post_threaded = 0; /* notyet... */
100dc989ac6Skurt 	}
101b8ec2dbdSguenther #ifndef NO_PIC
102e0ad4b33Sguenther 	else if (_DYNAMIC)
103e0ad4b33Sguenther 		_rthread_dl_lock(1);
104e0ad4b33Sguenther #endif
105dc989ac6Skurt 	return newid;
106dc989ac6Skurt }
107dc989ac6Skurt 
108dc989ac6Skurt pid_t
_thread_fork(void)109514a545fSguenther _thread_fork(void)
110dc989ac6Skurt {
111fe38b55cSguenther 	return _dofork(&fork);
112dc989ac6Skurt }
113dc989ac6Skurt 
114dc989ac6Skurt pid_t
_thread_vfork(void)115fe38b55cSguenther _thread_vfork(void)
116dc989ac6Skurt {
117fe38b55cSguenther 	return _dofork(&vfork);
118dc989ac6Skurt }
119