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$ 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. 42165967Simp * 3. Neither the name of the author nor the names of any co-contributors 43144518Sdavidxu * may be used to endorse or promote products derived from this software 44144518Sdavidxu * without specific prior written permission. 45144518Sdavidxu * 46144518Sdavidxu * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND 47144518Sdavidxu * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 48144518Sdavidxu * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 49144518Sdavidxu * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 50144518Sdavidxu * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 51144518Sdavidxu * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 52144518Sdavidxu * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 53144518Sdavidxu * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 54144518Sdavidxu * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 55144518Sdavidxu * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 56144518Sdavidxu * SUCH DAMAGE. 57144518Sdavidxu * 58144518Sdavidxu */ 59144518Sdavidxu 60267200Skib#include <sys/syscall.h> 61157457Sdavidxu#include "namespace.h" 62144518Sdavidxu#include <errno.h> 63211706Skib#include <link.h> 64144518Sdavidxu#include <string.h> 65144518Sdavidxu#include <stdlib.h> 66144518Sdavidxu#include <unistd.h> 67144518Sdavidxu#include <pthread.h> 68144518Sdavidxu#include <spinlock.h> 69157457Sdavidxu#include "un-namespace.h" 70144518Sdavidxu 71144518Sdavidxu#include "libc_private.h" 72185369Skib#include "rtld_lock.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; 93212078Sdavidxu THR_CRITICAL_ENTER(curthread); 94212078Sdavidxu _thr_rwl_wrlock(&_thr_atfork_lock); 95144518Sdavidxu TAILQ_INSERT_TAIL(&_thr_atfork_list, af, qe); 96212077Sdavidxu _thr_rwl_unlock(&_thr_atfork_lock); 97212078Sdavidxu THR_CRITICAL_LEAVE(curthread); 98144518Sdavidxu return (0); 99144518Sdavidxu} 100144518Sdavidxu 101211706Skibvoid 102211706Skib__pthread_cxa_finalize(struct dl_phdr_info *phdr_info) 103211706Skib{ 104212083Sdavidxu atfork_head temp_list = TAILQ_HEAD_INITIALIZER(temp_list); 105211706Skib struct pthread *curthread; 106211706Skib struct pthread_atfork *af, *af1; 107211706Skib 108211706Skib _thr_check_init(); 109211706Skib 110211706Skib curthread = _get_curthread(); 111212083Sdavidxu THR_CRITICAL_ENTER(curthread); 112212077Sdavidxu _thr_rwl_wrlock(&_thr_atfork_lock); 113211706Skib TAILQ_FOREACH_SAFE(af, &_thr_atfork_list, qe, af1) { 114211706Skib if (__elf_phdr_match_addr(phdr_info, af->prepare) || 115211706Skib __elf_phdr_match_addr(phdr_info, af->parent) || 116211706Skib __elf_phdr_match_addr(phdr_info, af->child)) { 117211706Skib TAILQ_REMOVE(&_thr_atfork_list, af, qe); 118212083Sdavidxu TAILQ_INSERT_TAIL(&temp_list, af, qe); 119211706Skib } 120211706Skib } 121212077Sdavidxu _thr_rwl_unlock(&_thr_atfork_lock); 122212083Sdavidxu THR_CRITICAL_LEAVE(curthread); 123212083Sdavidxu while ((af = TAILQ_FIRST(&temp_list)) != NULL) { 124212083Sdavidxu TAILQ_REMOVE(&temp_list, af, qe); 125212083Sdavidxu free(af); 126212083Sdavidxu } 127211860Sdavidxu _thr_tsd_unload(phdr_info); 128212076Sdavidxu _thr_sigact_unload(phdr_info); 129211706Skib} 130211706Skib 131144518Sdavidxu__weak_reference(_fork, fork); 132144518Sdavidxu 133157457Sdavidxupid_t _fork(void); 134157457Sdavidxu 135144518Sdavidxupid_t 136144518Sdavidxu_fork(void) 137144518Sdavidxu{ 138144518Sdavidxu struct pthread *curthread; 139144518Sdavidxu struct pthread_atfork *af; 140144518Sdavidxu pid_t ret; 141212841Sdavidxu int errsave, cancelsave; 142191993Sgreen int was_threaded; 143185558Skib int rtld_locks[MAX_RTLD_LOCKS]; 144144518Sdavidxu 145144518Sdavidxu if (!_thr_is_inited()) 146144518Sdavidxu return (__sys_fork()); 147144518Sdavidxu 148144518Sdavidxu curthread = _get_curthread(); 149212841Sdavidxu cancelsave = curthread->no_cancel; 150212841Sdavidxu curthread->no_cancel = 1; 151212077Sdavidxu _thr_rwl_rdlock(&_thr_atfork_lock); 152144518Sdavidxu 153144518Sdavidxu /* Run down atfork prepare handlers. */ 154144518Sdavidxu TAILQ_FOREACH_REVERSE(af, &_thr_atfork_list, atfork_head, qe) { 155144518Sdavidxu if (af->prepare != NULL) 156144518Sdavidxu af->prepare(); 157144518Sdavidxu } 158144518Sdavidxu 159144518Sdavidxu /* 160212077Sdavidxu * Block all signals until we reach a safe point. 161212077Sdavidxu */ 162212077Sdavidxu _thr_signal_block(curthread); 163212077Sdavidxu _thr_signal_prefork(); 164212077Sdavidxu 165212077Sdavidxu /* 166191993Sgreen * All bets are off as to what should happen soon if the parent 167191993Sgreen * process was not so kindly as to set up pthread fork hooks to 168191993Sgreen * relinquish all running threads. 169144518Sdavidxu */ 170154248Sjasone if (_thr_isthreaded() != 0) { 171191993Sgreen was_threaded = 1; 172154248Sjasone _malloc_prefork(); 173185369Skib _rtld_atfork_pre(rtld_locks); 174144518Sdavidxu } else { 175191993Sgreen was_threaded = 0; 176144518Sdavidxu } 177144518Sdavidxu 178267200Skib /* 179267200Skib * Fork a new process. 180267200Skib * There is no easy way to pre-resolve the __sys_fork symbol 181267200Skib * without performing the fork. Use the syscall(2) 182267200Skib * indirection, the syscall symbol is resolved in 183267200Skib * _thr_rtld_init() with side-effect free call. 184267200Skib */ 185267200Skib ret = syscall(SYS_fork); 186267200Skib if (ret == 0) { 187144518Sdavidxu /* Child process */ 188144518Sdavidxu errsave = errno; 189164583Sdavidxu curthread->cancel_pending = 0; 190212536Sdavidxu curthread->flags &= ~(THR_FLAGS_NEED_SUSPEND|THR_FLAGS_DETACHED); 191163346Sdavidxu 192144518Sdavidxu /* 193144518Sdavidxu * Thread list will be reinitialized, and later we call 194144518Sdavidxu * _libpthread_init(), it will add us back to list. 195144518Sdavidxu */ 196212536Sdavidxu curthread->tlflags &= ~TLFLAGS_IN_TDLIST; 197144518Sdavidxu 198144518Sdavidxu /* child is a new kernel thread. */ 199144518Sdavidxu thr_self(&curthread->tid); 200144518Sdavidxu 201144518Sdavidxu /* clear other threads locked us. */ 202162061Sdavidxu _thr_umutex_init(&curthread->lock); 203212077Sdavidxu _mutex_fork(curthread); 204185531Skan 205212076Sdavidxu _thr_signal_postfork_child(); 206212076Sdavidxu 207191993Sgreen if (was_threaded) 208185531Skan _rtld_atfork_post(rtld_locks); 209144518Sdavidxu _thr_setthreaded(0); 210144518Sdavidxu 211144518Sdavidxu /* reinitalize library. */ 212144518Sdavidxu _libpthread_init(curthread); 213144518Sdavidxu 214212077Sdavidxu /* atfork is reinitializeded by _libpthread_init()! */ 215212077Sdavidxu _thr_rwl_rdlock(&_thr_atfork_lock); 216144518Sdavidxu 217191993Sgreen if (was_threaded) { 218190025Skib __isthreaded = 1; 219185456Skib _malloc_postfork(); 220190025Skib __isthreaded = 0; 221190025Skib } 222185369Skib 223212077Sdavidxu /* Ready to continue, unblock signals. */ 224212077Sdavidxu _thr_signal_unblock(curthread); 225212077Sdavidxu 226144518Sdavidxu /* Run down atfork child handlers. */ 227144518Sdavidxu TAILQ_FOREACH(af, &_thr_atfork_list, qe) { 228144518Sdavidxu if (af->child != NULL) 229144518Sdavidxu af->child(); 230144518Sdavidxu } 231212077Sdavidxu _thr_rwlock_unlock(&_thr_atfork_lock); 232212841Sdavidxu curthread->no_cancel = cancelsave; 233144518Sdavidxu } else { 234144518Sdavidxu /* Parent process */ 235144518Sdavidxu errsave = errno; 236144518Sdavidxu 237212076Sdavidxu _thr_signal_postfork(); 238212076Sdavidxu 239191993Sgreen if (was_threaded) { 240185369Skib _rtld_atfork_post(rtld_locks); 241154248Sjasone _malloc_postfork(); 242185369Skib } 243144518Sdavidxu 244212077Sdavidxu /* Ready to continue, unblock signals. */ 245212077Sdavidxu _thr_signal_unblock(curthread); 246212077Sdavidxu 247144518Sdavidxu /* Run down atfork parent handlers. */ 248144518Sdavidxu TAILQ_FOREACH(af, &_thr_atfork_list, qe) { 249144518Sdavidxu if (af->parent != NULL) 250144518Sdavidxu af->parent(); 251144518Sdavidxu } 252144518Sdavidxu 253212077Sdavidxu _thr_rwlock_unlock(&_thr_atfork_lock); 254212841Sdavidxu curthread->no_cancel = cancelsave; 255212841Sdavidxu /* test async cancel */ 256213096Sdavidxu if (curthread->cancel_async) 257213096Sdavidxu _thr_testcancel(curthread); 258144518Sdavidxu } 259144518Sdavidxu errno = errsave; 260144518Sdavidxu 261144518Sdavidxu return (ret); 262144518Sdavidxu} 263