summaryrefslogtreecommitdiffstats
path: root/lib/libpthread/thread/thr_sigwait.c
diff options
context:
space:
mode:
authordavidxu <davidxu@FreeBSD.org>2003-06-28 09:55:02 +0000
committerdavidxu <davidxu@FreeBSD.org>2003-06-28 09:55:02 +0000
commit7b25bda5637f6013ca7067e4482a40b0a4c73bc6 (patch)
tree081cc14974dcb04e9a4a9f829846792004190d57 /lib/libpthread/thread/thr_sigwait.c
parentedb09b0c7fe5cfb64cf9fbdff972073411292488 (diff)
downloadFreeBSD-src-7b25bda5637f6013ca7067e4482a40b0a4c73bc6.zip
FreeBSD-src-7b25bda5637f6013ca7067e4482a40b0a4c73bc6.tar.gz
o Use a daemon thread to monitor signal events in kernel, if pending
signals were changed in kernel, it will retrieve the pending set and try to find a thread to dispatch the signal. The dispatching process can be rolled back if the signal is no longer in kernel. o Create two functions _thr_signal_init() and _thr_signal_deinit(), all signal action settings are retrieved from kernel when threading mode is turned on, after a fork(), child process will reset them to user settings by calling _thr_signal_deinit(). when threading mode is not turned on, all signal operations are direct past to kernel. o When a thread generated a synchoronous signals and its context returned from completed list, UTS will retrieve the signal from its mailbox and try to deliver the signal to thread. o Context signal mask is now only used when delivering signals, thread's current signal mask is always the one in pthread structure. o Remove have_signals field in pthread structure, replace it with psf_valid in pthread_signal_frame. when psf_valid is true, in context switch time, thread will backout itself from some mutex/condition internal queues, then begin to process signals. when a thread is not at blocked state and running, check_pending indicates there are signals for the thread, after preempted and then resumed time, UTS will try to deliver signals to the thread. o At signal delivering time, not only pending signals in thread will be scanned, process's pending signals will be scanned too. o Change sigwait code a bit, remove field sigwait in pthread_wait_data, replace it with oldsigmask in pthread structure, when a thread calls sigwait(), its current signal mask is backuped to oldsigmask, and waitset is copied to its signal mask and when the thread gets a signal in the waitset range, its current signal mask is restored from oldsigmask, these are done in atomic fashion. o Two additional POSIX APIs are implemented, sigwaitinfo() and sigtimedwait(). o Signal code locking is better than previous, there is fewer race conditions. o Temporary disable most of code in _kse_single_thread as it is not safe after fork().
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