Fix for sigwait problem.

Submitted by: Daniel M. Eischen <eischen@vigrid.com>
PR:           misc/7039
This commit is contained in:
John Birrell 1998-08-25 11:19:14 +00:00
parent 5520d4646e
commit 42f37683ee
9 changed files with 297 additions and 51 deletions

View File

@ -47,9 +47,18 @@ pthread_kill(pthread_t pthread, int sig)
ret = EINVAL;
/* Find the thread in the list of active threads: */
else if ((ret = _find_thread(pthread)) == 0)
/* Increment the pending signal count: */
sigaddset(&pthread->sigpend,sig);
else if ((ret = _find_thread(pthread)) == 0) {
if ((pthread->state == PS_SIGWAIT) &&
sigismember(&pthread->sigmask, sig)) {
/* Change the state of the thread to run: */
PTHREAD_NEW_STATE(pthread,PS_RUNNING);
/* Return the signal number: */
pthread->signo = sig;
} else
/* Increment the pending signal count: */
sigaddset(&pthread->sigpend,sig);
}
/* Return the completion status: */
return (ret);

View File

@ -212,6 +212,31 @@ _thread_sig_handler(int sig, int code, struct sigcontext * scp)
sigdelset(&pthread->sigpend,SIGCONT);
}
/*
* Enter a loop to process each thread in the linked
* list that is sigwait-ing on a signal. Since POSIX
* doesn't specify which thread will get the signal
* if there are multiple waiters, we'll give it to the
* first one we find.
*/
for (pthread = _thread_link_list; pthread != NULL;
pthread = pthread->nxt) {
if ((pthread->state == PS_SIGWAIT) &&
sigismember(&pthread->sigmask, sig)) {
/* Change the state of the thread to run: */
PTHREAD_NEW_STATE(pthread,PS_RUNNING);
/* Return the signal number: */
pthread->signo = sig;
/*
* Do not attempt to deliver this signal
* to other threads.
*/
return;
}
}
/* Check if the signal is not being ignored: */
if (_thread_sigact[sig - 1].sa_handler != SIG_IGN)
/*
@ -259,6 +284,7 @@ _thread_signal(pthread_t pthread, int sig)
case PS_RUNNING:
case PS_STATE_MAX:
case PS_SIGTHREAD:
case PS_SIGWAIT:
case PS_SUSPENDED:
/* Nothing to do here. */
break;
@ -290,7 +316,6 @@ _thread_signal(pthread_t pthread, int sig)
case PS_FDR_WAIT:
case PS_FDW_WAIT:
case PS_SLEEP_WAIT:
case PS_SIGWAIT:
case PS_SELECT_WAIT:
if (sig != SIGCHLD ||
_thread_sigact[sig - 1].sa_handler != SIG_DFL) {

View File

@ -39,24 +39,72 @@
int
sigwait(const sigset_t * set, int *sig)
{
int ret;
int status;
sigset_t oset;
int ret = 0;
int i;
sigset_t oset;
struct sigaction act;
/*
* Specify the thread kernel signal handler.
*/
act.sa_handler = (void (*) ()) _thread_sig_handler;
act.sa_flags = SA_RESTART;
act.sa_mask = *set;
/* Save the current sigmal mask: */
oset = _thread_run->sigmask;
/*
* These signals can't be waited on.
*/
sigdelset(&act.sa_mask, SIGKILL);
sigdelset(&act.sa_mask, SIGSTOP);
sigdelset(&act.sa_mask, SIGVTALRM);
sigdelset(&act.sa_mask, SIGCHLD);
sigdelset(&act.sa_mask, SIGINFO);
/* Combine the caller's mask with the current one: */
_thread_run->sigmask |= *set;
/*
* 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
* that the application must explicitly install a dummy
* handler for signals that are SIG_IGN in order to sigwait
* on them, so we ignore SIG_IGN signals.
*/
for (i = 1; i < NSIG; i++) {
if (sigismember(&act.sa_mask, i)) {
if (_thread_sigact[i - 1].sa_handler == SIG_DFL) {
if (_thread_sys_sigaction(i,&act,NULL) != 0)
ret = -1;
}
else if (_thread_sigact[i - 1].sa_handler == SIG_IGN)
sigdelset(&act.sa_mask, i);
}
}
if (ret == 0) {
/* Wait for a signal: */
_thread_kern_sched_state(PS_SIGWAIT, __FILE__, __LINE__);
/* Save the current signal mask: */
oset = _thread_run->sigmask;
/* Return the signal number to the caller: */
*sig = _thread_run->signo;
/* Combine the caller's mask with the current one: */
_thread_run->sigmask |= act.sa_mask;
/* Restore the signal mask: */
_thread_run->sigmask = oset;
/* Wait for a signal: */
_thread_kern_sched_state(PS_SIGWAIT, __FILE__, __LINE__);
/* Return the signal number to the caller: */
*sig = _thread_run->signo;
/* Restore the signal mask: */
_thread_run->sigmask = oset;
}
/* Restore the sigactions: */
act.sa_handler = SIG_DFL;
for (i = 1; i < NSIG; i++) {
if (sigismember(&act.sa_mask, i) &&
(_thread_sigact[i - 1].sa_handler == SIG_DFL)) {
if (_thread_sys_sigaction(i,&act,NULL) != 0)
ret = -1;
}
}
/* Return the completion status: */
return (ret);

View File

@ -47,9 +47,18 @@ pthread_kill(pthread_t pthread, int sig)
ret = EINVAL;
/* Find the thread in the list of active threads: */
else if ((ret = _find_thread(pthread)) == 0)
/* Increment the pending signal count: */
sigaddset(&pthread->sigpend,sig);
else if ((ret = _find_thread(pthread)) == 0) {
if ((pthread->state == PS_SIGWAIT) &&
sigismember(&pthread->sigmask, sig)) {
/* Change the state of the thread to run: */
PTHREAD_NEW_STATE(pthread,PS_RUNNING);
/* Return the signal number: */
pthread->signo = sig;
} else
/* Increment the pending signal count: */
sigaddset(&pthread->sigpend,sig);
}
/* Return the completion status: */
return (ret);

View File

@ -212,6 +212,31 @@ _thread_sig_handler(int sig, int code, struct sigcontext * scp)
sigdelset(&pthread->sigpend,SIGCONT);
}
/*
* Enter a loop to process each thread in the linked
* list that is sigwait-ing on a signal. Since POSIX
* doesn't specify which thread will get the signal
* if there are multiple waiters, we'll give it to the
* first one we find.
*/
for (pthread = _thread_link_list; pthread != NULL;
pthread = pthread->nxt) {
if ((pthread->state == PS_SIGWAIT) &&
sigismember(&pthread->sigmask, sig)) {
/* Change the state of the thread to run: */
PTHREAD_NEW_STATE(pthread,PS_RUNNING);
/* Return the signal number: */
pthread->signo = sig;
/*
* Do not attempt to deliver this signal
* to other threads.
*/
return;
}
}
/* Check if the signal is not being ignored: */
if (_thread_sigact[sig - 1].sa_handler != SIG_IGN)
/*
@ -259,6 +284,7 @@ _thread_signal(pthread_t pthread, int sig)
case PS_RUNNING:
case PS_STATE_MAX:
case PS_SIGTHREAD:
case PS_SIGWAIT:
case PS_SUSPENDED:
/* Nothing to do here. */
break;
@ -290,7 +316,6 @@ _thread_signal(pthread_t pthread, int sig)
case PS_FDR_WAIT:
case PS_FDW_WAIT:
case PS_SLEEP_WAIT:
case PS_SIGWAIT:
case PS_SELECT_WAIT:
if (sig != SIGCHLD ||
_thread_sigact[sig - 1].sa_handler != SIG_DFL) {

View File

@ -39,24 +39,72 @@
int
sigwait(const sigset_t * set, int *sig)
{
int ret;
int status;
sigset_t oset;
int ret = 0;
int i;
sigset_t oset;
struct sigaction act;
/*
* Specify the thread kernel signal handler.
*/
act.sa_handler = (void (*) ()) _thread_sig_handler;
act.sa_flags = SA_RESTART;
act.sa_mask = *set;
/* Save the current sigmal mask: */
oset = _thread_run->sigmask;
/*
* These signals can't be waited on.
*/
sigdelset(&act.sa_mask, SIGKILL);
sigdelset(&act.sa_mask, SIGSTOP);
sigdelset(&act.sa_mask, SIGVTALRM);
sigdelset(&act.sa_mask, SIGCHLD);
sigdelset(&act.sa_mask, SIGINFO);
/* Combine the caller's mask with the current one: */
_thread_run->sigmask |= *set;
/*
* 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
* that the application must explicitly install a dummy
* handler for signals that are SIG_IGN in order to sigwait
* on them, so we ignore SIG_IGN signals.
*/
for (i = 1; i < NSIG; i++) {
if (sigismember(&act.sa_mask, i)) {
if (_thread_sigact[i - 1].sa_handler == SIG_DFL) {
if (_thread_sys_sigaction(i,&act,NULL) != 0)
ret = -1;
}
else if (_thread_sigact[i - 1].sa_handler == SIG_IGN)
sigdelset(&act.sa_mask, i);
}
}
if (ret == 0) {
/* Wait for a signal: */
_thread_kern_sched_state(PS_SIGWAIT, __FILE__, __LINE__);
/* Save the current signal mask: */
oset = _thread_run->sigmask;
/* Return the signal number to the caller: */
*sig = _thread_run->signo;
/* Combine the caller's mask with the current one: */
_thread_run->sigmask |= act.sa_mask;
/* Restore the signal mask: */
_thread_run->sigmask = oset;
/* Wait for a signal: */
_thread_kern_sched_state(PS_SIGWAIT, __FILE__, __LINE__);
/* Return the signal number to the caller: */
*sig = _thread_run->signo;
/* Restore the signal mask: */
_thread_run->sigmask = oset;
}
/* Restore the sigactions: */
act.sa_handler = SIG_DFL;
for (i = 1; i < NSIG; i++) {
if (sigismember(&act.sa_mask, i) &&
(_thread_sigact[i - 1].sa_handler == SIG_DFL)) {
if (_thread_sys_sigaction(i,&act,NULL) != 0)
ret = -1;
}
}
/* Return the completion status: */
return (ret);

View File

@ -47,9 +47,18 @@ pthread_kill(pthread_t pthread, int sig)
ret = EINVAL;
/* Find the thread in the list of active threads: */
else if ((ret = _find_thread(pthread)) == 0)
/* Increment the pending signal count: */
sigaddset(&pthread->sigpend,sig);
else if ((ret = _find_thread(pthread)) == 0) {
if ((pthread->state == PS_SIGWAIT) &&
sigismember(&pthread->sigmask, sig)) {
/* Change the state of the thread to run: */
PTHREAD_NEW_STATE(pthread,PS_RUNNING);
/* Return the signal number: */
pthread->signo = sig;
} else
/* Increment the pending signal count: */
sigaddset(&pthread->sigpend,sig);
}
/* Return the completion status: */
return (ret);

View File

@ -212,6 +212,31 @@ _thread_sig_handler(int sig, int code, struct sigcontext * scp)
sigdelset(&pthread->sigpend,SIGCONT);
}
/*
* Enter a loop to process each thread in the linked
* list that is sigwait-ing on a signal. Since POSIX
* doesn't specify which thread will get the signal
* if there are multiple waiters, we'll give it to the
* first one we find.
*/
for (pthread = _thread_link_list; pthread != NULL;
pthread = pthread->nxt) {
if ((pthread->state == PS_SIGWAIT) &&
sigismember(&pthread->sigmask, sig)) {
/* Change the state of the thread to run: */
PTHREAD_NEW_STATE(pthread,PS_RUNNING);
/* Return the signal number: */
pthread->signo = sig;
/*
* Do not attempt to deliver this signal
* to other threads.
*/
return;
}
}
/* Check if the signal is not being ignored: */
if (_thread_sigact[sig - 1].sa_handler != SIG_IGN)
/*
@ -259,6 +284,7 @@ _thread_signal(pthread_t pthread, int sig)
case PS_RUNNING:
case PS_STATE_MAX:
case PS_SIGTHREAD:
case PS_SIGWAIT:
case PS_SUSPENDED:
/* Nothing to do here. */
break;
@ -290,7 +316,6 @@ _thread_signal(pthread_t pthread, int sig)
case PS_FDR_WAIT:
case PS_FDW_WAIT:
case PS_SLEEP_WAIT:
case PS_SIGWAIT:
case PS_SELECT_WAIT:
if (sig != SIGCHLD ||
_thread_sigact[sig - 1].sa_handler != SIG_DFL) {

View File

@ -39,24 +39,72 @@
int
sigwait(const sigset_t * set, int *sig)
{
int ret;
int status;
sigset_t oset;
int ret = 0;
int i;
sigset_t oset;
struct sigaction act;
/*
* Specify the thread kernel signal handler.
*/
act.sa_handler = (void (*) ()) _thread_sig_handler;
act.sa_flags = SA_RESTART;
act.sa_mask = *set;
/* Save the current sigmal mask: */
oset = _thread_run->sigmask;
/*
* These signals can't be waited on.
*/
sigdelset(&act.sa_mask, SIGKILL);
sigdelset(&act.sa_mask, SIGSTOP);
sigdelset(&act.sa_mask, SIGVTALRM);
sigdelset(&act.sa_mask, SIGCHLD);
sigdelset(&act.sa_mask, SIGINFO);
/* Combine the caller's mask with the current one: */
_thread_run->sigmask |= *set;
/*
* 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
* that the application must explicitly install a dummy
* handler for signals that are SIG_IGN in order to sigwait
* on them, so we ignore SIG_IGN signals.
*/
for (i = 1; i < NSIG; i++) {
if (sigismember(&act.sa_mask, i)) {
if (_thread_sigact[i - 1].sa_handler == SIG_DFL) {
if (_thread_sys_sigaction(i,&act,NULL) != 0)
ret = -1;
}
else if (_thread_sigact[i - 1].sa_handler == SIG_IGN)
sigdelset(&act.sa_mask, i);
}
}
if (ret == 0) {
/* Wait for a signal: */
_thread_kern_sched_state(PS_SIGWAIT, __FILE__, __LINE__);
/* Save the current signal mask: */
oset = _thread_run->sigmask;
/* Return the signal number to the caller: */
*sig = _thread_run->signo;
/* Combine the caller's mask with the current one: */
_thread_run->sigmask |= act.sa_mask;
/* Restore the signal mask: */
_thread_run->sigmask = oset;
/* Wait for a signal: */
_thread_kern_sched_state(PS_SIGWAIT, __FILE__, __LINE__);
/* Return the signal number to the caller: */
*sig = _thread_run->signo;
/* Restore the signal mask: */
_thread_run->sigmask = oset;
}
/* Restore the sigactions: */
act.sa_handler = SIG_DFL;
for (i = 1; i < NSIG; i++) {
if (sigismember(&act.sa_mask, i) &&
(_thread_sigact[i - 1].sa_handler == SIG_DFL)) {
if (_thread_sys_sigaction(i,&act,NULL) != 0)
ret = -1;
}
}
/* Return the completion status: */
return (ret);