summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJulian Elischer <julian@FreeBSD.org>2008-02-04 20:03:36 +0000
committerJulian Elischer <julian@FreeBSD.org>2008-02-04 20:03:36 +0000
commite1a6d0886bb0899dcbc1e070710082a3b1fc53bc (patch)
tree7e50f9ee4b1d07cbe28f3846540a99950f1e421b
parent93d9a654b31355fc2cd1be0886cce561b93e5f8b (diff)
Notes
-rw-r--r--lib/libkse/sys/lock.c25
-rw-r--r--lib/libkse/thread/thr_kern.c25
2 files changed, 42 insertions, 8 deletions
diff --git a/lib/libkse/sys/lock.c b/lib/libkse/sys/lock.c
index 2ac8c0c09370..a4a28aff7509 100644
--- a/lib/libkse/sys/lock.c
+++ b/lib/libkse/sys/lock.c
@@ -117,14 +117,23 @@ _lockuser_reinit(struct lockuser *lu, void *priv)
{
if (lu == NULL)
return (-1);
- /*
- * All lockusers keep their watch request and drop their
- * own (lu_myreq) request. Their own request is either
- * some other lockuser's watch request or is the head of
- * the lock.
- */
- lu->lu_myreq = lu->lu_watchreq;
- if (lu->lu_myreq == NULL)
+
+ if (lu->lu_watchreq != NULL) {
+ /*
+ * In this case the lock is active. All lockusers
+ * keep their watch request and drop their own
+ * (lu_myreq) request. Their own request is either
+ * some other lockuser's watch request or is the
+ * head of the lock.
+ */
+ lu->lu_myreq = lu->lu_watchreq;
+ lu->lu_watchreq = NULL;
+ }
+ if (lu->lu_myreq == NULL)
+ /*
+ * Oops, something isn't quite right. Try to
+ * allocate one.
+ */
return (_lockuser_init(lu, priv));
else {
lu->lu_myreq->lr_locked = 1;
diff --git a/lib/libkse/thread/thr_kern.c b/lib/libkse/thread/thr_kern.c
index b362fe9fd42c..d6ecb7b1468f 100644
--- a/lib/libkse/thread/thr_kern.c
+++ b/lib/libkse/thread/thr_kern.c
@@ -342,6 +342,17 @@ _kse_single_thread(struct pthread *curthread)
_LCK_SET_PRIVATE2(&curthread->kse->k_lockusers[i], NULL);
}
curthread->kse->k_locklevel = 0;
+
+ /*
+ * Reinitialize the thread and signal locks so that
+ * sigaction() will work after a fork().
+ */
+ _lock_reinit(&curthread->lock, LCK_ADAPTIVE, _thr_lock_wait,
+ _thr_lock_wakeup);
+ _lock_reinit(&_thread_signal_lock, LCK_ADAPTIVE, _kse_lock_wait,
+ _kse_lock_wakeup);
+
+
_thr_spinlock_init();
if (__isthreaded) {
_thr_rtld_fini();
@@ -351,6 +362,20 @@ _kse_single_thread(struct pthread *curthread)
curthread->kse->k_kcb->kcb_kmbx.km_curthread = NULL;
curthread->attr.flags |= PTHREAD_SCOPE_SYSTEM;
+ /*
+ * After a fork, it is possible that an upcall occurs in
+ * the parent KSE that fork()'d before the child process
+ * is fully created and before its vm space is copied.
+ * During the upcall, the tcb is set to null or to another
+ * thread, and this is what gets copied in the child process
+ * when the vm space is cloned sometime after the upcall
+ * occurs. Note that we shouldn't have to set the kcb, but
+ * we do it for completeness.
+ */
+ _kcb_set(curthread->kse->k_kcb);
+ _tcb_set(curthread->kse->k_kcb, curthread->tcb);
+
+
/* After a fork(), there child should have no pending signals. */
sigemptyset(&curthread->sigpend);