thr_fork.c revision 154248
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 154248 2006-01-12 07:28:21Z jasone $ 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 63144518Sdavidxu#include <errno.h> 64144518Sdavidxu#include <string.h> 65144518Sdavidxu#include <stdlib.h> 66144518Sdavidxu#include <unistd.h> 67144518Sdavidxu#include <pthread.h> 68144518Sdavidxu#include <spinlock.h> 69144518Sdavidxu 70144518Sdavidxu#include "libc_private.h" 71144518Sdavidxu#include "thr_private.h" 72144518Sdavidxu 73144518Sdavidxu__weak_reference(_pthread_atfork, pthread_atfork); 74144518Sdavidxu 75144518Sdavidxuint 76144518Sdavidxu_pthread_atfork(void (*prepare)(void), void (*parent)(void), 77144518Sdavidxu void (*child)(void)) 78144518Sdavidxu{ 79144518Sdavidxu struct pthread *curthread; 80144518Sdavidxu struct pthread_atfork *af; 81144518Sdavidxu 82144518Sdavidxu _thr_check_init(); 83144518Sdavidxu 84144518Sdavidxu if ((af = malloc(sizeof(struct pthread_atfork))) == NULL) 85144518Sdavidxu return (ENOMEM); 86144518Sdavidxu 87144518Sdavidxu curthread = _get_curthread(); 88144518Sdavidxu af->prepare = prepare; 89144518Sdavidxu af->parent = parent; 90144518Sdavidxu af->child = child; 91144518Sdavidxu THR_UMTX_LOCK(curthread, &_thr_atfork_lock); 92144518Sdavidxu TAILQ_INSERT_TAIL(&_thr_atfork_list, af, qe); 93144518Sdavidxu THR_UMTX_UNLOCK(curthread, &_thr_atfork_lock); 94144518Sdavidxu return (0); 95144518Sdavidxu} 96144518Sdavidxu 97144518Sdavidxu__weak_reference(_fork, fork); 98144518Sdavidxu 99144518Sdavidxupid_t 100144518Sdavidxu_fork(void) 101144518Sdavidxu{ 102144518Sdavidxu struct pthread *curthread; 103144518Sdavidxu struct pthread_atfork *af; 104144518Sdavidxu pid_t ret; 105144518Sdavidxu int errsave; 106144518Sdavidxu int unlock_malloc; 107144518Sdavidxu 108144518Sdavidxu if (!_thr_is_inited()) 109144518Sdavidxu return (__sys_fork()); 110144518Sdavidxu 111144518Sdavidxu curthread = _get_curthread(); 112144518Sdavidxu 113144518Sdavidxu THR_UMTX_LOCK(curthread, &_thr_atfork_lock); 114144518Sdavidxu 115144518Sdavidxu /* Run down atfork prepare handlers. */ 116144518Sdavidxu TAILQ_FOREACH_REVERSE(af, &_thr_atfork_list, atfork_head, qe) { 117144518Sdavidxu if (af->prepare != NULL) 118144518Sdavidxu af->prepare(); 119144518Sdavidxu } 120144518Sdavidxu 121144518Sdavidxu /* 122144518Sdavidxu * Try our best to protect memory from being corrupted in 123144518Sdavidxu * child process because another thread in malloc code will 124144518Sdavidxu * simply be kill by fork(). 125144518Sdavidxu */ 126154248Sjasone if (_thr_isthreaded() != 0) { 127144518Sdavidxu unlock_malloc = 1; 128154248Sjasone _malloc_prefork(); 129144518Sdavidxu } else { 130144518Sdavidxu unlock_malloc = 0; 131144518Sdavidxu } 132144518Sdavidxu 133153987Sdavidxu /* 134153987Sdavidxu * Block all signals until we reach a safe point. 135153987Sdavidxu */ 136153987Sdavidxu _thr_signal_block(curthread); 137153987Sdavidxu 138144518Sdavidxu /* Fork a new process: */ 139144518Sdavidxu if ((ret = __sys_fork()) == 0) { 140144518Sdavidxu /* Child process */ 141144518Sdavidxu errsave = errno; 142144518Sdavidxu curthread->cancelflags &= ~THR_CANCEL_NEEDED; 143144518Sdavidxu /* 144144518Sdavidxu * Thread list will be reinitialized, and later we call 145144518Sdavidxu * _libpthread_init(), it will add us back to list. 146144518Sdavidxu */ 147144518Sdavidxu curthread->tlflags &= ~(TLFLAGS_IN_TDLIST | TLFLAGS_DETACHED); 148144518Sdavidxu 149144518Sdavidxu /* child is a new kernel thread. */ 150144518Sdavidxu thr_self(&curthread->tid); 151144518Sdavidxu 152144518Sdavidxu /* clear other threads locked us. */ 153144518Sdavidxu _thr_umtx_init(&curthread->lock); 154144518Sdavidxu _thr_umtx_init(&_thr_atfork_lock); 155144518Sdavidxu _thr_setthreaded(0); 156144518Sdavidxu 157154248Sjasone /* reinitialize libc spinlocks. */ 158144518Sdavidxu _thr_spinlock_init(); 159144518Sdavidxu _mutex_fork(curthread); 160144518Sdavidxu 161144518Sdavidxu /* reinitalize library. */ 162144518Sdavidxu _libpthread_init(curthread); 163144518Sdavidxu 164144518Sdavidxu /* Ready to continue, unblock signals. */ 165144518Sdavidxu _thr_signal_unblock(curthread); 166144518Sdavidxu 167144518Sdavidxu /* Run down atfork child handlers. */ 168144518Sdavidxu TAILQ_FOREACH(af, &_thr_atfork_list, qe) { 169144518Sdavidxu if (af->child != NULL) 170144518Sdavidxu af->child(); 171144518Sdavidxu } 172144518Sdavidxu } else { 173144518Sdavidxu /* Parent process */ 174144518Sdavidxu errsave = errno; 175144518Sdavidxu 176153987Sdavidxu /* Ready to continue, unblock signals. */ 177153987Sdavidxu _thr_signal_unblock(curthread); 178153987Sdavidxu 179144518Sdavidxu if (unlock_malloc) 180154248Sjasone _malloc_postfork(); 181144518Sdavidxu 182144518Sdavidxu /* Run down atfork parent handlers. */ 183144518Sdavidxu TAILQ_FOREACH(af, &_thr_atfork_list, qe) { 184144518Sdavidxu if (af->parent != NULL) 185144518Sdavidxu af->parent(); 186144518Sdavidxu } 187144518Sdavidxu 188144518Sdavidxu THR_UMTX_UNLOCK(curthread, &_thr_atfork_lock); 189144518Sdavidxu } 190144518Sdavidxu errno = errsave; 191144518Sdavidxu 192144518Sdavidxu /* Return the process ID: */ 193144518Sdavidxu return (ret); 194144518Sdavidxu} 195