diff options
author | mtm <mtm@FreeBSD.org> | 2004-06-27 10:01:35 +0000 |
---|---|---|
committer | mtm <mtm@FreeBSD.org> | 2004-06-27 10:01:35 +0000 |
commit | 32356d604915fd82194fe6d674571b7db002f1b7 (patch) | |
tree | 7f18580f62576acd89a952ab6952543489b92ea1 /lib/libthr | |
parent | 7598f9b9ec4cee0a912b90d99abf745006764240 (diff) | |
download | FreeBSD-src-32356d604915fd82194fe6d674571b7db002f1b7.zip FreeBSD-src-32356d604915fd82194fe6d674571b7db002f1b7.tar.gz |
Implement pthread_atfork in libthr. This is mostly from deichen's
work in libpthread.
Submitted by: Dan Nelson <dnelson@allantgroup.com>
Diffstat (limited to 'lib/libthr')
-rw-r--r-- | lib/libthr/thread/Makefile.inc | 1 | ||||
-rw-r--r-- | lib/libthr/thread/thr_atfork.c | 60 | ||||
-rw-r--r-- | lib/libthr/thread/thr_init.c | 4 | ||||
-rw-r--r-- | lib/libthr/thread/thr_private.h | 10 | ||||
-rw-r--r-- | lib/libthr/thread/thr_syscalls.c | 58 |
5 files changed, 133 insertions, 0 deletions
diff --git a/lib/libthr/thread/Makefile.inc b/lib/libthr/thread/Makefile.inc index 36b6b60..395cefc 100644 --- a/lib/libthr/thread/Makefile.inc +++ b/lib/libthr/thread/Makefile.inc @@ -4,6 +4,7 @@ .PATH: ${.CURDIR}/thread SRCS+= \ + thr_atfork.c \ thr_attr.c \ thr_autoinit.c \ thr_barrier.c \ diff --git a/lib/libthr/thread/thr_atfork.c b/lib/libthr/thread/thr_atfork.c new file mode 100644 index 0000000..214424a --- /dev/null +++ b/lib/libthr/thread/thr_atfork.c @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2003 Daniel Eischen <deischen@freebsd.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <errno.h> +#include <stdlib.h> +#include <pthread.h> +#include <sys/queue.h> + +#include "thr_private.h" + +__weak_reference(_pthread_atfork, pthread_atfork); + +int +_pthread_atfork(void (*prepare)(void), void (*parent)(void), + void (*child)(void)) +{ + struct pthread_atfork *af; + + if (_thread_initial == NULL) + _thread_init(); + + if ((af = malloc(sizeof(struct pthread_atfork))) == NULL) + return (ENOMEM); + + af->prepare = prepare; + af->parent = parent; + af->child = child; + _pthread_mutex_lock(&_atfork_mutex); + TAILQ_INSERT_TAIL(&_atfork_list, af, qe); + _pthread_mutex_unlock(&_atfork_mutex); + return (0); +} + diff --git a/lib/libthr/thread/thr_init.c b/lib/libthr/thread/thr_init.c index cf1eb6b..548474d 100644 --- a/lib/libthr/thread/thr_init.c +++ b/lib/libthr/thread/thr_init.c @@ -334,6 +334,10 @@ _thread_init(void) getcontext(&pthread->ctx); pthread->ctx.uc_stack.ss_sp = pthread->stack; pthread->ctx.uc_stack.ss_size = PTHREAD_STACK_INITIAL; + + /* Initialize the atfork list and mutex */ + TAILQ_INIT(&_atfork_list); + _pthread_mutex_init(&_atfork_mutex, NULL); } /* diff --git a/lib/libthr/thread/thr_private.h b/lib/libthr/thread/thr_private.h index 9263a8b..4e78de2 100644 --- a/lib/libthr/thread/thr_private.h +++ b/lib/libthr/thread/thr_private.h @@ -269,6 +269,13 @@ struct pthread_cleanup { void *routine_arg; }; +struct pthread_atfork { + TAILQ_ENTRY(pthread_atfork) qe; + void (*prepare)(void); + void (*parent)(void); + void (*child)(void); +}; + struct pthread_attr { int sched_policy; int sched_inherit; @@ -691,6 +698,9 @@ SCLASS struct pthread *_thread_initial ; #endif +SCLASS TAILQ_HEAD(atfork_head, pthread_atfork) _atfork_list; +SCLASS pthread_mutex_t _atfork_mutex; + /* Default thread attributes: */ SCLASS struct pthread_attr pthread_attr_default #ifdef GLOBAL_PTHREAD_PRIVATE diff --git a/lib/libthr/thread/thr_syscalls.c b/lib/libthr/thread/thr_syscalls.c index f0867d1..b899cbf 100644 --- a/lib/libthr/thread/thr_syscalls.c +++ b/lib/libthr/thread/thr_syscalls.c @@ -90,6 +90,8 @@ #include "thr_private.h" +extern spinlock_t *__malloc_lock; + extern int __creat(const char *, mode_t); extern int __sleep(unsigned int); extern int __sys_nanosleep(const struct timespec *, struct timespec *); @@ -174,6 +176,62 @@ _fcntl(int fd, int cmd,...) return ret; } +__weak_reference(_fork, fork); + +int +_fork(int fd) +{ + int ret; + struct pthread_atfork *af; + + _pthread_mutex_lock(&_atfork_mutex); + + /* Run down atfork prepare handlers. */ + TAILQ_FOREACH_REVERSE(af, &_atfork_list, atfork_head, qe) { + if (af->prepare != NULL) + af->prepare(); + } + + /* + * Fork a new process. + * XXX - The correct way to handle __malloc_lock is to have + * the threads libraries (or libc) install fork handlers for it + * in their initialization routine. We should probably + * do that for all the locks in libc. + */ + if (__isthreaded && __malloc_lock != NULL) + _SPINLOCK(__malloc_lock); + ret = __sys_fork(); + if (ret == 0) { + __isthreaded = 0; + if (__malloc_lock != NULL) + memset(__malloc_lock, 0, sizeof(spinlock_t)); + init_tdlist(curthread, 1); + init_td_common(curthread, NULL, 1); + _mutex_reinit(&_atfork_mutex); + + /* Run down atfork child handlers. */ + TAILQ_FOREACH(af, &_atfork_list, qe) { + if (af->child != NULL) + af->child(); + } + } else if (ret != -1) { + /* Run down atfork parent handlers. */ + TAILQ_FOREACH(af, &_atfork_list, qe) { + if (af->parent != NULL) + af->parent(); + } + } + + if (ret != 0) { + if (__isthreaded && __malloc_lock != NULL) + _SPINUNLOCK(__malloc_lock); + _pthread_mutex_unlock(&_atfork_mutex); + } + return ret; +} + + __weak_reference(_fsync, fsync); int |