summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/librthread/Makefile4
-rw-r--r--lib/librthread/rthread.c41
-rw-r--r--lib/librthread/rthread.h7
-rw-r--r--lib/librthread/rthread_fork.c177
4 files changed, 208 insertions, 21 deletions
diff --git a/lib/librthread/Makefile b/lib/librthread/Makefile
index 1b325c8b8fb..958236ad04c 100644
--- a/lib/librthread/Makefile
+++ b/lib/librthread/Makefile
@@ -1,4 +1,4 @@
-# $OpenBSD: Makefile,v 1.9 2006/01/05 04:06:48 marc Exp $
+# $OpenBSD: Makefile,v 1.10 2008/06/05 21:06:11 kurt Exp $
LIB=rthread
WANTLINT=
@@ -12,7 +12,7 @@ CFLAGS+=-I${LIBCSRCDIR}/include
.PATH: ${.CURDIR}/arch/${MACHINE_ARCH}
SRCS= rthread.c rthread_attr.c rthread_sched.c rthread_sync.c rthread_tls.c \
rthread_sig.c rthread_np.c rthread_debug.c rthread_stack.c \
- rthread_reaper.c rthread_libc.c
+ rthread_reaper.c rthread_libc.c rthread_fork.c
OBJS+= _atomic_lock.o rfork_thread.o
diff --git a/lib/librthread/rthread.c b/lib/librthread/rthread.c
index 48e7da7691c..5e8a88de030 100644
--- a/lib/librthread/rthread.c
+++ b/lib/librthread/rthread.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rthread.c,v 1.34 2007/05/18 14:36:17 art Exp $ */
+/* $OpenBSD: rthread.c,v 1.35 2008/06/05 21:06:11 kurt Exp $ */
/*
* Copyright (c) 2004,2005 Ted Unangst <tedu@openbsd.org>
* All Rights Reserved.
@@ -27,6 +27,7 @@
#include <machine/spinlock.h>
+#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
@@ -50,11 +51,6 @@ struct pthread _initial_thread;
int rfork_thread(int, void *, void (*)(void *), void *);
-#if defined(__ELF__) && defined(PIC)
-static void rthread_dl_lock(int what);
-static void rthread_bind_lock(int what);
-#endif
-
/*
* internal support functions
*/
@@ -100,6 +96,16 @@ _rthread_start(void *v)
pthread_exit(retval);
}
+int
+_rthread_open_kqueue(void)
+{
+ _rthread_kq = kqueue();
+ if (_rthread_kq == -1)
+ return 1;
+ fcntl(_rthread_kq, F_SETFD, FD_CLOEXEC);
+ return 0;
+}
+
static int
_rthread_init(void)
{
@@ -112,8 +118,7 @@ _rthread_init(void)
thread->flags_lock = _SPINLOCK_UNLOCKED;
strlcpy(thread->name, "Main process", sizeof(thread->name));
LIST_INSERT_HEAD(&_thread_list, thread, threads);
- _rthread_kq = kqueue();
- if (_rthread_kq == -1)
+ if (_rthread_open_kqueue())
return (errno);
_rthread_debug_init();
_rthread_debug(1, "rthread init\n");
@@ -126,12 +131,12 @@ _rthread_init(void)
* functions once to fully bind them before registering them
* for use.
*/
- rthread_dl_lock(0);
- rthread_dl_lock(1);
- rthread_bind_lock(0);
- rthread_bind_lock(1);
- dlctl(NULL, DL_SETTHREADLCK, rthread_dl_lock);
- dlctl(NULL, DL_SETBINDLCK, rthread_bind_lock);
+ _rthread_dl_lock(0);
+ _rthread_dl_lock(1);
+ _rthread_bind_lock(0);
+ _rthread_bind_lock(1);
+ dlctl(NULL, DL_SETTHREADLCK, _rthread_dl_lock);
+ dlctl(NULL, DL_SETBINDLCK, _rthread_bind_lock);
#endif
return (0);
@@ -470,8 +475,8 @@ _thread_dump_info(void)
}
#if defined(__ELF__) && defined(PIC)
-static void
-rthread_dl_lock(int what)
+void
+_rthread_dl_lock(int what)
{
static _spinlock_lock_t lock = _SPINLOCK_UNLOCKED;
@@ -481,8 +486,8 @@ rthread_dl_lock(int what)
_spinunlock(&lock);
}
-static void
-rthread_bind_lock(int what)
+void
+_rthread_bind_lock(int what)
{
static _spinlock_lock_t lock = _SPINLOCK_UNLOCKED;
diff --git a/lib/librthread/rthread.h b/lib/librthread/rthread.h
index 918a00d9e1c..1281b0dcece 100644
--- a/lib/librthread/rthread.h
+++ b/lib/librthread/rthread.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: rthread.h,v 1.17 2006/01/05 04:06:48 marc Exp $ */
+/* $OpenBSD: rthread.h,v 1.18 2008/06/05 21:06:11 kurt Exp $ */
/*
* Copyright (c) 2004,2005 Ted Unangst <tedu@openbsd.org>
* All Rights Reserved.
@@ -150,6 +150,11 @@ void _rthread_debug(int, const char *, ...)
void _rthread_debug_init(void);
void _rthread_add_to_reaper(pid_t, struct stack *);
void _rthread_reaper(void);
+int _rthread_open_kqueue(void);
+#if defined(__ELF__) && defined(PIC)
+void _rthread_dl_lock(int what);
+void _rthread_bind_lock(int);
+#endif
void _thread_dump_info(void);
diff --git a/lib/librthread/rthread_fork.c b/lib/librthread/rthread_fork.c
new file mode 100644
index 00000000000..530d9ad5b6e
--- /dev/null
+++ b/lib/librthread/rthread_fork.c
@@ -0,0 +1,177 @@
+/* $OpenBSD: rthread_fork.c,v 1.1 2008/06/05 21:06:11 kurt Exp $ */
+
+/*
+ * Copyright (c) 2008 Kurt Miller <kurt@openbsd.org>
+ * Copyright (c) 2008 Philip Guenther <guenther@gmail.com>
+ * 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.
+ *
+ * $FreeBSD: /repoman/r/ncvs/src/lib/libc_r/uthread/uthread_atfork.c,v 1.1 2004/12/10 03:36:45 grog Exp $
+ */
+
+#include <sys/param.h>
+
+#include <machine/spinlock.h>
+
+#include <errno.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "thread_private.h" /* in libc/include */
+
+#include "rthread.h"
+
+struct rthread_atfork {
+ TAILQ_ENTRY(rthread_atfork) next;
+ void (*prepare)(void);
+ void (*parent)(void);
+ void (*child)(void);
+};
+
+static TAILQ_HEAD(atfork_listhead, rthread_atfork) _atfork_list =
+ TAILQ_HEAD_INITIALIZER(_atfork_list);
+
+static _spinlock_lock_t _atfork_lock = _SPINLOCK_UNLOCKED;
+
+pid_t _thread_sys_fork(void);
+pid_t _thread_sys_vfork(void);
+pid_t _dofork(int);
+
+pid_t
+_dofork(int is_vfork)
+{
+ pthread_t me;
+ pid_t (*sys_fork)(void);
+ pid_t newid;
+
+ sys_fork = is_vfork ? &_thread_sys_vfork : &_thread_sys_fork;
+
+ if (!_threads_ready)
+ return sys_fork();
+
+ me = pthread_self();
+
+ /*
+ * Protect important libc/ld.so critical areas across the fork call.
+ * dlclose() will grab the atexit lock via __cxa_finalize() so lock
+ * the dl_lock first. malloc()/free() can grab the arc4 lock so lock
+ * malloc_lock first. Finally lock the bind_lock last so that any lazy
+ * binding in the other locking functions can succeed.
+ */
+
+#if defined(__ELF__) && defined(PIC)
+ _rthread_dl_lock(0);
+#endif
+
+ _thread_atexit_lock();
+ _thread_malloc_lock();
+ _thread_arc4_lock();
+
+#if defined(__ELF__) && defined(PIC)
+ _rthread_bind_lock(0);
+#endif
+
+ newid = sys_fork();
+
+#if defined(__ELF__) && defined(PIC)
+ _rthread_bind_lock(1);
+#endif
+
+ _thread_arc4_unlock();
+ _thread_malloc_unlock();
+ _thread_atexit_unlock();
+
+#if defined(__ELF__) && defined(PIC)
+ _rthread_dl_lock(1);
+#endif
+
+ if (newid == 0) {
+ if (_rthread_open_kqueue())
+ _exit(126); /* XXX */
+
+ /* update this thread's structure */
+ me->tid = getthrid();
+ me->donesem.lock = _SPINLOCK_UNLOCKED;
+ me->flags &= ~THREAD_DETACHED;
+ me->flags_lock = _SPINLOCK_UNLOCKED;
+
+ /* this thread is the initial thread for the new process */
+ _initial_thread = *me;
+
+ /* reinit the thread list */
+ LIST_INIT(&_thread_list);
+ LIST_INSERT_HEAD(&_thread_list, &_initial_thread, threads);
+ _thread_lock = _SPINLOCK_UNLOCKED;
+ }
+ return newid;
+}
+
+pid_t
+fork(void)
+{
+ struct rthread_atfork *p;
+ pid_t newid;
+
+ _spinlock(&_atfork_lock);
+ TAILQ_FOREACH_REVERSE(p, &_atfork_list, atfork_listhead, next)
+ if (p->prepare)
+ p->prepare();
+ newid = _dofork(0);
+ if (newid == 0) {
+ TAILQ_FOREACH(p, &_atfork_list, next)
+ if (p->child)
+ p->child();
+ } else {
+ TAILQ_FOREACH(p, &_atfork_list, next)
+ if (p->parent)
+ p->parent();
+ }
+ _spinunlock(&_atfork_lock);
+ return newid;
+}
+
+pid_t
+vfork(void)
+{
+ return _dofork(1);
+}
+
+int
+pthread_atfork(void (*prepare)(void), void (*parent)(void),
+ void (*child)(void))
+{
+ struct rthread_atfork *af;
+
+ if ((af = malloc(sizeof *af)) == NULL)
+ return (ENOMEM);
+
+ af->prepare = prepare;
+ af->parent = parent;
+ af->child = child;
+ _spinlock(&_atfork_lock);
+ TAILQ_INSERT_TAIL(&_atfork_list, af, next);
+ _spinunlock(&_atfork_lock);
+ return (0);
+}