summaryrefslogtreecommitdiffstats
path: root/lib/libpthread/thread/thr_sigwait.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libpthread/thread/thr_sigwait.c')
-rw-r--r--lib/libpthread/thread/thr_sigwait.c210
1 files changed, 142 insertions, 68 deletions
diff --git a/lib/libpthread/thread/thr_sigwait.c b/lib/libpthread/thread/thr_sigwait.c
index c8c7762..4b9cb69 100644
--- a/lib/libpthread/thread/thr_sigwait.c
+++ b/lib/libpthread/thread/thr_sigwait.c
@@ -39,10 +39,13 @@
#include <pthread.h>
#include "thr_private.h"
-__weak_reference(_sigwait, sigwait);
+__weak_reference(__sigwait, sigwait);
+__weak_reference(__sigtimedwait, sigtimedwait);
+__weak_reference(__sigwaitinfo, sigwaitinfo);
-int
-_sigwait(const sigset_t *set, int *sig)
+static int
+lib_sigtimedwait(const sigset_t *set, siginfo_t *info,
+ const struct timespec * timeout)
{
struct pthread *curthread = _get_curthread();
int ret = 0;
@@ -50,8 +53,14 @@ _sigwait(const sigset_t *set, int *sig)
sigset_t tempset, waitset;
struct sigaction act;
kse_critical_t crit;
+ siginfo_t siginfo;
- _thr_enter_cancellation_point(curthread);
+ if (!_kse_isthreaded()) {
+ if (info == NULL)
+ info = &siginfo;
+ return __sys_sigtimedwait((sigset_t *)set, info,
+ (struct timespec *)timeout);
+ }
/*
* Specify the thread kernel signal handler.
@@ -59,7 +68,7 @@ _sigwait(const sigset_t *set, int *sig)
act.sa_handler = (void (*) ()) _thr_sig_handler;
act.sa_flags = SA_RESTART | SA_SIGINFO;
/* Ensure the signal handler cannot be interrupted by other signals: */
- sigfillset(&act.sa_mask);
+ SIGFILLSET(act.sa_mask);
/*
* Initialize the set of signals that will be waited on:
@@ -67,41 +76,14 @@ _sigwait(const sigset_t *set, int *sig)
waitset = *set;
/* These signals can't be waited on. */
- sigdelset(&waitset, SIGKILL);
- sigdelset(&waitset, SIGSTOP);
+ SIGDELSET(waitset, SIGKILL);
+ SIGDELSET(waitset, SIGSTOP);
- /*
- * Check to see if a pending signal is in the wait mask.
- * This has to be atomic.
- */
- tempset = curthread->sigpend;
crit = _kse_critical_enter();
KSE_LOCK_ACQUIRE(curthread->kse, &_thread_signal_lock);
- SIGSETOR(tempset, _thr_proc_sigpending);
- SIGSETAND(tempset, waitset);
- if (SIGNOTEMPTY(tempset)) {
- /* Enter a loop to find a pending signal: */
- for (i = 1; i < NSIG; i++) {
- if (sigismember (&tempset, i))
- break;
- }
-
- /* Clear the pending signal: */
- if (sigismember(&curthread->sigpend, i))
- sigdelset(&curthread->sigpend, i);
- else
- sigdelset(&_thr_proc_sigpending, i);
-
- KSE_LOCK_RELEASE(curthread->kse, &_thread_signal_lock);
- _kse_critical_leave(crit);
- _thr_leave_cancellation_point(curthread);
- /* Return the signal number to the caller: */
- *sig = i;
- return (0);
- }
/*
- * Enter a loop to find the signals that are SIG_DFL. For
+ * 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
@@ -110,66 +92,158 @@ _sigwait(const sigset_t *set, int *sig)
* mask because a subsequent sigaction could enable an
* ignored signal.
*/
- sigemptyset(&tempset);
- for (i = 1; i < NSIG; i++) {
- if (sigismember(&waitset, i) &&
+ SIGEMPTYSET(tempset);
+ for (i = 1; i <= _SIG_MAXSIG; i++) {
+ if (SIGISMEMBER(waitset, i) &&
(_thread_sigact[i - 1].sa_handler == SIG_DFL)) {
- _thread_dfl_count[i]++;
- sigaddset(&tempset, i);
- if (_thread_dfl_count[i] == 1) {
+ _thread_dfl_count[i - 1]++;
+ SIGADDSET(tempset, i);
+ if (_thread_dfl_count[i - 1] == 1) {
if (__sys_sigaction(i, &act, NULL) != 0)
- ret = -1;
+ /* ret = -1 */;
}
}
}
- /* Done accessing _thread_dfl_count for now. */
- KSE_LOCK_RELEASE(curthread->kse, &_thread_signal_lock);
- _kse_critical_leave(crit);
- if (ret == 0) {
- /*
- * Save the wait signal mask. The wait signal
- * mask is independent of the threads signal mask
- * and requires separate storage.
- */
- curthread->data.sigwait = &waitset;
+ if (ret == 0) {
+ /* Done accessing _thread_dfl_count for now. */
+ KSE_LOCK_RELEASE(curthread->kse, &_thread_signal_lock);
+ KSE_SCHED_LOCK(curthread->kse, curthread->kseg);
+ for (i = 1; i <= _SIG_MAXSIG; ++i) {
+ if (SIGISMEMBER(waitset, i) &&
+ SIGISMEMBER(curthread->sigpend, i)) {
+ SIGDELSET(curthread->sigpend, i);
+ *info = curthread->siginfo[i];
+ KSE_SCHED_UNLOCK(curthread->kse,
+ curthread->kseg);
+ _kse_critical_leave(crit);
+ return (i);
+ }
+ }
+ curthread->timeout = 0;
+ _thr_set_timeout(timeout);
/* Wait for a signal: */
- THR_LOCK_SWITCH(curthread);
+ curthread->oldsigmask = curthread->sigmask;
+ siginfo.si_signo = 0;
+ curthread->data.sigwaitinfo = &siginfo;
+ SIGFILLSET(curthread->sigmask);
+ SIGSETNAND(curthread->sigmask, waitset);
THR_SET_STATE(curthread, PS_SIGWAIT);
_thr_sched_switch_unlocked(curthread);
- /* Return the signal number to the caller: */
- *sig = curthread->signo;
+ /*
+ * Return the signal number to the caller:
+ * XXX Here is race, how about a signal come in before
+ * we reach here? so we might got an incorrect timeout
+ * status.
+ */
+ if (siginfo.si_signo > 0) {
+ if (info)
+ *info = siginfo;
+ ret = siginfo.si_signo;
+ } else {
+ if (curthread->timeout)
+ errno = EAGAIN;
+ ret = -1;
+ }
/*
* Probably unnecessary, but since it's in a union struct
* we don't know how it could be used in the future.
*/
- curthread->data.sigwait = NULL;
+ crit = _kse_critical_enter();
+ curthread->data.sigwaitinfo = NULL;
+ /*
+ * Relock the array of SIG_DFL wait counts.
+ */
+ KSE_LOCK_ACQUIRE(curthread->kse, &_thread_signal_lock);
}
- /*
- * Relock the array of SIG_DFL wait counts.
- */
- crit = _kse_critical_enter();
- KSE_LOCK_ACQUIRE(curthread->kse, &_thread_signal_lock);
-
/* Restore the sigactions: */
act.sa_handler = SIG_DFL;
- for (i = 1; i < NSIG; i++) {
- if (sigismember(&tempset, i)) {
- _thread_dfl_count[i]--;
+ for (i = 1; i <= _SIG_MAXSIG; i++) {
+ if (SIGISMEMBER(tempset, i)) {
+ _thread_dfl_count[i - 1]--;
if ((_thread_sigact[i - 1].sa_handler == SIG_DFL) &&
- (_thread_dfl_count[i] == 0)) {
+ (_thread_dfl_count[i - 1] == 0)) {
if (__sys_sigaction(i, &act, NULL) != 0)
- ret = -1;
+ /* ret = -1 */ ;
}
}
}
/* Done accessing _thread_dfl_count. */
KSE_LOCK_RELEASE(curthread->kse, &_thread_signal_lock);
_kse_critical_leave(crit);
+
+ return (ret);
+}
+
+int
+__sigtimedwait(const sigset_t *set, siginfo_t *info,
+ const struct timespec * timeout)
+{
+ struct pthread *curthread = _get_curthread();
+ int ret;
+
+ _thr_enter_cancellation_point(curthread);
+ ret = lib_sigtimedwait(set, info, timeout);
+ _thr_leave_cancellation_point(curthread);
+ return (ret);
+}
+
+int _sigtimedwait(const sigset_t *set, siginfo_t *info,
+ const struct timespec * timeout)
+{
+ return lib_sigtimedwait(set, info, timeout);
+}
+
+int
+__sigwaitinfo(const sigset_t *set, siginfo_t *info)
+{
+ struct pthread *curthread = _get_curthread();
+ int ret;
+
+ _thr_enter_cancellation_point(curthread);
+ ret = lib_sigtimedwait(set, info, NULL);
+ _thr_leave_cancellation_point(curthread);
+ return (ret);
+}
+
+int
+_sigwaitinfo(const sigset_t *set, siginfo_t *info)
+{
+ return lib_sigtimedwait(set, info, NULL);
+}
+
+int
+__sigwait(const sigset_t *set, int *sig)
+{
+ struct pthread *curthread = _get_curthread();
+ int ret;
+
+ _thr_enter_cancellation_point(curthread);
+ ret = lib_sigtimedwait(set, NULL, NULL);
+ if (ret > 0) {
+ *sig = ret;
+ ret = 0;
+ }
+ else
+ ret = -1;
_thr_leave_cancellation_point(curthread);
+ return (ret);
+}
- /* Return the completion status: */
+int
+_sigwait(const sigset_t *set, int *sig)
+{
+ int ret;
+
+ ret = lib_sigtimedwait(set, NULL, NULL);
+ if (ret > 0) {
+ *sig = ret;
+ ret = 0;
+ } else {
+ ret = -1;
+ }
return (ret);
}
+
OpenPOWER on IntegriCloud