summaryrefslogtreecommitdiffstats
path: root/lib/libpthread
diff options
context:
space:
mode:
authorjasone <jasone@FreeBSD.org>2000-06-27 21:30:16 +0000
committerjasone <jasone@FreeBSD.org>2000-06-27 21:30:16 +0000
commit685b55093c390c42f0371340e0c057c475c1af39 (patch)
tree0b6d43f7b9fcdca766faa281a3f499dc24828c6a /lib/libpthread
parent26efc47d384874586102325d5751243778fa6cbb (diff)
downloadFreeBSD-src-685b55093c390c42f0371340e0c057c475c1af39.zip
FreeBSD-src-685b55093c390c42f0371340e0c057c475c1af39.tar.gz
If multiple threads are blocked in sigwait() for the same signal that does
not have a user-supplied signal handler, when a signal is delivered, one thread will receive the signal, and then the code reverts to having no signal handler for the signal. This can leave the other sigwait()ing threads stranded permanently if the signal is later ignored, or can result in process termination when the process should have delivered the signal to one of the threads in sigwait(). To fix this problem, maintain a count of sigwait()ers for each signal that has no default signal handler. Use the count to correctly install/uninstall dummy signal handlers. Reviewed by: deischen
Diffstat (limited to 'lib/libpthread')
-rw-r--r--lib/libpthread/thread/thr_init.c3
-rw-r--r--lib/libpthread/thread/thr_private.h7
-rw-r--r--lib/libpthread/thread/thr_sigwait.c31
3 files changed, 37 insertions, 4 deletions
diff --git a/lib/libpthread/thread/thr_init.c b/lib/libpthread/thread/thr_init.c
index dd5f53f..8e13f90 100644
--- a/lib/libpthread/thread/thr_init.c
+++ b/lib/libpthread/thread/thr_init.c
@@ -277,6 +277,9 @@ _thread_init(void)
*/
PANIC("Cannot read signal handler info");
}
+
+ /* Initialize the SIG_DFL dummy handler count. */
+ _thread_dfl_count[i] = 0;
}
/*
diff --git a/lib/libpthread/thread/thr_private.h b/lib/libpthread/thread/thr_private.h
index 6b48f23..1ecda3c 100644
--- a/lib/libpthread/thread/thr_private.h
+++ b/lib/libpthread/thread/thr_private.h
@@ -930,6 +930,13 @@ SCLASS pthread_cond_t _gc_cond
SCLASS struct sigaction _thread_sigact[NSIG];
/*
+ * Array of counts of dummy handlers for SIG_DFL signals. This is used to
+ * assure that there is always a dummy signal handler installed while there is a
+ * thread sigwait()ing on the corresponding signal.
+ */
+SCLASS int _thread_dfl_count[NSIG];
+
+/*
* Pending signals for this process.
*/
SCLASS sigset_t _process_sigpending;
diff --git a/lib/libpthread/thread/thr_sigwait.c b/lib/libpthread/thread/thr_sigwait.c
index a509687..b12c028 100644
--- a/lib/libpthread/thread/thr_sigwait.c
+++ b/lib/libpthread/thread/thr_sigwait.c
@@ -95,6 +95,12 @@ sigwait(const sigset_t * set, int *sig)
}
/*
+ * Access the _thread_dfl_count array under the protection of signal
+ * deferral.
+ */
+ _thread_kern_sig_defer();
+
+ /*
* Enter a loop to find the signals that are SIG_DFL. For
* these signals we must install a dummy signal handler in
* order for the kernel to pass them in to us. POSIX says
@@ -107,10 +113,16 @@ sigwait(const sigset_t * set, int *sig)
for (i = 1; i < NSIG; i++) {
if (sigismember(&waitset, i) &&
(_thread_sigact[i - 1].sa_handler == SIG_DFL)) {
- if (_thread_sys_sigaction(i,&act,NULL) != 0)
- ret = -1;
+ _thread_dfl_count[i]++;
+ if (_thread_dfl_count[i] == 1) {
+ if (_thread_sys_sigaction(i,&act,NULL) != 0)
+ ret = -1;
+ }
}
}
+ /* Done accessing _thread_dfl_count for now. */
+ _thread_kern_sig_undefer();
+
if (ret == 0) {
/*
* Save the wait signal mask. The wait signal
@@ -132,15 +144,26 @@ sigwait(const sigset_t * set, int *sig)
_thread_run->data.sigwait = NULL;
}
+ /*
+ * Access the _thread_dfl_count array under the protection of signal
+ * deferral.
+ */
+ _thread_kern_sig_defer();
+
/* Restore the sigactions: */
act.sa_handler = SIG_DFL;
for (i = 1; i < NSIG; i++) {
if (sigismember(&waitset, i) &&
(_thread_sigact[i - 1].sa_handler == SIG_DFL)) {
- if (_thread_sys_sigaction(i,&act,NULL) != 0)
- ret = -1;
+ _thread_dfl_count[i]--;
+ if (_thread_dfl_count == 0) {
+ if (_thread_sys_sigaction(i,&act,NULL) != 0)
+ ret = -1;
+ }
}
}
+ /* Done accessing _thread_dfl_count. */
+ _thread_kern_sig_undefer();
_thread_leave_cancellation_point();
OpenPOWER on IntegriCloud