Home | History | Annotate | Line # | Download | only in thread
      1 /*
      2  * Copyright (c) 2005 David Xu <davidxu (at) freebsd.org>
      3  * Copyright (c) 2003 Daniel Eischen <deischen (at) freebsd.org>
      4  * All rights reserved.
      5  *
      6  * Redistribution and use in source and binary forms, with or without
      7  * modification, are permitted provided that the following conditions
      8  * are met:
      9  * 1. Redistributions of source code must retain the above copyright
     10  *    notice, this list of conditions and the following disclaimer.
     11  * 2. Neither the name of the author nor the names of any co-contributors
     12  *    may be used to endorse or promote products derived from this software
     13  *    without specific prior written permission.
     14  *
     15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
     16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     25  * SUCH DAMAGE.
     26  */
     27 
     28 /*
     29  * Copyright (c) 1995-1998 John Birrell <jb (at) cimlogic.com.au>
     30  * All rights reserved.
     31  *
     32  * Redistribution and use in source and binary forms, with or without
     33  * modification, are permitted provided that the following conditions
     34  * are met:
     35  * 1. Redistributions of source code must retain the above copyright
     36  *    notice, this list of conditions and the following disclaimer.
     37  * 2. Redistributions in binary form must reproduce the above copyright
     38  *    notice, this list of conditions and the following disclaimer in the
     39  *    documentation and/or other materials provided with the distribution.
     40  * 3. Neither the name of the author nor the names of any co-contributors
     41  *    may be used to endorse or promote products derived from this software
     42  *    without specific prior written permission.
     43  *
     44  * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
     45  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     46  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     47  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     48  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     49  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     50  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     51  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     52  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     53  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     54  * SUCH DAMAGE.
     55  *
     56  */
     57 
     58 #include <sys/cdefs.h>
     59 __FBSDID("$FreeBSD: head/lib/libthr/thread/thr_fork.c 297706 2016-04-08 11:15:26Z kib $");
     60 
     61 #include <sys/syscall.h>
     62 #include "namespace.h"
     63 #include <errno.h>
     64 #include <link.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 "rtld_lock.h"
     74 #include "thr_private.h"
     75 
     76 __weak_reference(_pthread_atfork, pthread_atfork);
     77 
     78 int
     79 _pthread_atfork(void (*prepare)(void), void (*parent)(void),
     80     void (*child)(void))
     81 {
     82 	struct pthread *curthread;
     83 	struct pthread_atfork *af;
     84 
     85 	_thr_check_init();
     86 
     87 	if ((af = malloc(sizeof(struct pthread_atfork))) == NULL)
     88 		return (ENOMEM);
     89 
     90 	curthread = _get_curthread();
     91 	af->prepare = prepare;
     92 	af->parent = parent;
     93 	af->child = child;
     94 	THR_CRITICAL_ENTER(curthread);
     95 	_thr_rwl_wrlock(&_thr_atfork_lock);
     96 	TAILQ_INSERT_TAIL(&_thr_atfork_list, af, qe);
     97 	_thr_rwl_unlock(&_thr_atfork_lock);
     98 	THR_CRITICAL_LEAVE(curthread);
     99 	return (0);
    100 }
    101 
    102 void
    103 __pthread_cxa_finalize(struct dl_phdr_info *phdr_info)
    104 {
    105 	atfork_head    temp_list = TAILQ_HEAD_INITIALIZER(temp_list);
    106 	struct pthread *curthread;
    107 	struct pthread_atfork *af, *af1;
    108 
    109 	_thr_check_init();
    110 
    111 	curthread = _get_curthread();
    112 	THR_CRITICAL_ENTER(curthread);
    113 	_thr_rwl_wrlock(&_thr_atfork_lock);
    114 	TAILQ_FOREACH_SAFE(af, &_thr_atfork_list, qe, af1) {
    115 		if (__elf_phdr_match_addr(phdr_info, af->prepare) ||
    116 		    __elf_phdr_match_addr(phdr_info, af->parent) ||
    117 		    __elf_phdr_match_addr(phdr_info, af->child)) {
    118 			TAILQ_REMOVE(&_thr_atfork_list, af, qe);
    119 			TAILQ_INSERT_TAIL(&temp_list, af, qe);
    120 		}
    121 	}
    122 	_thr_rwl_unlock(&_thr_atfork_lock);
    123 	THR_CRITICAL_LEAVE(curthread);
    124 	while ((af = TAILQ_FIRST(&temp_list)) != NULL) {
    125 		TAILQ_REMOVE(&temp_list, af, qe);
    126 		free(af);
    127 	}
    128 	_thr_tsd_unload(phdr_info);
    129 	_thr_sigact_unload(phdr_info);
    130 }
    131 
    132 __weak_reference(__thr_fork, _fork);
    133 
    134 pid_t
    135 __thr_fork(void)
    136 {
    137 	struct pthread *curthread;
    138 	struct pthread_atfork *af;
    139 	pid_t ret;
    140 	int errsave, cancelsave;
    141 	int was_threaded;
    142 	int rtld_locks[MAX_RTLD_LOCKS];
    143 
    144 	if (!_thr_is_inited())
    145 		return (__sys_fork());
    146 
    147 	curthread = _get_curthread();
    148 	cancelsave = curthread->no_cancel;
    149 	curthread->no_cancel = 1;
    150 	_thr_rwl_rdlock(&_thr_atfork_lock);
    151 
    152 	/* Run down atfork prepare handlers. */
    153 	TAILQ_FOREACH_REVERSE(af, &_thr_atfork_list, atfork_head, qe) {
    154 		if (af->prepare != NULL)
    155 			af->prepare();
    156 	}
    157 
    158 	/*
    159 	 * Block all signals until we reach a safe point.
    160 	 */
    161 	_thr_signal_block(curthread);
    162 	_thr_signal_prefork();
    163 
    164 	/*
    165 	 * All bets are off as to what should happen soon if the parent
    166 	 * process was not so kindly as to set up pthread fork hooks to
    167 	 * relinquish all running threads.
    168 	 */
    169 	if (_thr_isthreaded() != 0) {
    170 		was_threaded = 1;
    171 		_malloc_prefork();
    172 		__thr_pshared_atfork_pre();
    173 		_rtld_atfork_pre(rtld_locks);
    174 	} else {
    175 		was_threaded = 0;
    176 	}
    177 
    178 	/*
    179 	 * Fork a new process.
    180 	 * There is no easy way to pre-resolve the __sys_fork symbol
    181 	 * without performing the fork.  Use the syscall(2)
    182 	 * indirection, the syscall symbol is resolved in
    183 	 * _thr_rtld_init() with side-effect free call.
    184 	 */
    185 	ret = syscall(SYS_fork);
    186 	if (ret == 0) {
    187 		/* Child process */
    188 		errsave = errno;
    189 		curthread->cancel_pending = 0;
    190 		curthread->flags &= ~(THR_FLAGS_NEED_SUSPEND|THR_FLAGS_DETACHED);
    191 
    192 		/*
    193 		 * Thread list will be reinitialized, and later we call
    194 		 * _libpthread_init(), it will add us back to list.
    195 		 */
    196 		curthread->tlflags &= ~TLFLAGS_IN_TDLIST;
    197 
    198 		/* child is a new kernel thread. */
    199 		thr_self(&curthread->tid);
    200 
    201 		/* clear other threads locked us. */
    202 		_thr_umutex_init(&curthread->lock);
    203 		_mutex_fork(curthread);
    204 
    205 		_thr_signal_postfork_child();
    206 
    207 		if (was_threaded) {
    208 			_rtld_atfork_post(rtld_locks);
    209 			__thr_pshared_atfork_post();
    210 		}
    211 		_thr_setthreaded(0);
    212 
    213 		/* reinitalize library. */
    214 		_libpthread_init(curthread);
    215 
    216 		/* atfork is reinitialized by _libpthread_init()! */
    217 		_thr_rwl_rdlock(&_thr_atfork_lock);
    218 
    219 		if (was_threaded) {
    220 			__isthreaded = 1;
    221 			_malloc_postfork();
    222 			__isthreaded = 0;
    223 		}
    224 
    225 		/* Ready to continue, unblock signals. */
    226 		_thr_signal_unblock(curthread);
    227 
    228 		/* Run down atfork child handlers. */
    229 		TAILQ_FOREACH(af, &_thr_atfork_list, qe) {
    230 			if (af->child != NULL)
    231 				af->child();
    232 		}
    233 		_thr_rwlock_unlock(&_thr_atfork_lock);
    234 		curthread->no_cancel = cancelsave;
    235 	} else {
    236 		/* Parent process */
    237 		errsave = errno;
    238 
    239 		_thr_signal_postfork();
    240 
    241 		if (was_threaded) {
    242 			_rtld_atfork_post(rtld_locks);
    243 			__thr_pshared_atfork_post();
    244 			_malloc_postfork();
    245 		}
    246 
    247 		/* Ready to continue, unblock signals. */
    248 		_thr_signal_unblock(curthread);
    249 
    250 		/* Run down atfork parent handlers. */
    251 		TAILQ_FOREACH(af, &_thr_atfork_list, qe) {
    252 			if (af->parent != NULL)
    253 				af->parent();
    254 		}
    255 
    256 		_thr_rwlock_unlock(&_thr_atfork_lock);
    257 		curthread->no_cancel = cancelsave;
    258 		/* test async cancel */
    259 		if (curthread->cancel_async)
    260 			_thr_testcancel(curthread);
    261 	}
    262 	errno = errsave;
    263 
    264 	return (ret);
    265 }
    266