Fix for sigwait problem.
Submitted by: Daniel M. Eischen <eischen@vigrid.com> PR: misc/7039
This commit is contained in:
parent
5520d4646e
commit
42f37683ee
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user