diff options
| author | Julian Elischer <julian@FreeBSD.org> | 2008-02-04 20:03:36 +0000 |
|---|---|---|
| committer | Julian Elischer <julian@FreeBSD.org> | 2008-02-04 20:03:36 +0000 |
| commit | e1a6d0886bb0899dcbc1e070710082a3b1fc53bc (patch) | |
| tree | 7e50f9ee4b1d07cbe28f3846540a99950f1e421b | |
| parent | 93d9a654b31355fc2cd1be0886cce561b93e5f8b (diff) | |
Notes
| -rw-r--r-- | lib/libkse/sys/lock.c | 25 | ||||
| -rw-r--r-- | lib/libkse/thread/thr_kern.c | 25 |
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); |
