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 131277317Skib__weak_reference(__thr_fork, _fork); 132144518Sdavidxu 133144518Sdavidxupid_t 134277317Skib__thr_fork(void) 135144518Sdavidxu{ 136144518Sdavidxu struct pthread *curthread; 137144518Sdavidxu struct pthread_atfork *af; 138144518Sdavidxu pid_t ret; 139212841Sdavidxu int errsave, cancelsave; 140191993Sgreen int was_threaded; 141185558Skib int rtld_locks[MAX_RTLD_LOCKS]; 142144518Sdavidxu 143144518Sdavidxu if (!_thr_is_inited()) 144144518Sdavidxu return (__sys_fork()); 145144518Sdavidxu 146144518Sdavidxu curthread = _get_curthread(); 147212841Sdavidxu cancelsave = curthread->no_cancel; 148212841Sdavidxu curthread->no_cancel = 1; 149212077Sdavidxu _thr_rwl_rdlock(&_thr_atfork_lock); 150144518Sdavidxu 151144518Sdavidxu /* Run down atfork prepare handlers. */ 152144518Sdavidxu TAILQ_FOREACH_REVERSE(af, &_thr_atfork_list, atfork_head, qe) { 153144518Sdavidxu if (af->prepare != NULL) 154144518Sdavidxu af->prepare(); 155144518Sdavidxu } 156144518Sdavidxu 157144518Sdavidxu /* 158212077Sdavidxu * Block all signals until we reach a safe point. 159212077Sdavidxu */ 160212077Sdavidxu _thr_signal_block(curthread); 161212077Sdavidxu _thr_signal_prefork(); 162212077Sdavidxu 163212077Sdavidxu /* 164191993Sgreen * All bets are off as to what should happen soon if the parent 165191993Sgreen * process was not so kindly as to set up pthread fork hooks to 166191993Sgreen * relinquish all running threads. 167144518Sdavidxu */ 168154248Sjasone if (_thr_isthreaded() != 0) { 169191993Sgreen was_threaded = 1; 170154248Sjasone _malloc_prefork(); 171185369Skib _rtld_atfork_pre(rtld_locks); 172144518Sdavidxu } else { 173191993Sgreen was_threaded = 0; 174144518Sdavidxu } 175144518Sdavidxu 176267200Skib /* 177267200Skib * Fork a new process. 178267200Skib * There is no easy way to pre-resolve the __sys_fork symbol 179267200Skib * without performing the fork. Use the syscall(2) 180267200Skib * indirection, the syscall symbol is resolved in 181267200Skib * _thr_rtld_init() with side-effect free call. 182267200Skib */ 183267200Skib ret = syscall(SYS_fork); 184267200Skib if (ret == 0) { 185144518Sdavidxu /* Child process */ 186144518Sdavidxu errsave = errno; 187164583Sdavidxu curthread->cancel_pending = 0; 188212536Sdavidxu curthread->flags &= ~(THR_FLAGS_NEED_SUSPEND|THR_FLAGS_DETACHED); 189163346Sdavidxu 190144518Sdavidxu /* 191144518Sdavidxu * Thread list will be reinitialized, and later we call 192144518Sdavidxu * _libpthread_init(), it will add us back to list. 193144518Sdavidxu */ 194212536Sdavidxu curthread->tlflags &= ~TLFLAGS_IN_TDLIST; 195144518Sdavidxu 196144518Sdavidxu /* child is a new kernel thread. */ 197144518Sdavidxu thr_self(&curthread->tid); 198144518Sdavidxu 199144518Sdavidxu /* clear other threads locked us. */ 200162061Sdavidxu _thr_umutex_init(&curthread->lock); 201212077Sdavidxu _mutex_fork(curthread); 202185531Skan 203212076Sdavidxu _thr_signal_postfork_child(); 204212076Sdavidxu 205191993Sgreen if (was_threaded) 206185531Skan _rtld_atfork_post(rtld_locks); 207144518Sdavidxu _thr_setthreaded(0); 208144518Sdavidxu 209144518Sdavidxu /* reinitalize library. */ 210144518Sdavidxu _libpthread_init(curthread); 211144518Sdavidxu 212212077Sdavidxu /* atfork is reinitializeded by _libpthread_init()! */ 213212077Sdavidxu _thr_rwl_rdlock(&_thr_atfork_lock); 214144518Sdavidxu 215191993Sgreen if (was_threaded) { 216190025Skib __isthreaded = 1; 217185456Skib _malloc_postfork(); 218190025Skib __isthreaded = 0; 219190025Skib } 220185369Skib 221212077Sdavidxu /* Ready to continue, unblock signals. */ 222212077Sdavidxu _thr_signal_unblock(curthread); 223212077Sdavidxu 224144518Sdavidxu /* Run down atfork child handlers. */ 225144518Sdavidxu TAILQ_FOREACH(af, &_thr_atfork_list, qe) { 226144518Sdavidxu if (af->child != NULL) 227144518Sdavidxu af->child(); 228144518Sdavidxu } 229212077Sdavidxu _thr_rwlock_unlock(&_thr_atfork_lock); 230212841Sdavidxu curthread->no_cancel = cancelsave; 231144518Sdavidxu } else { 232144518Sdavidxu /* Parent process */ 233144518Sdavidxu errsave = errno; 234144518Sdavidxu 235212076Sdavidxu _thr_signal_postfork(); 236212076Sdavidxu 237191993Sgreen if (was_threaded) { 238185369Skib _rtld_atfork_post(rtld_locks); 239154248Sjasone _malloc_postfork(); 240185369Skib } 241144518Sdavidxu 242212077Sdavidxu /* Ready to continue, unblock signals. */ 243212077Sdavidxu _thr_signal_unblock(curthread); 244212077Sdavidxu 245144518Sdavidxu /* Run down atfork parent handlers. */ 246144518Sdavidxu TAILQ_FOREACH(af, &_thr_atfork_list, qe) { 247144518Sdavidxu if (af->parent != NULL) 248144518Sdavidxu af->parent(); 249144518Sdavidxu } 250144518Sdavidxu 251212077Sdavidxu _thr_rwlock_unlock(&_thr_atfork_lock); 252212841Sdavidxu curthread->no_cancel = cancelsave; 253212841Sdavidxu /* test async cancel */ 254213096Sdavidxu if (curthread->cancel_async) 255213096Sdavidxu _thr_testcancel(curthread); 256144518Sdavidxu } 257144518Sdavidxu errno = errsave; 258144518Sdavidxu 259144518Sdavidxu return (ret); 260144518Sdavidxu} 261