thr_fork.c revision 164583
1178476Sjb/*
2178476Sjb * Copyright (c) 2005 David Xu <davidxu@freebsd.org>
3178476Sjb * Copyright (c) 2003 Daniel Eischen <deischen@freebsd.org>
4178476Sjb * All rights reserved.
5178476Sjb *
6178476Sjb * Redistribution and use in source and binary forms, with or without
7178476Sjb * modification, are permitted provided that the following conditions
8178476Sjb * are met:
9178476Sjb * 1. Redistributions of source code must retain the above copyright
10178476Sjb *    notice, this list of conditions and the following disclaimer.
11178476Sjb * 2. Neither the name of the author nor the names of any co-contributors
12178476Sjb *    may be used to endorse or promote products derived from this software
13178476Sjb *    without specific prior written permission.
14178476Sjb *
15178476Sjb * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16178476Sjb * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17178476Sjb * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18178476Sjb * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19178476Sjb * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20178476Sjb * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21178476Sjb * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22178476Sjb * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23178476Sjb * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24178476Sjb * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25178476Sjb * SUCH DAMAGE.
26178476Sjb *
27178476Sjb * $FreeBSD: head/lib/libthr/thread/thr_fork.c 164583 2006-11-24 09:57:38Z davidxu $
28178476Sjb */
29178476Sjb
30178476Sjb/*
31178476Sjb * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>
32178476Sjb * All rights reserved.
33178476Sjb *
34178476Sjb * Redistribution and use in source and binary forms, with or without
35178476Sjb * modification, are permitted provided that the following conditions
36178476Sjb * are met:
37178476Sjb * 1. Redistributions of source code must retain the above copyright
38178476Sjb *    notice, this list of conditions and the following disclaimer.
39178476Sjb * 2. Redistributions in binary form must reproduce the above copyright
40178476Sjb *    notice, this list of conditions and the following disclaimer in the
41178476Sjb *    documentation and/or other materials provided with the distribution.
42178476Sjb * 3. All advertising materials mentioning features or use of this software
43178476Sjb *    must display the following acknowledgement:
44178476Sjb *	This product includes software developed by John Birrell.
45178476Sjb * 4. Neither the name of the author nor the names of any co-contributors
46178476Sjb *    may be used to endorse or promote products derived from this software
47178476Sjb *    without specific prior written permission.
48 *
49 * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
50 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
51 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
52 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
53 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
54 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
55 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
56 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
57 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
58 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
59 * SUCH DAMAGE.
60 *
61 */
62
63#include "namespace.h"
64#include <errno.h>
65#include <string.h>
66#include <stdlib.h>
67#include <unistd.h>
68#include <pthread.h>
69#include <spinlock.h>
70#include "un-namespace.h"
71
72#include "libc_private.h"
73#include "thr_private.h"
74
75__weak_reference(_pthread_atfork, pthread_atfork);
76
77int
78_pthread_atfork(void (*prepare)(void), void (*parent)(void),
79    void (*child)(void))
80{
81	struct pthread *curthread;
82	struct pthread_atfork *af;
83
84	_thr_check_init();
85
86	if ((af = malloc(sizeof(struct pthread_atfork))) == NULL)
87		return (ENOMEM);
88
89	curthread = _get_curthread();
90	af->prepare = prepare;
91	af->parent = parent;
92	af->child = child;
93	THR_UMUTEX_LOCK(curthread, &_thr_atfork_lock);
94	TAILQ_INSERT_TAIL(&_thr_atfork_list, af, qe);
95	THR_UMUTEX_UNLOCK(curthread, &_thr_atfork_lock);
96	return (0);
97}
98
99__weak_reference(_fork, fork);
100
101pid_t _fork(void);
102
103pid_t
104_fork(void)
105{
106	struct pthread *curthread;
107	struct pthread_atfork *af;
108	pid_t ret;
109	int errsave;
110	int unlock_malloc;
111
112	if (!_thr_is_inited())
113		return (__sys_fork());
114
115	curthread = _get_curthread();
116
117	THR_UMUTEX_LOCK(curthread, &_thr_atfork_lock);
118
119	/* Run down atfork prepare handlers. */
120	TAILQ_FOREACH_REVERSE(af, &_thr_atfork_list, atfork_head, qe) {
121		if (af->prepare != NULL)
122			af->prepare();
123	}
124
125	/*
126	 * Try our best to protect memory from being corrupted in
127	 * child process because another thread in malloc code will
128	 * simply be kill by fork().
129	 */
130	if (_thr_isthreaded() != 0) {
131		unlock_malloc = 1;
132		_malloc_prefork();
133	} else {
134		unlock_malloc = 0;
135	}
136
137	/*
138	 * Block all signals until we reach a safe point.
139	 */
140	_thr_signal_block(curthread);
141
142	/* Fork a new process: */
143	if ((ret = __sys_fork()) == 0) {
144		/* Child process */
145		errsave = errno;
146		curthread->cancel_pending = 0;
147		curthread->flags &= ~THR_FLAGS_NEED_SUSPEND;
148
149		/*
150		 * Thread list will be reinitialized, and later we call
151		 * _libpthread_init(), it will add us back to list.
152		 */
153		curthread->tlflags &= ~(TLFLAGS_IN_TDLIST | TLFLAGS_DETACHED);
154
155		/* child is a new kernel thread. */
156		thr_self(&curthread->tid);
157
158		/* clear other threads locked us. */
159		_thr_umutex_init(&curthread->lock);
160		_thr_umutex_init(&_thr_atfork_lock);
161		_thr_setthreaded(0);
162
163		/* reinitialize libc spinlocks. */
164		_thr_spinlock_init();
165		_mutex_fork(curthread);
166
167		/* reinitalize library. */
168		_libpthread_init(curthread);
169
170		/* Ready to continue, unblock signals. */
171		_thr_signal_unblock(curthread);
172
173		/* Run down atfork child handlers. */
174		TAILQ_FOREACH(af, &_thr_atfork_list, qe) {
175			if (af->child != NULL)
176				af->child();
177		}
178	} else {
179		/* Parent process */
180		errsave = errno;
181
182		/* Ready to continue, unblock signals. */
183		_thr_signal_unblock(curthread);
184
185		if (unlock_malloc)
186			_malloc_postfork();
187
188		/* Run down atfork parent handlers. */
189		TAILQ_FOREACH(af, &_thr_atfork_list, qe) {
190			if (af->parent != NULL)
191				af->parent();
192		}
193
194		THR_UMUTEX_UNLOCK(curthread, &_thr_atfork_lock);
195	}
196	errno = errsave;
197
198	/* Return the process ID: */
199	return (ret);
200}
201