From 8d107d12102747d3d8691aea11c17e37f43fb70d Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Tue, 27 Jun 2000 21:30:16 +0000 Subject: 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 --- lib/libpthread/thread/thr_sigwait.c | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) (limited to 'lib/libpthread/thread/thr_sigwait.c') diff --git a/lib/libpthread/thread/thr_sigwait.c b/lib/libpthread/thread/thr_sigwait.c index a50968768082..b12c028740c9 100644 --- a/lib/libpthread/thread/thr_sigwait.c +++ b/lib/libpthread/thread/thr_sigwait.c @@ -94,6 +94,12 @@ sigwait(const sigset_t * set, int *sig) return (0); } + /* + * 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 @@ -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(); -- cgit v1.2.3