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
This commit is contained in:
Jason Evans 2000-06-27 21:30:16 +00:00
parent 21deafa350
commit 8d107d1210
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=62181
9 changed files with 111 additions and 12 deletions

View File

@ -929,6 +929,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.
*/

View File

@ -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;
}
/*

View File

@ -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();

View File

@ -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;
}
/*

View File

@ -929,6 +929,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.
*/

View File

@ -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();

View File

@ -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;
}
/*

View File

@ -929,6 +929,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.
*/

View File

@ -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();