thr_fork.c revision 162061
1144518Sdavidxu/* 2144518Sdavidxu * Copyright (c) 2005 David Xu <davidxu@freebsd.org> 3144518Sdavidxu * Copyright (c) 2003 Daniel Eischen <deischen@freebsd.org> 4144518Sdavidxu * All rights reserved. 5144518Sdavidxu * 6144518Sdavidxu * Redistribution and use in source and binary forms, with or without 7144518Sdavidxu * modification, are permitted provided that the following conditions 8144518Sdavidxu * are met: 9144518Sdavidxu * 1. Redistributions of source code must retain the above copyright 10144518Sdavidxu * notice, this list of conditions and the following disclaimer. 11144518Sdavidxu * 2. Neither the name of the author nor the names of any co-contributors 12144518Sdavidxu * may be used to endorse or promote products derived from this software 13144518Sdavidxu * without specific prior written permission. 14144518Sdavidxu * 15144518Sdavidxu * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16144518Sdavidxu * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17144518Sdavidxu * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18144518Sdavidxu * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19144518Sdavidxu * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20144518Sdavidxu * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21144518Sdavidxu * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22144518Sdavidxu * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23144518Sdavidxu * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24144518Sdavidxu * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25144518Sdavidxu * SUCH DAMAGE. 26144518Sdavidxu * 27144518Sdavidxu * $FreeBSD: head/lib/libthr/thread/thr_fork.c 162061 2006-09-06 04:04:10Z davidxu $ 28144518Sdavidxu */ 29144518Sdavidxu 30144518Sdavidxu/* 31144518Sdavidxu * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au> 32144518Sdavidxu * All rights reserved. 33144518Sdavidxu * 34144518Sdavidxu * Redistribution and use in source and binary forms, with or without 35144518Sdavidxu * modification, are permitted provided that the following conditions 36144518Sdavidxu * are met: 37144518Sdavidxu * 1. Redistributions of source code must retain the above copyright 38144518Sdavidxu * notice, this list of conditions and the following disclaimer. 39144518Sdavidxu * 2. Redistributions in binary form must reproduce the above copyright 40144518Sdavidxu * notice, this list of conditions and the following disclaimer in the 41144518Sdavidxu * documentation and/or other materials provided with the distribution. 42144518Sdavidxu * 3. All advertising materials mentioning features or use of this software 43144518Sdavidxu * must display the following acknowledgement: 44144518Sdavidxu * This product includes software developed by John Birrell. 45144518Sdavidxu * 4. Neither the name of the author nor the names of any co-contributors 46144518Sdavidxu * may be used to endorse or promote products derived from this software 47144518Sdavidxu * without specific prior written permission. 48144518Sdavidxu * 49144518Sdavidxu * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND 50144518Sdavidxu * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 51144518Sdavidxu * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 52144518Sdavidxu * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 53144518Sdavidxu * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 54144518Sdavidxu * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 55144518Sdavidxu * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 56144518Sdavidxu * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 57144518Sdavidxu * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 58144518Sdavidxu * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 59144518Sdavidxu * SUCH DAMAGE. 60144518Sdavidxu * 61144518Sdavidxu */ 62144518Sdavidxu 63157457Sdavidxu#include "namespace.h" 64144518Sdavidxu#include <errno.h> 65144518Sdavidxu#include <string.h> 66144518Sdavidxu#include <stdlib.h> 67144518Sdavidxu#include <unistd.h> 68144518Sdavidxu#include <pthread.h> 69144518Sdavidxu#include <spinlock.h> 70157457Sdavidxu#include "un-namespace.h" 71144518Sdavidxu 72144518Sdavidxu#include "libc_private.h" 73144518Sdavidxu#include "thr_private.h" 74144518Sdavidxu 75144518Sdavidxu__weak_reference(_pthread_atfork, pthread_atfork); 76144518Sdavidxu 77144518Sdavidxuint 78144518Sdavidxu_pthread_atfork(void (*prepare)(void), void (*parent)(void), 79144518Sdavidxu void (*child)(void)) 80144518Sdavidxu{ 81144518Sdavidxu struct pthread *curthread; 82144518Sdavidxu struct pthread_atfork *af; 83144518Sdavidxu 84144518Sdavidxu _thr_check_init(); 85144518Sdavidxu 86144518Sdavidxu if ((af = malloc(sizeof(struct pthread_atfork))) == NULL) 87144518Sdavidxu return (ENOMEM); 88144518Sdavidxu 89144518Sdavidxu curthread = _get_curthread(); 90144518Sdavidxu af->prepare = prepare; 91144518Sdavidxu af->parent = parent; 92144518Sdavidxu af->child = child; 93162061Sdavidxu THR_UMUTEX_LOCK(curthread, &_thr_atfork_lock); 94144518Sdavidxu TAILQ_INSERT_TAIL(&_thr_atfork_list, af, qe); 95162061Sdavidxu THR_UMUTEX_UNLOCK(curthread, &_thr_atfork_lock); 96144518Sdavidxu return (0); 97144518Sdavidxu} 98144518Sdavidxu 99144518Sdavidxu__weak_reference(_fork, fork); 100144518Sdavidxu 101157457Sdavidxupid_t _fork(void); 102157457Sdavidxu 103144518Sdavidxupid_t 104144518Sdavidxu_fork(void) 105144518Sdavidxu{ 106144518Sdavidxu struct pthread *curthread; 107144518Sdavidxu struct pthread_atfork *af; 108144518Sdavidxu pid_t ret; 109144518Sdavidxu int errsave; 110144518Sdavidxu int unlock_malloc; 111144518Sdavidxu 112144518Sdavidxu if (!_thr_is_inited()) 113144518Sdavidxu return (__sys_fork()); 114144518Sdavidxu 115144518Sdavidxu curthread = _get_curthread(); 116144518Sdavidxu 117162061Sdavidxu THR_UMUTEX_LOCK(curthread, &_thr_atfork_lock); 118144518Sdavidxu 119144518Sdavidxu /* Run down atfork prepare handlers. */ 120144518Sdavidxu TAILQ_FOREACH_REVERSE(af, &_thr_atfork_list, atfork_head, qe) { 121144518Sdavidxu if (af->prepare != NULL) 122144518Sdavidxu af->prepare(); 123144518Sdavidxu } 124144518Sdavidxu 125144518Sdavidxu /* 126144518Sdavidxu * Try our best to protect memory from being corrupted in 127144518Sdavidxu * child process because another thread in malloc code will 128144518Sdavidxu * simply be kill by fork(). 129144518Sdavidxu */ 130154248Sjasone if (_thr_isthreaded() != 0) { 131144518Sdavidxu unlock_malloc = 1; 132154248Sjasone _malloc_prefork(); 133144518Sdavidxu } else { 134144518Sdavidxu unlock_malloc = 0; 135144518Sdavidxu } 136144518Sdavidxu 137153987Sdavidxu /* 138153987Sdavidxu * Block all signals until we reach a safe point. 139153987Sdavidxu */ 140153987Sdavidxu _thr_signal_block(curthread); 141153987Sdavidxu 142144518Sdavidxu /* Fork a new process: */ 143144518Sdavidxu if ((ret = __sys_fork()) == 0) { 144144518Sdavidxu /* Child process */ 145144518Sdavidxu errsave = errno; 146144518Sdavidxu curthread->cancelflags &= ~THR_CANCEL_NEEDED; 147144518Sdavidxu /* 148144518Sdavidxu * Thread list will be reinitialized, and later we call 149144518Sdavidxu * _libpthread_init(), it will add us back to list. 150144518Sdavidxu */ 151144518Sdavidxu curthread->tlflags &= ~(TLFLAGS_IN_TDLIST | TLFLAGS_DETACHED); 152144518Sdavidxu 153144518Sdavidxu /* child is a new kernel thread. */ 154144518Sdavidxu thr_self(&curthread->tid); 155144518Sdavidxu 156144518Sdavidxu /* clear other threads locked us. */ 157162061Sdavidxu _thr_umutex_init(&curthread->lock); 158162061Sdavidxu _thr_umutex_init(&_thr_atfork_lock); 159144518Sdavidxu _thr_setthreaded(0); 160144518Sdavidxu 161154248Sjasone /* reinitialize libc spinlocks. */ 162144518Sdavidxu _thr_spinlock_init(); 163144518Sdavidxu _mutex_fork(curthread); 164144518Sdavidxu 165144518Sdavidxu /* reinitalize library. */ 166144518Sdavidxu _libpthread_init(curthread); 167144518Sdavidxu 168144518Sdavidxu /* Ready to continue, unblock signals. */ 169144518Sdavidxu _thr_signal_unblock(curthread); 170144518Sdavidxu 171144518Sdavidxu /* Run down atfork child handlers. */ 172144518Sdavidxu TAILQ_FOREACH(af, &_thr_atfork_list, qe) { 173144518Sdavidxu if (af->child != NULL) 174144518Sdavidxu af->child(); 175144518Sdavidxu } 176144518Sdavidxu } else { 177144518Sdavidxu /* Parent process */ 178144518Sdavidxu errsave = errno; 179144518Sdavidxu 180153987Sdavidxu /* Ready to continue, unblock signals. */ 181153987Sdavidxu _thr_signal_unblock(curthread); 182153987Sdavidxu 183144518Sdavidxu if (unlock_malloc) 184154248Sjasone _malloc_postfork(); 185144518Sdavidxu 186144518Sdavidxu /* Run down atfork parent handlers. */ 187144518Sdavidxu TAILQ_FOREACH(af, &_thr_atfork_list, qe) { 188144518Sdavidxu if (af->parent != NULL) 189144518Sdavidxu af->parent(); 190144518Sdavidxu } 191144518Sdavidxu 192162061Sdavidxu THR_UMUTEX_UNLOCK(curthread, &_thr_atfork_lock); 193144518Sdavidxu } 194144518Sdavidxu errno = errsave; 195144518Sdavidxu 196144518Sdavidxu /* Return the process ID: */ 197144518Sdavidxu return (ret); 198144518Sdavidxu} 199