summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/libkse/support/thr_support.c3
-rw-r--r--lib/libkse/thread/thr_info.c17
-rw-r--r--lib/libkse/thread/thr_init.c43
-rw-r--r--lib/libkse/thread/thr_kern.c234
-rw-r--r--lib/libkse/thread/thr_kill.c2
-rw-r--r--lib/libkse/thread/thr_private.h33
-rw-r--r--lib/libkse/thread/thr_sig.c784
-rw-r--r--lib/libkse/thread/thr_sigaction.c13
-rw-r--r--lib/libkse/thread/thr_sigmask.c25
-rw-r--r--lib/libkse/thread/thr_sigpending.c7
-rw-r--r--lib/libkse/thread/thr_sigprocmask.c5
-rw-r--r--lib/libkse/thread/thr_sigsuspend.c19
-rw-r--r--lib/libkse/thread/thr_sigwait.c210
-rw-r--r--lib/libpthread/pthread.map4
-rw-r--r--lib/libpthread/support/thr_support.c3
-rw-r--r--lib/libpthread/thread/thr_info.c17
-rw-r--r--lib/libpthread/thread/thr_init.c43
-rw-r--r--lib/libpthread/thread/thr_kern.c234
-rw-r--r--lib/libpthread/thread/thr_kill.c2
-rw-r--r--lib/libpthread/thread/thr_private.h33
-rw-r--r--lib/libpthread/thread/thr_sig.c784
-rw-r--r--lib/libpthread/thread/thr_sigaction.c13
-rw-r--r--lib/libpthread/thread/thr_sigmask.c25
-rw-r--r--lib/libpthread/thread/thr_sigpending.c7
-rw-r--r--lib/libpthread/thread/thr_sigprocmask.c5
-rw-r--r--lib/libpthread/thread/thr_sigsuspend.c19
-rw-r--r--lib/libpthread/thread/thr_sigwait.c210
27 files changed, 1622 insertions, 1172 deletions
diff --git a/lib/libkse/support/thr_support.c b/lib/libkse/support/thr_support.c
index 1b3c4ef..ad40fec 100644
--- a/lib/libkse/support/thr_support.c
+++ b/lib/libkse/support/thr_support.c
@@ -54,5 +54,8 @@ __strong_reference(memcpy, _thr_memcpy);
__strong_reference(strcpy, _thr_strcpy);
__strong_reference(strlen, _thr_strlen);
__strong_reference(bzero, _thr_bzero);
+__strong_reference(bcopy, _thr_bcopy);
__strong_reference(__sys_write, _thr__sys_write);
+__strong_reference(__sys_sigtimedwait, _thr__sys_sigtimedwait);
+
diff --git a/lib/libkse/thread/thr_info.c b/lib/libkse/thread/thr_info.c
index 3218b5b..4410ace 100644
--- a/lib/libkse/thread/thr_info.c
+++ b/lib/libkse/thread/thr_info.c
@@ -77,7 +77,7 @@ _thread_dump_info(void)
int fd, i;
for (i = 0; i < 100000; i++) {
- snprintf(tmpfile, sizeof(tmpfile), "/tmp/uthread.dump.%u.%i",
+ snprintf(tmpfile, sizeof(tmpfile), "/tmp/pthread.dump.%u.%i",
getpid(), i);
/* Open the dump file for append and create it if necessary: */
if ((fd = __sys_open(tmpfile, O_RDWR | O_CREAT | O_EXCL,
@@ -166,6 +166,12 @@ dump_thread(int fd, pthread_t pthread, int long_version)
strcpy(s, "This is the initial thread\n");
__sys_write(fd, s, strlen(s));
}
+ /* Check if this is the signal daemon thread: */
+ if (pthread == _thr_sig_daemon) {
+ /* Output a record for the signal thread: */
+ strcpy(s, "This is the signal daemon thread\n");
+ __sys_write(fd, s, strlen(s));
+ }
/* Process according to thread state: */
switch (pthread->state) {
case PS_SIGWAIT:
@@ -173,6 +179,15 @@ dump_thread(int fd, pthread_t pthread, int long_version)
__sys_write(fd, s, strlen(s));
for (i = _SIG_WORDS - 1; i >= 0; i--) {
snprintf(s, sizeof(s), "%08x\n",
+ pthread->oldsigmask.__bits[i]);
+ __sys_write(fd, s, strlen(s));
+ }
+ snprintf(s, sizeof(s), "(lo)\n");
+ __sys_write(fd, s, strlen(s));
+ snprintf(s, sizeof(s), "waitset (hi)");
+ __sys_write(fd, s, strlen(s));
+ for (i = _SIG_WORDS - 1; i >= 0; i--) {
+ snprintf(s, sizeof(s), "%08x\n",
pthread->sigmask.__bits[i]);
__sys_write(fd, s, strlen(s));
}
diff --git a/lib/libkse/thread/thr_init.c b/lib/libkse/thread/thr_init.c
index 227bdf3..202db62 100644
--- a/lib/libkse/thread/thr_init.c
+++ b/lib/libkse/thread/thr_init.c
@@ -39,6 +39,7 @@
#include "namespace.h"
#include <sys/param.h>
#include <sys/types.h>
+#include <sys/signalvar.h>
#include <machine/reg.h>
#include <sys/ioctl.h>
@@ -304,7 +305,7 @@ _libpthread_init(struct pthread *curthread)
_thr_initial->kse->k_curthread = _thr_initial;
_thr_initial->kse->k_flags |= KF_INITIALIZED;
_kse_initial->k_curthread = _thr_initial;
-
+
_thr_rtld_init();
}
@@ -365,14 +366,13 @@ init_main_thread(struct pthread *thread)
thread->name = strdup("initial thread");
/* Initialize the thread for signals: */
- sigemptyset(&thread->sigmask);
+ SIGEMPTYSET(thread->sigmask);
/*
* Set up the thread mailbox. The threads saved context
* is also in the mailbox.
*/
thread->tmbx.tm_udata = thread;
- thread->tmbx.tm_context.uc_sigmask = thread->sigmask;
thread->tmbx.tm_context.uc_stack.ss_size = thread->attr.stacksize_attr;
thread->tmbx.tm_context.uc_stack.ss_sp = thread->attr.stackaddr_attr;
@@ -407,10 +407,8 @@ static void
init_private(void)
{
struct clockinfo clockinfo;
- struct sigaction act;
size_t len;
int mib[2];
- int i;
/*
* Avoid reinitializing some things if they don't need to be,
@@ -448,36 +446,6 @@ init_private(void)
_thr_page_size = getpagesize();
_thr_guard_default = _thr_page_size;
-
- /* Enter a loop to get the existing signal status: */
- for (i = 1; i < NSIG; i++) {
- /* Check for signals which cannot be trapped: */
- if (i == SIGKILL || i == SIGSTOP) {
- }
-
- /* Get the signal handler details: */
- else if (__sys_sigaction(i, NULL,
- &_thread_sigact[i - 1]) != 0) {
- /*
- * Abort this process if signal
- * initialisation fails:
- */
- PANIC("Cannot read signal handler info");
- }
- }
- /*
- * Install the signal handler for SIGINFO. It isn't
- * really needed, but it is nice to have for debugging
- * purposes.
- */
- if (__sys_sigaction(SIGINFO, &act, NULL) != 0) {
- /*
- * Abort this process if signal initialisation fails:
- */
- PANIC("Cannot initialize signal handler");
- }
- _thread_sigact[SIGINFO - 1].sa_flags = SA_SIGINFO | SA_RESTART;
-
init_once = 1; /* Don't do this again. */
} else {
/*
@@ -495,8 +463,6 @@ init_private(void)
TAILQ_INIT(&_thread_list);
TAILQ_INIT(&_thread_gc_list);
- /* Enter a loop to get the existing signal status: */
-
/* Initialize the SIG_DFL dummy handler count. */
bzero(_thread_dfl_count, sizeof(_thread_dfl_count));
@@ -520,8 +486,7 @@ init_private(void)
_thr_spinlock_init();
/* Clear pending signals and get the process signal mask. */
- sigemptyset(&_thr_proc_sigpending);
- __sys_sigprocmask(SIG_SETMASK, NULL, &_thr_proc_sigmask);
+ SIGEMPTYSET(_thr_proc_sigpending);
/*
* _thread_list_lock and _kse_count are initialized
diff --git a/lib/libkse/thread/thr_kern.c b/lib/libkse/thread/thr_kern.c
index d1a2006..8a1ecc3 100644
--- a/lib/libkse/thread/thr_kern.c
+++ b/lib/libkse/thread/thr_kern.c
@@ -40,6 +40,7 @@ __FBSDID("$FreeBSD$");
#include <sys/signalvar.h>
#include <sys/queue.h>
#include <machine/atomic.h>
+#include <machine/sigframe.h>
#include <assert.h>
#include <errno.h>
@@ -125,7 +126,6 @@ static void dump_queues(struct kse *curkse);
#endif
static void kse_check_completed(struct kse *kse);
static void kse_check_waitq(struct kse *kse);
-static void kse_check_signals(struct kse *kse);
static void kse_fini(struct kse *curkse);
static void kse_reinit(struct kse *kse);
static void kse_sched_multi(struct kse *curkse);
@@ -143,27 +143,39 @@ static void kse_wakeup_multi(struct kse *curkse);
static void kse_wakeup_one(struct pthread *thread);
static void thr_cleanup(struct kse *kse, struct pthread *curthread);
static void thr_link(struct pthread *thread);
-static void thr_resume_wrapper(int unused_1, siginfo_t *unused_2,
- ucontext_t *ucp);
+static void thr_resume_wrapper(int sig, siginfo_t *, ucontext_t *);
static void thr_resume_check(struct pthread *curthread, ucontext_t *ucp,
struct pthread_sigframe *psf);
static int thr_timedout(struct pthread *thread, struct timespec *curtime);
static void thr_unlink(struct pthread *thread);
+
/*
* This is called after a fork().
* No locks need to be taken here since we are guaranteed to be
* single threaded.
+ *
+ * XXX
+ * POSIX says for threaded process, fork() function is used
+ * only to run new programs, and the effects of calling functions
+ * that require certain resources between the call to fork() and
+ * the call to an exec function are undefined.
+ *
+ * Here it is not safe to reinitialize the library after fork().
+ * Because memory management may be corrupted, further calling
+ * malloc()/free() may cause undefined behavior.
*/
void
_kse_single_thread(struct pthread *curthread)
{
+#ifdef NOTYET
struct kse *kse;
struct kse_group *kseg;
struct pthread *thread;
kse_critical_t crit;
int i;
+
/*
* Disable upcalls and clear the threaded flag.
* XXX - I don't think we need to disable upcalls after a fork().
@@ -172,6 +184,7 @@ _kse_single_thread(struct pthread *curthread)
crit = _kse_critical_enter();
__isthreaded = 0;
active_threads = 1;
+ _thr_signal_deinit();
/*
* Enter a loop to remove and free all threads other than
@@ -201,7 +214,7 @@ _kse_single_thread(struct pthread *curthread)
TAILQ_INIT(&curthread->mutexq); /* initialize mutex queue */
curthread->joiner = NULL; /* no joining threads yet */
curthread->refcount = 0;
- sigemptyset(&curthread->sigpend); /* clear pending signals */
+ SIGEMPTYSET(curthread->sigpend); /* clear pending signals */
if (curthread->specific != NULL) {
free(curthread->specific);
curthread->specific = NULL;
@@ -307,6 +320,12 @@ _kse_single_thread(struct pthread *curthread)
curthread->kseg = NULL;
_kse_initial = NULL;
_libpthread_init(curthread);
+#else
+ _ksd_readandclear_tmbx();
+ __isthreaded = 0;
+ active_threads = 0;
+ _thr_signal_deinit();
+#endif
}
/*
@@ -363,15 +382,17 @@ _kse_setthreaded(int threaded)
* Tell the kernel to create a KSE for the initial thread
* and enable upcalls in it.
*/
+ _thr_signal_init();
_kse_initial->k_flags |= KF_STARTED;
if (kse_create(&_kse_initial->k_mbx, 0) != 0) {
_kse_initial->k_flags &= ~KF_STARTED;
__isthreaded = 0;
/* may abort() */
- DBG_MSG("kse_create failed\n");
+ PANIC("kse_create() failed\n");
return (-1);
}
KSE_SET_MBOX(_kse_initial, _thr_initial);
+ _thr_start_sig_daemon();
_thr_setmaxconcurrency();
}
return (0);
@@ -536,6 +557,7 @@ _thr_sched_switch_unlocked(struct pthread *curthread)
int ret;
volatile int uts_once;
volatile int resume_once = 0;
+ ucontext_t uc;
/* We're in the scheduler, 5 by 5: */
curkse = _get_curkse();
@@ -552,7 +574,7 @@ _thr_sched_switch_unlocked(struct pthread *curthread)
* a thread can be interrupted by other signals while
* it is running down pending signals.
*/
- sigemptyset(&psf.psf_sigset);
+ psf.psf_valid = 0;
curthread->curframe = &psf;
/*
@@ -561,6 +583,8 @@ _thr_sched_switch_unlocked(struct pthread *curthread)
* o The current thread is dead; it's stack needs to be
* cleaned up and it can't be done while operating on
* it.
+ * o The current thread has signals pending, should
+ * let scheduler install signal trampoline for us.
* o There are no runnable threads.
* o The next thread to run won't unlock the scheduler
* lock. A side note: the current thread may be run
@@ -570,8 +594,10 @@ _thr_sched_switch_unlocked(struct pthread *curthread)
if ((curthread->state == PS_DEAD) ||
(((td = KSE_RUNQ_FIRST(curkse)) == NULL) &&
(curthread->state != PS_RUNNING)) ||
- ((td != NULL) && (td->lock_switch == 0)))
+ ((td != NULL) && (td->lock_switch == 0))) {
+ curkse->k_switch = 1;
_thread_enter_uts(&curthread->tmbx, &curkse->k_mbx);
+ }
else {
uts_once = 0;
THR_GETCONTEXT(&curthread->tmbx.tm_context);
@@ -623,6 +649,15 @@ _thr_sched_switch_unlocked(struct pthread *curthread)
}
}
+ if (psf.psf_valid) {
+ /*
+ * It is ugly we must increase critical count, because we
+ * have a frame saved, we must backout state in psf
+ * before we can process signals.
+ */
+ curthread->critical_count++;
+ }
+
if (curthread->lock_switch != 0) {
/*
* Unlock the scheduling queue and leave the
@@ -638,11 +673,15 @@ _thr_sched_switch_unlocked(struct pthread *curthread)
/*
* This thread is being resumed; check for cancellations.
*/
- if ((resume_once == 0) && (!THR_IN_CRITICAL(curthread))) {
- resume_once = 1;
- thr_resume_check(curthread, &curthread->tmbx.tm_context, &psf);
+ if ((psf.psf_valid || curthread->check_pending)) {
+ resume_once = 0;
+ THR_GETCONTEXT(&uc);
+ if (resume_once == 0) {
+ resume_once = 1;
+ curthread->check_pending = 0;
+ thr_resume_check(curthread, &uc, &psf);
+ }
}
-
THR_ACTIVATE_LAST_LOCK(curthread);
}
@@ -747,9 +786,6 @@ kse_sched_single(struct kse *curkse)
KSE_WAITQ_REMOVE(curkse, td_wait);
}
}
- KSE_SCHED_UNLOCK(curkse, curkse->k_kseg);
- kse_check_signals(curkse);
- KSE_SCHED_LOCK(curkse, curkse->k_kseg);
}
/* Remove the frame reference. */
@@ -810,12 +846,12 @@ kse_sched_multi(struct kse *curkse)
KSE_CLEAR_WAIT(curkse);
}
- /* Lock the scheduling lock. */
- curthread = curkse->k_curthread;
- if ((curthread == NULL) || (curthread->need_switchout == 0)) {
- /* This is an upcall; take the scheduler lock. */
+ /*If this is an upcall; take the scheduler lock. */
+ if (curkse->k_switch == 0)
KSE_SCHED_LOCK(curkse, curkse->k_kseg);
- }
+ curkse->k_switch = 0;
+
+ curthread = curkse->k_curthread;
if (KSE_IS_IDLE(curkse)) {
KSE_CLEAR_IDLE(curkse);
@@ -879,11 +915,6 @@ kse_sched_multi(struct kse *curkse)
kse_wakeup_multi(curkse);
- /* This has to be done without the scheduling lock held. */
- KSE_SCHED_UNLOCK(curkse, curkse->k_kseg);
- kse_check_signals(curkse);
- KSE_SCHED_LOCK(curkse, curkse->k_kseg);
-
#ifdef DEBUG_THREAD_KERN
dump_queues(curkse);
#endif
@@ -899,9 +930,6 @@ kse_sched_multi(struct kse *curkse)
kse_wait(curkse, td_wait);
kse_check_completed(curkse);
kse_check_waitq(curkse);
- KSE_SCHED_UNLOCK(curkse, curkse->k_kseg);
- kse_check_signals(curkse);
- KSE_SCHED_LOCK(curkse, curkse->k_kseg);
}
/* Check for no more threads: */
@@ -966,15 +994,19 @@ kse_sched_multi(struct kse *curkse)
* signal frame to the thread's context.
*/
#ifdef NOT_YET
- if ((curframe == NULL) && ((curthread->have_signals != 0) ||
+ if ((((curframe == NULL) && (curthread->check_pending != 0)) ||
(((curthread->cancelflags & THR_AT_CANCEL_POINT) == 0) &&
- ((curthread->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS) != 0))))
+ ((curthread->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS) != 0))) &&
+ !THR_IN_CRITICAL(curthread))
signalcontext(&curthread->tmbx.tm_context, 0,
(__sighandler_t *)thr_resume_wrapper);
#else
- if ((curframe == NULL) && (curthread->have_signals != 0))
+ if ((curframe == NULL) && (curthread->check_pending != 0) &&
+ !THR_IN_CRITICAL(curthread)) {
+ curthread->check_pending = 0;
signalcontext(&curthread->tmbx.tm_context, 0,
(__sighandler_t *)thr_resume_wrapper);
+ }
#endif
/*
* Continue the thread at its current frame:
@@ -999,61 +1031,31 @@ kse_sched_multi(struct kse *curkse)
}
static void
-kse_check_signals(struct kse *curkse)
-{
- sigset_t sigset;
- int i;
-
- /* Deliver posted signals. */
- for (i = 0; i < _SIG_WORDS; i++) {
- atomic_swap_int(&curkse->k_mbx.km_sigscaught.__bits[i],
- 0, &sigset.__bits[i]);
- }
- if (SIGNOTEMPTY(sigset)) {
- /*
- * Dispatch each signal.
- *
- * XXX - There is no siginfo for any of these.
- * I think there should be, especially for
- * signals from other processes (si_pid, si_uid).
- */
- for (i = 1; i < NSIG; i++) {
- if (sigismember(&sigset, i) != 0) {
- DBG_MSG("Dispatching signal %d\n", i);
- _thr_sig_dispatch(curkse, i,
- NULL /* no siginfo */);
- }
- }
- sigemptyset(&sigset);
- __sys_sigprocmask(SIG_SETMASK, &sigset, NULL);
- }
-}
-
-static void
-thr_resume_wrapper(int unused_1, siginfo_t *unused_2, ucontext_t *ucp)
+thr_resume_wrapper(int sig, siginfo_t *siginfo, ucontext_t *ucp)
{
struct pthread *curthread = _get_curthread();
+ struct kse *curkse;
+ int ret;
+ DBG_MSG(">>> sig wrapper\n");
+ if (curthread->lock_switch)
+ PANIC("thr_resume_wrapper, lock_switch != 0\n");
thr_resume_check(curthread, ucp, NULL);
+ _kse_critical_enter();
+ curkse = _get_curkse();
+ curthread->tmbx.tm_context = *ucp;
+ ret = _thread_switch(&curthread->tmbx, &curkse->k_mbx.km_curthread);
+ if (ret != 0)
+ PANIC("thr_resume_wrapper: thread has returned "
+ "from _thread_switch");
+ /* THR_SETCONTEXT(ucp); */ /* not work, why ? */
}
static void
thr_resume_check(struct pthread *curthread, ucontext_t *ucp,
struct pthread_sigframe *psf)
{
- /* Check signals before cancellations. */
- while (curthread->have_signals != 0) {
- /* Clear the pending flag. */
- curthread->have_signals = 0;
-
- /*
- * It's perfectly valid, though not portable, for
- * signal handlers to munge their interrupted context
- * and expect to return to it. Ensure we use the
- * correct context when running down signals.
- */
- _thr_sig_rundown(curthread, ucp, psf);
- }
+ _thr_sig_rundown(curthread, ucp, psf);
#ifdef NOT_YET
if (((curthread->cancelflags & THR_AT_CANCEL_POINT) == 0) &&
@@ -1124,7 +1126,7 @@ thr_cleanup(struct kse *curkse, struct pthread *thread)
THR_GCLIST_ADD(thread);
/* Use thread_list_lock */
active_threads--;
- if (active_threads == 0) {
+ if (active_threads == 1) {
KSE_LOCK_RELEASE(curkse, &_thread_list_lock);
exit(0);
}
@@ -1203,8 +1205,15 @@ _thr_gc(struct pthread *curthread)
KSE_LOCK_RELEASE(curthread->kse, &kse_lock);
_kse_critical_leave(crit);
}
- DBG_MSG("Freeing thread %p\n", td);
- _thr_free(curthread, td);
+ /*
+ * XXX we don't free initial thread, because there might
+ * have some code referencing initial thread.
+ */
+ if (td != _thr_initial) {
+ DBG_MSG("Freeing thread %p\n", td);
+ _thr_free(curthread, td);
+ } else
+ DBG_MSG("Initial thread won't be freed\n");
}
/* XXX free kse and ksegrp list should be looked as well */
}
@@ -1216,7 +1225,6 @@ _thr_gc(struct pthread *curthread)
int
_thr_schedule_add(struct pthread *curthread, struct pthread *newthread)
{
- struct kse *curkse;
kse_critical_t crit;
int ret;
@@ -1250,15 +1258,11 @@ _thr_schedule_add(struct pthread *curthread, struct pthread *newthread)
/*
* This thread needs a new KSE and KSEG.
*/
- crit = _kse_critical_enter();
- curkse = _get_curkse();
- _ksd_setprivate(&newthread->kse->k_ksd);
- newthread->kse->k_flags |= KF_INITIALIZED|KF_STARTED;
+ newthread->kse->k_flags &= ~KF_INITIALIZED;
+ newthread->kse->k_flags |= KF_STARTED;
ret = kse_create(&newthread->kse->k_mbx, 1);
if (ret != 0)
ret = errno;
- _ksd_setprivate(&curkse->k_ksd);
- _kse_critical_leave(crit);
}
else {
/*
@@ -1266,6 +1270,7 @@ _thr_schedule_add(struct pthread *curthread, struct pthread *newthread)
* assigned threads. If the new thread is runnable, also
* add it to the KSE's run queue.
*/
+ crit = _kse_critical_enter();
KSE_SCHED_LOCK(curthread->kse, newthread->kseg);
KSEG_THRQ_ADD(newthread->kseg, newthread);
if (newthread->state == PS_RUNNING)
@@ -1288,6 +1293,7 @@ _thr_schedule_add(struct pthread *curthread, struct pthread *newthread)
kse_wakeup_one(newthread);
}
KSE_SCHED_UNLOCK(curthread->kse, newthread->kseg);
+ _kse_critical_leave(crit);
ret = 0;
}
if (ret != 0)
@@ -1328,6 +1334,7 @@ kse_check_completed(struct kse *kse)
{
struct pthread *thread;
struct kse_thr_mailbox *completed;
+ int sig;
if ((completed = kse->k_mbx.km_completed) != NULL) {
kse->k_mbx.km_completed = NULL;
@@ -1348,6 +1355,13 @@ kse_check_completed(struct kse *kse)
thread->active = 0;
}
}
+ if ((sig = thread->tmbx.tm_syncsig.si_signo) != 0) {
+ if (SIGISMEMBER(thread->sigmask, sig))
+ SIGADDSET(thread->sigpend, sig);
+ else
+ _thr_sig_add(thread, sig, &thread->tmbx.tm_syncsig);
+ thread->tmbx.tm_syncsig.si_signo = 0;
+ }
completed = completed->tm_next;
}
}
@@ -1446,6 +1460,8 @@ kse_switchout_thread(struct kse *kse, struct pthread *thread)
{
int level;
int i;
+ int restart;
+ siginfo_t siginfo;
/*
* Place the currently running thread into the
@@ -1459,15 +1475,25 @@ kse_switchout_thread(struct kse *kse, struct pthread *thread)
thread->need_switchout = 0;
/* This thread must have blocked in the kernel. */
/* thread->slice_usec = -1;*/ /* restart timeslice */
- /*
- * XXX - Check for pending signals for this thread to
- * see if we need to interrupt it in the kernel.
- */
- /* if (thread->check_pending != 0) */
if ((thread->slice_usec != -1) &&
(thread->attr.sched_policy != SCHED_FIFO))
thread->slice_usec += (thread->tmbx.tm_uticks
+ thread->tmbx.tm_sticks) * _clock_res_usec;
+ /*
+ * Check for pending signals for this thread to
+ * see if we need to interrupt it in the kernel.
+ */
+ if (thread->check_pending != 0) {
+ for (i = 1; i <= _SIG_MAXSIG; ++i) {
+ if (SIGISMEMBER(thread->sigpend, i) &&
+ !SIGISMEMBER(thread->sigmask, i)) {
+ restart = _thread_sigact[1 - 1].sa_flags & SA_RESTART;
+ kse_thr_interrupt(&thread->tmbx,
+ restart ? -2 : -1);
+ break;
+ }
+ }
+ }
}
else {
switch (thread->state) {
@@ -1507,10 +1533,12 @@ kse_switchout_thread(struct kse *kse, struct pthread *thread)
THR_SET_STATE(thread, PS_RUNNING);
break;
+ case PS_SIGWAIT:
+ KSE_WAITQ_INSERT(kse, thread);
+ break;
case PS_JOIN:
case PS_MUTEX_WAIT:
case PS_SIGSUSPEND:
- case PS_SIGWAIT:
case PS_SUSPENDED:
case PS_DEADLOCK:
default:
@@ -1564,11 +1592,18 @@ kse_switchout_thread(struct kse *kse, struct pthread *thread)
if (thread->check_pending != 0) {
/* Install pending signals into the frame. */
thread->check_pending = 0;
- for (i = 0; i < _SIG_MAXSIG; i++) {
- if (sigismember(&thread->sigpend, i) &&
- !sigismember(&thread->tmbx.tm_context.uc_sigmask, i))
+ KSE_LOCK_ACQUIRE(kse, &_thread_signal_lock);
+ for (i = 1; i <= _SIG_MAXSIG; i++) {
+ if (SIGISMEMBER(thread->sigmask, i))
+ continue;
+ if (SIGISMEMBER(thread->sigpend, i))
_thr_sig_add(thread, i, &thread->siginfo[i]);
+ else if (SIGISMEMBER(_thr_proc_sigpending, i) &&
+ _thr_getprocsig_unlocked(i, &siginfo)) {
+ _thr_sig_add(thread, i, &siginfo);
+ }
}
+ KSE_LOCK_RELEASE(kse, &_thread_signal_lock);
}
}
@@ -2016,6 +2051,10 @@ _kse_alloc(struct pthread *curthread)
_lockuser_destroy(&kse->k_lockusers[i]);
}
free(kse);
+ if (curthread != NULL) {
+ KSE_LOCK_RELEASE(curthread->kse, &kse_lock);
+ _kse_critical_leave(crit);
+ }
return (NULL);
}
kse->k_flags = 0;
@@ -2044,7 +2083,7 @@ kse_reinit(struct kse *kse)
kse->k_kseg = 0;
kse->k_schedq = 0;
kse->k_locklevel = 0;
- sigemptyset(&kse->k_sigmask);
+ SIGEMPTYSET(kse->k_sigmask);
bzero(&kse->k_sigq, sizeof(kse->k_sigq));
kse->k_check_sigq = 0;
kse->k_flags = 0;
@@ -2053,6 +2092,7 @@ kse_reinit(struct kse *kse)
kse->k_error = 0;
kse->k_cpu = 0;
kse->k_done = 0;
+ kse->k_switch = 0;
}
void
@@ -2171,10 +2211,12 @@ thr_link(struct pthread *thread)
{
kse_critical_t crit;
struct kse *curkse;
+ struct pthread *curthread;
crit = _kse_critical_enter();
curkse = _get_curkse();
-
+ curthread = _get_curthread();
+ thread->sigmask = curthread->sigmask;
KSE_LOCK_ACQUIRE(curkse, &_thread_list_lock);
/*
* Initialize the unique id (which GDB uses to track
diff --git a/lib/libkse/thread/thr_kill.c b/lib/libkse/thread/thr_kill.c
index 19f34bb..226cb86 100644
--- a/lib/libkse/thread/thr_kill.c
+++ b/lib/libkse/thread/thr_kill.c
@@ -45,7 +45,7 @@ _pthread_kill(pthread_t pthread, int sig)
int ret;
/* Check for invalid signal numbers: */
- if (sig < 0 || sig >= NSIG)
+ if (sig < 0 || sig > _SIG_MAXSIG)
/* Invalid signal: */
ret = EINVAL;
/*
diff --git a/lib/libkse/thread/thr_private.h b/lib/libkse/thread/thr_private.h
index 3672025..fefacd1 100644
--- a/lib/libkse/thread/thr_private.h
+++ b/lib/libkse/thread/thr_private.h
@@ -171,7 +171,7 @@ typedef struct kse_thr_mailbox *kse_critical_t;
struct kse_group;
-#define MAX_KSE_LOCKLEVEL 3
+#define MAX_KSE_LOCKLEVEL 5
struct kse {
struct kse_mailbox k_mbx; /* kernel kse mailbox */
/* -- location and order specific items for gdb -- */
@@ -190,7 +190,7 @@ struct kse {
struct lockuser k_lockusers[MAX_KSE_LOCKLEVEL];
int k_locklevel;
sigset_t k_sigmask;
- struct sigstatus k_sigq[NSIG];
+ struct sigstatus k_sigq[_SIG_MAXSIG];
stack_t k_stack;
int k_check_sigq;
int k_flags;
@@ -201,6 +201,7 @@ struct kse {
int k_error; /* syscall errno in critical */
int k_cpu; /* CPU ID when bound */
int k_done; /* this KSE is done */
+ int k_switch; /* thread switch in UTS */
};
/*
@@ -546,8 +547,8 @@ enum pthread_state {
union pthread_wait_data {
pthread_mutex_t mutex;
pthread_cond_t cond;
- const sigset_t *sigwait; /* Waiting on a signal in sigwait */
struct lock *lock;
+ siginfo_t *sigwaitinfo; /* used to save siginfo for sigwaitinfo() */
};
/*
@@ -563,6 +564,7 @@ typedef void (*thread_continuation_t) (void *);
* state is restored from here.
*/
struct pthread_sigframe {
+ int psf_valid;
int psf_flags;
int psf_interrupted;
int psf_signo;
@@ -586,7 +588,7 @@ struct pthread_specific_elem {
};
-#define MAX_THR_LOCKLEVEL 3
+#define MAX_THR_LOCKLEVEL 5
/*
* Thread structure.
*/
@@ -640,7 +642,7 @@ struct pthread {
* Used for tracking delivery of signal handlers.
*/
struct pthread_sigframe *curframe;
- siginfo_t siginfo[NSIG];
+ siginfo_t siginfo[_SIG_MAXSIG];
/*
* Cancelability flags - the lower 2 bits are used by cancel
@@ -657,11 +659,10 @@ struct pthread {
* The thread's base and pending signal masks. The active
* signal mask is stored in the thread's context (in mailbox).
*/
+ sigset_t oldsigmask;
sigset_t sigmask;
sigset_t sigpend;
- int sigmask_seqno;
int check_pending;
- int have_signals;
int refcount;
/* Thread state: */
@@ -997,14 +998,14 @@ SCLASS struct pthread_cond_attr _pthread_condattr_default
SCLASS int _clock_res_usec SCLASS_PRESET(CLOCK_RES_USEC);
/* Array of signal actions for this process: */
-SCLASS struct sigaction _thread_sigact[NSIG];
+SCLASS struct sigaction _thread_sigact[_SIG_MAXSIG];
/*
* 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];
+SCLASS int _thread_dfl_count[_SIG_MAXSIG];
/*
* Lock for above count of dummy handlers and for the process signal
@@ -1014,8 +1015,7 @@ SCLASS struct lock _thread_signal_lock;
/* Pending signals and mask for this process: */
SCLASS sigset_t _thr_proc_sigpending;
-SCLASS sigset_t _thr_proc_sigmask SCLASS_PRESET({{0, 0, 0, 0}});
-SCLASS siginfo_t _thr_proc_siginfo[NSIG];
+SCLASS siginfo_t _thr_proc_siginfo[_SIG_MAXSIG];
SCLASS pid_t _thr_pid SCLASS_PRESET(0);
@@ -1030,7 +1030,7 @@ SCLASS struct lock _keytable_lock;
SCLASS struct lock _thread_list_lock;
SCLASS int _thr_guard_default;
SCLASS int _thr_page_size;
-
+SCLASS pthread_t _thr_sig_daemon;
SCLASS int _thr_debug_flags SCLASS_PRESET(0);
/* Undefine the storage class and preset specifiers: */
@@ -1116,7 +1116,6 @@ void _thr_panic_exit(char *, int, char *);
void _thread_cleanupspecific(void);
void _thread_dump_info(void);
void _thread_printf(int, const char *, ...);
-void _thr_sched_frame(struct pthread_sigframe *);
void _thr_sched_switch(struct pthread *);
void _thr_sched_switch_unlocked(struct pthread *);
void _thr_set_timeout(const struct timespec *);
@@ -1126,13 +1125,17 @@ void _thr_sig_check_pending(struct pthread *);
void _thr_sig_rundown(struct pthread *, ucontext_t *,
struct pthread_sigframe *);
void _thr_sig_send(struct pthread *pthread, int sig);
-void _thr_sig_wrapper(void);
void _thr_sigframe_restore(struct pthread *thread, struct pthread_sigframe *psf);
void _thr_spinlock_init(void);
void _thr_enter_cancellation_point(struct pthread *);
void _thr_leave_cancellation_point(struct pthread *);
int _thr_setconcurrency(int new_level);
int _thr_setmaxconcurrency(void);
+int _thr_start_sig_daemon(void);
+int _thr_getprocsig(int sig, siginfo_t *siginfo);
+int _thr_getprocsig_unlocked(int sig, siginfo_t *siginfo);
+void _thr_signal_init(void);
+void _thr_signal_deinit(void);
/*
* Aliases for _pthread functions. Should be called instead of
@@ -1216,6 +1219,8 @@ int __sys_select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
ssize_t __sys_read(int, void *, size_t);
ssize_t __sys_write(int, const void *, size_t);
void __sys_exit(int);
+int __sys_sigwait(const sigset_t *, int *);
+int __sys_sigtimedwait(sigset_t *, siginfo_t *, struct timespec *);
#endif
/* #include <poll.h> */
diff --git a/lib/libkse/thread/thr_sig.c b/lib/libkse/thread/thr_sig.c
index 94e5630..d06db9d 100644
--- a/lib/libkse/thread/thr_sig.c
+++ b/lib/libkse/thread/thr_sig.c
@@ -45,19 +45,15 @@
/* Prototypes: */
static void build_siginfo(siginfo_t *info, int signo);
-/* static void thr_sig_add(struct pthread *pthread, int sig, siginfo_t *info); */
static void thr_sig_check_state(struct pthread *pthread, int sig);
static struct pthread *thr_sig_find(struct kse *curkse, int sig,
siginfo_t *info);
static void handle_special_signals(struct kse *curkse, int sig);
-static void thr_sigframe_add(struct pthread *thread, int sig,
- siginfo_t *info);
+static void thr_sigframe_add(struct pthread *thread);
static void thr_sigframe_restore(struct pthread *thread,
struct pthread_sigframe *psf);
static void thr_sigframe_save(struct pthread *thread,
struct pthread_sigframe *psf);
-static void thr_sig_invoke_handler(struct pthread *, int sig,
- siginfo_t *info, ucontext_t *ucp);
/* #define DEBUG_SIGNAL */
#ifdef DEBUG_SIGNAL
@@ -137,6 +133,65 @@ static void thr_sig_invoke_handler(struct pthread *, int sig,
* signal unmasked.
*/
+static void *
+sig_daemon(void *arg /* Unused */)
+{
+ int i;
+ kse_critical_t crit;
+ struct timespec ts;
+ sigset_t set;
+ struct kse *curkse;
+ struct pthread *curthread = _get_curthread();
+
+ DBG_MSG("signal daemon started");
+
+ curthread->name = strdup("signal thread");
+ crit = _kse_critical_enter();
+ curkse = _get_curkse();
+ SIGFILLSET(set);
+ __sys_sigprocmask(SIG_SETMASK, &set, NULL);
+ __sys_sigpending(&set);
+ ts.tv_sec = 0;
+ ts.tv_nsec = 0;
+ while (1) {
+ KSE_LOCK_ACQUIRE(curkse, &_thread_signal_lock);
+ _thr_proc_sigpending = set;
+ KSE_LOCK_RELEASE(curkse, &_thread_signal_lock);
+ for (i = 1; i <= _SIG_MAXSIG; i++) {
+ if (SIGISMEMBER(set, i) != 0)
+ _thr_sig_dispatch(curkse, i,
+ NULL /* no siginfo */);
+ }
+ ts.tv_sec = 30;
+ ts.tv_nsec = 0;
+ curkse->k_mbx.km_flags =
+ KMF_NOUPCALL | KMF_NOCOMPLETED | KMF_WAITSIGEVENT;
+ kse_release(&ts);
+ curkse->k_mbx.km_flags = 0;
+ set = curkse->k_mbx.km_sigscaught;
+ }
+ return (0);
+}
+
+/* Utility function to create signal daemon thread */
+int
+_thr_start_sig_daemon(void)
+{
+ pthread_attr_t attr;
+ sigset_t sigset, oldset;
+
+ SIGFILLSET(sigset);
+ pthread_sigmask(SIG_SETMASK, &sigset, &oldset);
+ pthread_attr_init(&attr);
+ pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
+ /* sigmask will be inherited */
+ if (pthread_create(&_thr_sig_daemon, &attr, sig_daemon, NULL))
+ PANIC("can not create signal daemon thread!\n");
+ pthread_attr_destroy(&attr);
+ pthread_sigmask(SIG_SETMASK, &oldset, NULL);
+ return (0);
+}
+
/*
* This signal handler only delivers asynchronous signals.
* This must be called with upcalls disabled and without
@@ -151,7 +206,6 @@ _thr_sig_dispatch(struct kse *curkse, int sig, siginfo_t *info)
/* Some signals need special handling: */
handle_special_signals(curkse, sig);
- DBG_MSG("dispatch sig:%d\n", sig);
while ((thread = thr_sig_find(curkse, sig, info)) != NULL) {
/*
* Setup the target thread to receive the signal:
@@ -163,18 +217,17 @@ _thr_sig_dispatch(struct kse *curkse, int sig, siginfo_t *info)
THR_IS_EXITING(thread) || THR_IS_SUSPENDED(thread)) {
KSE_SCHED_UNLOCK(curkse, thread->kseg);
_thr_ref_delete(NULL, thread);
- } else if (sigismember(&thread->tmbx.tm_context.uc_sigmask,
- sig)) {
+ } else if (SIGISMEMBER(thread->sigmask, sig)) {
KSE_SCHED_UNLOCK(curkse, thread->kseg);
_thr_ref_delete(NULL, thread);
- }
- else {
+ } else {
_thr_sig_add(thread, sig, info);
KSE_SCHED_UNLOCK(curkse, thread->kseg);
_thr_ref_delete(NULL, thread);
break;
}
}
+ DBG_MSG("<<< _thr_sig_dispatch\n");
}
void
@@ -187,7 +240,6 @@ _thr_sig_handler(int sig, siginfo_t *info, ucontext_t *ucp)
if ((curkse == NULL) || ((curkse->k_flags & KF_STARTED) == 0)) {
/* Upcalls are not yet started; just call the handler. */
sigfunc = _thread_sigact[sig - 1].sa_sigaction;
- ucp->uc_sigmask = _thr_proc_sigmask;
if (((__sighandler_t *)sigfunc != SIG_DFL) &&
((__sighandler_t *)sigfunc != SIG_IGN) &&
(sigfunc != (__siginfohandler_t *)_thr_sig_handler)) {
@@ -202,68 +254,119 @@ _thr_sig_handler(int sig, siginfo_t *info, ucontext_t *ucp)
else {
/* Nothing. */
DBG_MSG("Got signal %d\n", sig);
- sigaddset(&curkse->k_mbx.km_sigscaught, sig);
- ucp->uc_sigmask = _thr_proc_sigmask;
+ /* XXX Bound thread will fall into this... */
}
}
+/* Must be called with signal lock and schedule lock held in order */
static void
thr_sig_invoke_handler(struct pthread *curthread, int sig, siginfo_t *info,
ucontext_t *ucp)
{
void (*sigfunc)(int, siginfo_t *, void *);
- sigset_t saved_mask;
- int saved_seqno;
+ sigset_t sigmask;
+ int sa_flags;
+ struct sigaction act;
+ struct kse *curkse;
- /* Invoke the signal handler without going through the scheduler:
+ /*
+ * Invoke the signal handler without going through the scheduler:
*/
DBG_MSG("Got signal %d, calling handler for current thread %p\n",
sig, curthread);
- /*
- * Setup the threads signal mask.
- *
- * The mask is changed in the thread's active signal mask
- * (in the context) and not in the base signal mask because
- * a thread is allowed to change its signal mask within a
- * signal handler. If it does, the signal mask restored
- * after the handler should be the same as that set by the
- * thread during the handler, not the original mask from
- * before calling the handler. The thread could also
- * modify the signal mask in the context and expect this
- * mask to be used.
- */
- THR_SCHED_LOCK(curthread, curthread);
- saved_mask = curthread->tmbx.tm_context.uc_sigmask;
- saved_seqno = curthread->sigmask_seqno;
- SIGSETOR(curthread->tmbx.tm_context.uc_sigmask,
- _thread_sigact[sig - 1].sa_mask);
- sigaddset(&curthread->tmbx.tm_context.uc_sigmask, sig);
- THR_SCHED_UNLOCK(curthread, curthread);
-
+ if (!_kse_in_critical())
+ PANIC("thr_sig_invoke_handler without in critical\n");
+ curkse = _get_curkse();
/*
* Check that a custom handler is installed and if
* the signal is not blocked:
*/
sigfunc = _thread_sigact[sig - 1].sa_sigaction;
- ucp->uc_sigmask = _thr_proc_sigmask;
+ sa_flags = _thread_sigact[sig - 1].sa_flags & SA_SIGINFO;
+ sigmask = curthread->sigmask;
+ SIGSETOR(curthread->sigmask, _thread_sigact[sig - 1].sa_mask);
+ if (!(sa_flags & (SA_NODEFER | SA_RESETHAND)))
+ SIGADDSET(curthread->sigmask, sig);
+ if ((sig != SIGILL) && (sa_flags & SA_RESETHAND)) {
+ if (_thread_dfl_count[sig - 1] == 0) {
+ act.sa_handler = SIG_DFL;
+ act.sa_flags = SA_RESTART;
+ SIGEMPTYSET(act.sa_mask);
+ __sys_sigaction(sig, &act, NULL);
+ __sys_sigaction(sig, NULL, &_thread_sigact[sig - 1]);
+ }
+ }
+ KSE_LOCK_RELEASE(curkse, &_thread_signal_lock);
+ KSE_SCHED_UNLOCK(curkse, curkse->k_kseg);
+ _kse_critical_leave(&curthread->tmbx);
+ ucp->uc_sigmask = sigmask;
+
if (((__sighandler_t *)sigfunc != SIG_DFL) &&
((__sighandler_t *)sigfunc != SIG_IGN)) {
- if (((_thread_sigact[sig - 1].sa_flags & SA_SIGINFO) != 0) ||
- (info == NULL))
+ if ((sa_flags & SA_SIGINFO) != 0 || info == NULL)
(*(sigfunc))(sig, info, ucp);
else
(*(sigfunc))(sig, (siginfo_t*)(intptr_t)info->si_code,
ucp);
+ } else {
+ /* XXX
+ * TODO: exit process if signal would kill it.
+ */
+#ifdef NOTYET
+ if (sigprop(sig) & SA_KILL)
+ kse_sigexit(sig);
+#endif
}
-
+ _kse_critical_enter();
+ /* Don't trust after critical leave/enter */
+ curkse = _get_curkse();
+ KSE_SCHED_LOCK(curkse, curkse->k_kseg);
+ KSE_LOCK_ACQUIRE(curkse, &_thread_signal_lock);
/*
* Restore the thread's signal mask.
*/
- if (saved_seqno == curthread->sigmask_seqno)
- curthread->tmbx.tm_context.uc_sigmask = saved_mask;
- else
- curthread->tmbx.tm_context.uc_sigmask = curthread->sigmask;
+ curthread->sigmask = ucp->uc_sigmask;
+
+ DBG_MSG("Got signal %d, handler returned %p\n", sig, curthread);
+}
+
+int
+_thr_getprocsig(int sig, siginfo_t *siginfo)
+{
+ kse_critical_t crit;
+ struct kse *curkse;
+ int ret;
+
+ DBG_MSG(">>> _thr_getprocsig\n");
+
+ crit = _kse_critical_enter();
+ curkse = _get_curkse();
+ KSE_LOCK_ACQUIRE(curkse, &_thread_signal_lock);
+ ret = _thr_getprocsig_unlocked(sig, siginfo);
+ KSE_LOCK_RELEASE(curkse, &_thread_signal_lock);
+ _kse_critical_leave(crit);
+
+ DBG_MSG("<<< _thr_getprocsig\n");
+ return (ret);
+}
+
+int
+_thr_getprocsig_unlocked(int sig, siginfo_t *siginfo)
+{
+ sigset_t sigset;
+ struct timespec ts;
+
+ /* try to retrieve signal from kernel */
+ SIGEMPTYSET(sigset);
+ SIGADDSET(sigset, sig);
+ ts.tv_sec = 0;
+ ts.tv_nsec = 0;
+ if (__sys_sigtimedwait(&sigset, siginfo, &ts) > 0) {
+ SIGDELSET(_thr_proc_sigpending, sig);
+ return (sig);
+ }
+ return (0);
}
/*
@@ -273,15 +376,12 @@ thr_sig_invoke_handler(struct pthread *curthread, int sig, siginfo_t *info,
struct pthread *
thr_sig_find(struct kse *curkse, int sig, siginfo_t *info)
{
- int handler_installed;
struct pthread *pthread;
struct pthread *suspended_thread, *signaled_thread;
+ siginfo_t si;
DBG_MSG("Looking for thread to handle signal %d\n", sig);
- handler_installed = (_thread_sigact[sig - 1].sa_handler != SIG_IGN) &&
- (_thread_sigact[sig - 1].sa_handler != SIG_DFL);
-
/* Check if the signal requires a dump of thread information: */
if (sig == SIGINFO) {
/* Dump thread information to file: */
@@ -302,19 +402,39 @@ thr_sig_find(struct kse *curkse, int sig, siginfo_t *info)
KSE_LOCK_ACQUIRE(curkse, &_thread_list_lock);
TAILQ_FOREACH(pthread, &_thread_list, tle) {
+ if (pthread == _thr_sig_daemon)
+ continue;
+#ifdef NOTYET
+ /* Signal delivering to bound thread is done by kernel */
+ if (pthread->attr.flags & PTHREAD_SCOPE_SYSTEM)
+ continue;
+#endif
+
/* Take the scheduling lock. */
KSE_SCHED_LOCK(curkse, pthread->kseg);
- if ((pthread->state == PS_SIGWAIT) &&
- sigismember(pthread->data.sigwait, sig)) {
+ if ((pthread->state == PS_DEAD) ||
+ (pthread->state == PS_DEADLOCK) ||
+ THR_IS_EXITING(pthread) ||
+ THR_IS_SUSPENDED(pthread) ||
+ SIGISMEMBER(pthread->sigmask, sig)) {
+ ; /* Skip this thread. */
+ } else if (pthread->state == PS_SIGWAIT) {
/*
- * Return the signal number and make the
- * thread runnable.
+ * retrieve signal from kernel, if it is job control
+ * signal, and sigaction is SIG_DFL, then we will
+ * be stopped in kernel, we hold lock here, but that
+ * does not matter, because that's job control, and
+ * whole process should be stopped.
*/
- pthread->signo = sig;
- _thr_setrunnable_unlocked(pthread);
-
+ if (_thr_getprocsig(sig, &si)) {
+ DBG_MSG("Waking thread %p in sigwait"
+ " with signal %d\n", pthread, sig);
+ /* where to put siginfo ? */
+ *(pthread->data.sigwaitinfo) = si;
+ pthread->sigmask = pthread->oldsigmask;
+ _thr_setrunnable_unlocked(pthread);
+ }
KSE_SCHED_UNLOCK(curkse, pthread->kseg);
-
/*
* POSIX doesn't doesn't specify which thread
* will get the signal if there are multiple
@@ -326,16 +446,8 @@ thr_sig_find(struct kse *curkse, int sig, siginfo_t *info)
* to the process pending set.
*/
KSE_LOCK_RELEASE(curkse, &_thread_list_lock);
- DBG_MSG("Waking thread %p in sigwait with signal %d\n",
- pthread, sig);
return (NULL);
- }
- else if ((pthread->state == PS_DEAD) ||
- (pthread->state == PS_DEADLOCK) ||
- THR_IS_EXITING(pthread) || THR_IS_SUSPENDED(pthread))
- ; /* Skip this thread. */
- else if ((handler_installed != 0) &&
- !sigismember(&pthread->tmbx.tm_context.uc_sigmask, sig)) {
+ } else {
if (pthread->state == PS_SIGSUSPEND) {
if (suspended_thread == NULL) {
suspended_thread = pthread;
@@ -344,49 +456,22 @@ thr_sig_find(struct kse *curkse, int sig, siginfo_t *info)
} else if (signaled_thread == NULL) {
signaled_thread = pthread;
signaled_thread->refcount++;
- }
+ }
}
KSE_SCHED_UNLOCK(curkse, pthread->kseg);
}
KSE_LOCK_RELEASE(curkse, &_thread_list_lock);
- /*
- * Only perform wakeups and signal delivery if there is a
- * custom handler installed:
- */
- if (handler_installed == 0) {
- /*
- * There is no handler installed; nothing to do here.
- */
- } else if (suspended_thread == NULL &&
- signaled_thread == NULL) {
- /*
- * Add it to the set of signals pending
- * on the process:
- */
- KSE_LOCK_ACQUIRE(curkse, &_thread_signal_lock);
- if (!sigismember(&_thr_proc_sigpending, sig)) {
- sigaddset(&_thr_proc_sigpending, sig);
- if (info == NULL)
- build_siginfo(&_thr_proc_siginfo[sig], sig);
- else
- memcpy(&_thr_proc_siginfo[sig], info,
- sizeof(*info));
- }
- KSE_LOCK_RELEASE(curkse, &_thread_signal_lock);
- } else {
- /*
- * We only deliver the signal to one thread;
- * give preference to the suspended thread:
- */
- if (suspended_thread != NULL) {
- pthread = suspended_thread;
+ if (suspended_thread != NULL) {
+ pthread = suspended_thread;
+ if (signaled_thread)
_thr_ref_delete(NULL, signaled_thread);
- } else
- pthread = signaled_thread;
- return (pthread);
+ } else if (signaled_thread) {
+ pthread = signaled_thread;
+ } else {
+ pthread = NULL;
}
- return (NULL);
+ return (pthread);
}
static void
@@ -405,64 +490,80 @@ void
_thr_sig_rundown(struct pthread *curthread, ucontext_t *ucp,
struct pthread_sigframe *psf)
{
- struct pthread_sigframe psf_save;
- sigset_t sigset;
+ siginfo_t siginfo;
int i;
+ kse_critical_t crit;
+ struct kse *curkse;
- THR_SCHED_LOCK(curthread, curthread);
- memcpy(&sigset, &curthread->sigpend, sizeof(sigset));
- sigemptyset(&curthread->sigpend);
- if (psf != NULL) {
- memcpy(&psf_save, psf, sizeof(*psf));
- SIGSETOR(sigset, psf_save.psf_sigset);
- sigemptyset(&psf->psf_sigset);
- }
- THR_SCHED_UNLOCK(curthread, curthread);
-
+ DBG_MSG(">>> thr_sig_rundown %p\n", curthread);
/* Check the threads previous state: */
- if ((psf != NULL) && (psf_save.psf_state != PS_RUNNING)) {
+ if ((psf != NULL) && (psf->psf_valid != 0)) {
/*
* Do a little cleanup handling for those threads in
* queues before calling the signal handler. Signals
* for these threads are temporarily blocked until
* after cleanup handling.
*/
- switch (psf_save.psf_state) {
+ switch (psf->psf_state) {
case PS_COND_WAIT:
_cond_wait_backout(curthread);
- psf_save.psf_state = PS_RUNNING;
+ psf->psf_state = PS_RUNNING;
break;
case PS_MUTEX_WAIT:
_mutex_lock_backout(curthread);
- psf_save.psf_state = PS_RUNNING;
+ psf->psf_state = PS_RUNNING;
break;
+ case PS_RUNNING:
+ break;
+
default:
+ psf->psf_state = PS_RUNNING;
break;
}
+ /* XXX see comment in thr_sched_switch_unlocked */
+ curthread->critical_count--;
}
+
/*
* Lower the priority before calling the handler in case
* it never returns (longjmps back):
*/
+ crit = _kse_critical_enter();
+ curkse = _get_curkse();
+ KSE_SCHED_LOCK(curkse, curkse->k_kseg);
+ KSE_LOCK_ACQUIRE(curkse, &_thread_signal_lock);
curthread->active_priority &= ~THR_SIGNAL_PRIORITY;
- for (i = 1; i < NSIG; i++) {
- if (sigismember(&sigset, i) != 0) {
- /* Call the handler: */
- thr_sig_invoke_handler(curthread, i,
- &curthread->siginfo[i], ucp);
+ while (1) {
+ for (i = 1; i <= _SIG_MAXSIG; i++) {
+ if (SIGISMEMBER(curthread->sigmask, i))
+ continue;
+ if (SIGISMEMBER(curthread->sigpend, i)) {
+ SIGDELSET(curthread->sigpend, i);
+ siginfo = curthread->siginfo[i];
+ break;
+ }
+ if (SIGISMEMBER(_thr_proc_sigpending, i)) {
+ if (_thr_getprocsig_unlocked(i, &siginfo))
+ break;
+ }
}
+ if (i <= _SIG_MAXSIG)
+ thr_sig_invoke_handler(curthread, i, &siginfo, ucp);
+ else
+ break;
}
- THR_SCHED_LOCK(curthread, curthread);
- if (psf != NULL)
- thr_sigframe_restore(curthread, &psf_save);
- /* Restore the signal mask. */
- curthread->tmbx.tm_context.uc_sigmask = curthread->sigmask;
- THR_SCHED_UNLOCK(curthread, curthread);
- _thr_sig_check_pending(curthread);
+ if (psf != NULL && psf->psf_valid != 0)
+ thr_sigframe_restore(curthread, psf);
+ curkse = _get_curkse();
+ KSE_LOCK_RELEASE(curkse, &_thread_signal_lock);
+ KSE_SCHED_UNLOCK(curkse, curkse->k_kseg);
+ _kse_critical_leave(&curthread->tmbx);
+
+ DBG_MSG("<<< thr_sig_rundown %p\n", curthread);
}
/*
@@ -477,87 +578,19 @@ _thr_sig_rundown(struct pthread *curthread, ucontext_t *ucp,
void
_thr_sig_check_pending(struct pthread *curthread)
{
- sigset_t sigset;
- sigset_t pending_process;
- sigset_t pending_thread;
- kse_critical_t crit;
- int i;
-
- curthread->check_pending = 0;
-
- /*
- * Check if there are pending signals for the running
- * thread or process that aren't blocked:
- */
- crit = _kse_critical_enter();
- KSE_LOCK_ACQUIRE(curthread->kse, &_thread_signal_lock);
- sigset = _thr_proc_sigpending;
- KSE_LOCK_RELEASE(curthread->kse, &_thread_signal_lock);
- _kse_critical_leave(crit);
+ ucontext_t uc;
+ volatile int once;
- THR_SCHED_LOCK(curthread, curthread);
- SIGSETOR(sigset, curthread->sigpend);
- SIGSETNAND(sigset, curthread->tmbx.tm_context.uc_sigmask);
- if (SIGNOTEMPTY(sigset)) {
- ucontext_t uc;
- volatile int once;
+ if (THR_IN_CRITICAL(curthread))
+ return;
+ once = 0;
+ THR_GETCONTEXT(&uc);
+ if (once == 0) {
+ once = 1;
curthread->check_pending = 0;
- THR_SCHED_UNLOCK(curthread, curthread);
-
- /*
- * Split the pending signals into those that were
- * pending on the process and those that were pending
- * on the thread.
- */
- sigfillset(&pending_process);
- sigfillset(&pending_thread);
- for (i = 1; i < NSIG; i++) {
- if (sigismember(&sigset, i) != 0) {
- if (sigismember(&curthread->sigpend, i) != 0) {
- build_siginfo(&curthread->siginfo[i], i);
- sigdelset(&pending_thread, i);
- } else {
- memcpy(&curthread->siginfo[i],
- &_thr_proc_siginfo[i],
- sizeof(siginfo_t));
- sigdelset(&pending_process, i);
- }
- }
- }
- /*
- * Remove any process pending signals that were scheduled
- * to be delivered from process' pending set.
- */
- crit = _kse_critical_enter();
- KSE_LOCK_ACQUIRE(curthread->kse, &_thread_signal_lock);
- SIGSETAND(_thr_proc_sigpending, pending_process);
- KSE_LOCK_RELEASE(curthread->kse, &_thread_signal_lock);
- _kse_critical_leave(crit);
-
- /*
- * Remove any thread pending signals that were scheduled
- * to be delivered from thread's pending set.
- */
- THR_SCHED_LOCK(curthread, curthread);
- SIGSETAND(curthread->sigpend, pending_thread);
- THR_SCHED_UNLOCK(curthread, curthread);
-
- once = 0;
- THR_GETCONTEXT(&uc);
- if (once == 0) {
- once = 1;
- for (i = 1; i < NSIG; i++) {
- if (sigismember(&sigset, i) != 0) {
- /* Call the handler: */
- thr_sig_invoke_handler(curthread, i,
- &curthread->siginfo[i], &uc);
- }
- }
- }
+ _thr_sig_rundown(curthread, &uc, NULL);
}
- else
- THR_SCHED_UNLOCK(curthread, curthread);
}
/*
@@ -575,10 +608,15 @@ handle_special_signals(struct kse *curkse, int sig)
case SIGTTIN:
case SIGTTOU:
KSE_LOCK_ACQUIRE(curkse, &_thread_signal_lock);
- sigdelset(&_thr_proc_sigpending, SIGCONT);
+ SIGDELSET(_thr_proc_sigpending, SIGCONT);
KSE_LOCK_RELEASE(curkse, &_thread_signal_lock);
break;
-
+ case SIGCONT:
+ KSE_LOCK_ACQUIRE(curkse, &_thread_signal_lock);
+ SIGDELSET(_thr_proc_sigpending, SIGTSTP);
+ SIGDELSET(_thr_proc_sigpending, SIGTTIN);
+ SIGDELSET(_thr_proc_sigpending, SIGTTOU);
+ KSE_LOCK_RELEASE(curkse, &_thread_signal_lock);
default:
break;
}
@@ -597,72 +635,92 @@ _thr_sig_add(struct pthread *pthread, int sig, siginfo_t *info)
{
int restart;
int suppress_handler = 0;
+ int fromproc = 0;
+ struct pthread *curthread = _get_curthread();
+ struct kse *curkse;
+ siginfo_t siginfo;
- if (pthread->curframe == NULL) {
- /*
- * This thread is active. Just add it to the
- * thread's pending set.
- */
- sigaddset(&pthread->sigpend, sig);
- pthread->check_pending = 1;
- if (info == NULL)
- build_siginfo(&pthread->siginfo[sig], sig);
- else if (info != &pthread->siginfo[sig])
- memcpy(&pthread->siginfo[sig], info,
- sizeof(*info));
- if ((pthread->blocked != 0) && !THR_IN_CRITICAL(pthread))
- kse_thr_interrupt(&pthread->tmbx /* XXX - restart?!?! */);
- }
- else {
- restart = _thread_sigact[sig - 1].sa_flags & SA_RESTART;
+ DBG_MSG(">>> _thr_sig_add\n");
- /* Make sure this signal isn't still in the pending set: */
- sigdelset(&pthread->sigpend, sig);
+ curkse = _get_curkse();
+ restart = _thread_sigact[sig - 1].sa_flags & SA_RESTART;
+ fromproc = (curthread == _thr_sig_daemon);
+
+ if (pthread->state == PS_DEAD || pthread->state == PS_DEADLOCK ||
+ pthread->state == PS_STATE_MAX)
+ return; /* return false */
+
+#ifdef NOTYET
+ if ((pthread->attrs.flags & PTHREAD_SCOPE_SYSTEM) != 0) {
+ if (!fromproc)
+ kse_thr_interrupt(&pthread->tmbx, 0, sig);
+ return;
+ }
+#endif
+ if (pthread->curframe == NULL ||
+ SIGISMEMBER(pthread->sigmask, sig) ||
+ THR_IN_CRITICAL(pthread)) {
+ /* thread is running or signal was being masked */
+ if (!fromproc) {
+ SIGADDSET(pthread->sigpend, sig);
+ if (info == NULL)
+ build_siginfo(&pthread->siginfo[sig], sig);
+ else if (info != &pthread->siginfo[sig])
+ memcpy(&pthread->siginfo[sig], info,
+ sizeof(*info));
+ } else {
+ if (!_thr_getprocsig(sig, &pthread->siginfo[sig]))
+ return;
+ SIGADDSET(pthread->sigpend, sig);
+ }
+ if (!SIGISMEMBER(pthread->sigmask, sig)) {
+ pthread->check_pending = 1;
+ if (pthread->blocked != 0 && !THR_IN_CRITICAL(pthread))
+ kse_thr_interrupt(&pthread->tmbx,
+ restart ? -2 : -1);
+ }
+ }
+ else {
+ /* if process signal not exists, just return */
+ if (fromproc) {
+ if (!_thr_getprocsig(sig, &siginfo))
+ return;
+ info = &siginfo;
+ }
/*
* Process according to thread state:
*/
switch (pthread->state) {
- /*
- * States which do not change when a signal is trapped:
- */
case PS_DEAD:
case PS_DEADLOCK:
+ case PS_STATE_MAX:
+ return; /* XXX return false */
case PS_LOCKWAIT:
case PS_SUSPENDED:
- case PS_STATE_MAX:
/*
* You can't call a signal handler for threads in these
* states.
*/
suppress_handler = 1;
break;
-
- /*
- * States which do not need any cleanup handling when signals
- * occur:
- */
case PS_RUNNING:
- /*
- * Remove the thread from the queue before changing its
- * priority:
- */
- if ((pthread->flags & THR_FLAGS_IN_RUNQ) != 0)
+ if ((pthread->flags & THR_FLAGS_IN_RUNQ)) {
THR_RUNQ_REMOVE(pthread);
+ pthread->active_priority |= THR_SIGNAL_PRIORITY;
+ THR_RUNQ_INSERT_TAIL(pthread);
+ } else {
+ /* Possible not in RUNQ and has curframe ? */
+ pthread->active_priority |= THR_SIGNAL_PRIORITY;
+ }
+ suppress_handler = 1;
break;
-
/*
* States which cannot be interrupted but still require the
* signal handler to run:
*/
case PS_COND_WAIT:
case PS_MUTEX_WAIT:
- /*
- * Remove the thread from the wait queue. It will
- * be added back to the wait queue once all signal
- * handlers have been invoked.
- */
- KSE_WAITQ_REMOVE(pthread->kse, pthread);
break;
case PS_SLEEP_WAIT:
@@ -671,60 +729,64 @@ _thr_sig_add(struct pthread *pthread, int sig, siginfo_t *info)
* early regardless of SA_RESTART:
*/
pthread->interrupted = 1;
- KSE_WAITQ_REMOVE(pthread->kse, pthread);
- THR_SET_STATE(pthread, PS_RUNNING);
break;
case PS_JOIN:
+ break;
+
case PS_SIGSUSPEND:
- KSE_WAITQ_REMOVE(pthread->kse, pthread);
- THR_SET_STATE(pthread, PS_RUNNING);
+ pthread->interrupted = 1;
break;
case PS_SIGWAIT:
+ if (info == NULL)
+ build_siginfo(&pthread->siginfo[sig], sig);
+ else if (info != &pthread->siginfo[sig])
+ memcpy(&pthread->siginfo[sig], info,
+ sizeof(*info));
/*
* The signal handler is not called for threads in
* SIGWAIT.
*/
suppress_handler = 1;
- /* Wake up the thread if the signal is blocked. */
- if (sigismember(pthread->data.sigwait, sig)) {
+ /* Wake up the thread if the signal is not blocked. */
+ if (!SIGISMEMBER(pthread->sigmask, sig)) {
/* Return the signal number: */
- pthread->signo = sig;
-
+ *(pthread->data.sigwaitinfo) = pthread->siginfo[sig];
+ pthread->sigmask = pthread->oldsigmask;
/* Make the thread runnable: */
_thr_setrunnable_unlocked(pthread);
- } else
+ } else {
/* Increment the pending signal count. */
- sigaddset(&pthread->sigpend, sig);
- break;
+ SIGADDSET(pthread->sigpend, sig);
+ pthread->check_pending = 1;
+ }
+
+ return;
}
+ SIGADDSET(pthread->sigpend, sig);
+ if (info == NULL)
+ build_siginfo(&pthread->siginfo[sig], sig);
+ else if (info != &pthread->siginfo[sig])
+ memcpy(&pthread->siginfo[sig], info, sizeof(*info));
+
if (suppress_handler == 0) {
/*
* Setup a signal frame and save the current threads
* state:
*/
- thr_sigframe_add(pthread, sig, info);
-
- if (pthread->state != PS_RUNNING)
- THR_SET_STATE(pthread, PS_RUNNING);
-
- /*
- * The thread should be removed from all scheduling
- * queues at this point. Raise the priority and
- * place the thread in the run queue. It is also
- * possible for a signal to be sent to a suspended
- * thread, mostly via pthread_kill(). If a thread
- * is suspended, don't insert it into the priority
- * queue; just set its state to suspended and it
- * will run the signal handler when it is resumed.
- */
+ thr_sigframe_add(pthread);
+ if (pthread->flags & THR_FLAGS_IN_RUNQ)
+ THR_RUNQ_REMOVE(pthread);
pthread->active_priority |= THR_SIGNAL_PRIORITY;
- if ((pthread->flags & THR_FLAGS_IN_RUNQ) == 0)
- THR_RUNQ_INSERT_TAIL(pthread);
+ _thr_setrunnable_unlocked(pthread);
+ } else {
+ pthread->check_pending = 1;
}
}
+
+ DBG_MSG("<<< _thr_sig_add\n");
}
static void
@@ -749,16 +811,19 @@ thr_sig_check_state(struct pthread *pthread, int sig)
break;
case PS_SIGWAIT:
+ build_siginfo(&pthread->siginfo[sig], sig);
/* Wake up the thread if the signal is blocked. */
- if (sigismember(pthread->data.sigwait, sig)) {
+ if (!SIGISMEMBER(pthread->sigmask, sig)) {
/* Return the signal number: */
- pthread->signo = sig;
-
+ *(pthread->data.sigwaitinfo) = pthread->siginfo[sig];
+ pthread->sigmask = pthread->oldsigmask;
/* Change the state of the thread to run: */
_thr_setrunnable_unlocked(pthread);
- } else
+ } else {
/* Increment the pending signal count. */
- sigaddset(&pthread->sigpend, sig);
+ SIGADDSET(pthread->sigpend, sig);
+ pthread->check_pending = 1;
+ }
break;
case PS_SIGSUSPEND:
@@ -783,6 +848,12 @@ _thr_sig_send(struct pthread *pthread, int sig)
{
struct pthread *curthread = _get_curthread();
+#ifdef NOTYET
+ if ((pthread->attr.flags & PTHREAD_SCOPE_SYSTEM) == 0) {
+ kse_thr_interrupt(&pthread->tmbx, sig);
+ return;
+ }
+#endif
/* Lock the scheduling queue of the target thread. */
THR_SCHED_LOCK(curthread, pthread);
@@ -792,7 +863,7 @@ _thr_sig_send(struct pthread *pthread, int sig)
* Check to see if a temporary signal handler is
* installed for sigwaiters:
*/
- if (_thread_dfl_count[sig] == 0) {
+ if (_thread_dfl_count[sig - 1] == 0) {
/*
* Deliver the signal to the process if a handler
* is not installed:
@@ -812,87 +883,47 @@ _thr_sig_send(struct pthread *pthread, int sig)
* Check that the signal is not being ignored:
*/
else if (_thread_sigact[sig - 1].sa_handler != SIG_IGN) {
- if (pthread->state == PS_SIGWAIT &&
- sigismember(pthread->data.sigwait, sig)) {
- /* Return the signal number: */
- pthread->signo = sig;
-
- /* Change the state of the thread to run: */
- _thr_setrunnable_unlocked(pthread);
- THR_SCHED_UNLOCK(curthread, pthread);
- } else if (sigismember(&pthread->tmbx.tm_context.uc_sigmask, sig)) {
- /* Add the signal to the pending set: */
- sigaddset(&pthread->sigpend, sig);
- THR_SCHED_UNLOCK(curthread, pthread);
- } else if (pthread == curthread) {
- ucontext_t uc;
- siginfo_t info;
- volatile int once;
-
- THR_SCHED_UNLOCK(curthread, pthread);
- build_siginfo(&info, sig);
- once = 0;
- THR_GETCONTEXT(&uc);
- if (once == 0) {
- once = 1;
- /*
- * Call the signal handler for the current
- * thread:
- */
- thr_sig_invoke_handler(curthread, sig,
- &info, &uc);
- }
- } else {
- /*
- * Perform any state changes due to signal
- * arrival:
- */
- _thr_sig_add(pthread, sig, NULL);
- THR_SCHED_UNLOCK(curthread, pthread);
- }
+ _thr_sig_add(pthread, sig, NULL);
+ THR_SCHED_UNLOCK(curthread, pthread);
+ /* XXX
+ * If thread sent signal to itself, check signals now.
+ * It is not really needed, _kse_critical_leave should
+ * have already checked signals.
+ */
+ if (pthread == curthread && curthread->check_pending)
+ _thr_sig_check_pending(curthread);
+ } else {
+ THR_SCHED_UNLOCK(curthread, pthread);
}
}
static void
-thr_sigframe_add(struct pthread *thread, int sig, siginfo_t *info)
+thr_sigframe_add(struct pthread *thread)
{
if (thread->curframe == NULL)
PANIC("Thread doesn't have signal frame ");
- if (thread->have_signals == 0) {
+ if (thread->curframe->psf_valid == 0) {
+ thread->curframe->psf_valid = 1;
/*
* Multiple signals can be added to the same signal
* frame. Only save the thread's state the first time.
*/
thr_sigframe_save(thread, thread->curframe);
- thread->have_signals = 1;
- thread->flags &= THR_FLAGS_PRIVATE;
}
- sigaddset(&thread->curframe->psf_sigset, sig);
- if (info == NULL)
- build_siginfo(&thread->siginfo[sig], sig);
- else if (info != &thread->siginfo[sig])
- memcpy(&thread->siginfo[sig], info, sizeof(*info));
-
- /* Setup the new signal mask. */
- SIGSETOR(thread->tmbx.tm_context.uc_sigmask,
- _thread_sigact[sig - 1].sa_mask);
- sigaddset(&thread->tmbx.tm_context.uc_sigmask, sig);
}
-void
+static void
thr_sigframe_restore(struct pthread *thread, struct pthread_sigframe *psf)
{
+ if (psf->psf_valid == 0)
+ PANIC("invalid pthread_sigframe\n");
thread->flags = psf->psf_flags;
thread->interrupted = psf->psf_interrupted;
thread->signo = psf->psf_signo;
thread->state = psf->psf_state;
thread->data = psf->psf_wait_data;
thread->wakeup_time = psf->psf_wakeup_time;
- if (thread->sigmask_seqno == psf->psf_seqno)
- thread->tmbx.tm_context.uc_sigmask = psf->psf_sigmask;
- else
- thread->tmbx.tm_context.uc_sigmask = thread->sigmask;
}
static void
@@ -906,7 +937,74 @@ thr_sigframe_save(struct pthread *thread, struct pthread_sigframe *psf)
psf->psf_state = thread->state;
psf->psf_wait_data = thread->data;
psf->psf_wakeup_time = thread->wakeup_time;
- psf->psf_sigmask = thread->tmbx.tm_context.uc_sigmask;
- psf->psf_seqno = thread->sigmask_seqno;
- sigemptyset(&psf->psf_sigset);
}
+
+void
+_thr_signal_init(void)
+{
+ sigset_t sigset;
+ struct sigaction act;
+ int i;
+
+ SIGFILLSET(sigset);
+ __sys_sigprocmask(SIG_SETMASK, &sigset, &_thr_initial->sigmask);
+ /* Enter a loop to get the existing signal status: */
+ for (i = 1; i <= _SIG_MAXSIG; i++) {
+ /* Check for signals which cannot be trapped: */
+ if (i == SIGKILL || i == SIGSTOP) {
+ }
+
+ /* Get the signal handler details: */
+ else if (__sys_sigaction(i, NULL,
+ &_thread_sigact[i - 1]) != 0) {
+ /*
+ * Abort this process if signal
+ * initialisation fails:
+ */
+ PANIC("Cannot read signal handler info");
+ }
+ }
+ /*
+ * Install the signal handler for SIGINFO. It isn't
+ * really needed, but it is nice to have for debugging
+ * purposes.
+ */
+ _thread_sigact[SIGINFO - 1].sa_flags = SA_SIGINFO | SA_RESTART;
+ SIGEMPTYSET(act.sa_mask);
+ act.sa_flags = SA_SIGINFO | SA_RESTART;
+ act.sa_sigaction = (__siginfohandler_t *)&_thr_sig_handler;
+ if (__sys_sigaction(SIGINFO, &act, NULL) != 0) {
+ /*
+ * Abort this process if signal initialisation fails:
+ */
+ PANIC("Cannot initialize signal handler");
+ }
+}
+
+void
+_thr_signal_deinit(void)
+{
+ sigset_t tmpmask, oldmask;
+ int i;
+
+ SIGFILLSET(tmpmask);
+ SIG_CANTMASK(tmpmask);
+ __sys_sigprocmask(SIG_SETMASK, &tmpmask, &oldmask);
+ /* Enter a loop to get the existing signal status: */
+ for (i = 1; i <= _SIG_MAXSIG; i++) {
+ /* Check for signals which cannot be trapped: */
+ if (i == SIGKILL || i == SIGSTOP) {
+ }
+
+ /* Set the signal handler details: */
+ else if (__sys_sigaction(i, &_thread_sigact[i - 1], NULL) != 0) {
+ /*
+ * Abort this process if signal
+ * initialisation fails:
+ */
+ PANIC("Cannot set signal handler info");
+ }
+ }
+ __sys_sigprocmask(SIG_SETMASK, &oldmask, NULL);
+}
+
diff --git a/lib/libkse/thread/thr_sigaction.c b/lib/libkse/thread/thr_sigaction.c
index 7ede6d2..2bef7f2 100644
--- a/lib/libkse/thread/thr_sigaction.c
+++ b/lib/libkse/thread/thr_sigaction.c
@@ -43,16 +43,21 @@ _sigaction(int sig, const struct sigaction * act, struct sigaction * oact)
{
int ret = 0;
struct sigaction gact;
+ struct pthread *curthread;
+ kse_critical_t crit;
/* Check if the signal number is out of range: */
- if (sig < 1 || sig > NSIG) {
+ if (sig < 1 || sig > _SIG_MAXSIG) {
/* Return an invalid argument: */
errno = EINVAL;
ret = -1;
} else {
- if (_thr_initial == NULL)
- _libpthread_init(NULL);
+ if (!_kse_isthreaded())
+ return __sys_sigaction(sig, act, oact);
+ crit = _kse_critical_enter();
+ curthread = _get_curthread();
+ KSE_LOCK_ACQUIRE(curthread->kse, &_thread_signal_lock);
/*
* Check if the existing signal action structure contents are
* to be returned:
@@ -99,6 +104,8 @@ _sigaction(int sig, const struct sigaction * act, struct sigaction * oact)
if (__sys_sigaction(sig, &gact, NULL) != 0)
ret = -1;
}
+ KSE_LOCK_RELEASE(curthread->kse, &_thread_signal_lock);
+ _kse_critical_leave(crit);
}
/* Return the completion status: */
diff --git a/lib/libkse/thread/thr_sigmask.c b/lib/libkse/thread/thr_sigmask.c
index d9cb839..c8fcec8 100644
--- a/lib/libkse/thread/thr_sigmask.c
+++ b/lib/libkse/thread/thr_sigmask.c
@@ -48,33 +48,35 @@ _pthread_sigmask(int how, const sigset_t *set, sigset_t *oset)
struct pthread *curthread = _get_curthread();
int ret;
+ if (! _kse_isthreaded())
+ _kse_setthreaded(1);
+
+ THR_SCHED_LOCK(curthread, curthread);
ret = 0;
if (oset != NULL)
/* Return the current mask: */
- *oset = curthread->tmbx.tm_context.uc_sigmask;
+ *oset = curthread->sigmask;
/* Check if a new signal set was provided by the caller: */
if (set != NULL) {
- THR_SCHED_LOCK(curthread, curthread);
-
/* Process according to what to do: */
switch (how) {
/* Block signals: */
case SIG_BLOCK:
/* Add signals to the existing mask: */
- SIGSETOR(curthread->tmbx.tm_context.uc_sigmask, *set);
+ SIGSETOR(curthread->sigmask, *set);
break;
/* Unblock signals: */
case SIG_UNBLOCK:
/* Clear signals from the existing mask: */
- SIGSETNAND(curthread->tmbx.tm_context.uc_sigmask, *set);
+ SIGSETNAND(curthread->sigmask, *set);
break;
/* Set the signal process mask: */
case SIG_SETMASK:
/* Set the new mask: */
- curthread->tmbx.tm_context.uc_sigmask = *set;
+ curthread->sigmask = *set;
break;
/* Trap invalid actions: */
@@ -84,13 +86,7 @@ _pthread_sigmask(int how, const sigset_t *set, sigset_t *oset)
ret = -1;
break;
}
-
- if (ret == 0) {
- curthread->sigmask =
- curthread->tmbx.tm_context.uc_sigmask;
- curthread->sigmask_seqno++;
- }
-
+ SIG_CANTMASK(curthread->sigmask);
THR_SCHED_UNLOCK(curthread, curthread);
/*
@@ -98,6 +94,7 @@ _pthread_sigmask(int how, const sigset_t *set, sigset_t *oset)
*/
if (ret == 0)
_thr_sig_check_pending(curthread);
- }
+ } else
+ THR_SCHED_UNLOCK(curthread, curthread);
return (ret);
}
diff --git a/lib/libkse/thread/thr_sigpending.c b/lib/libkse/thread/thr_sigpending.c
index 7f42ff3..1b9b502 100644
--- a/lib/libkse/thread/thr_sigpending.c
+++ b/lib/libkse/thread/thr_sigpending.c
@@ -54,8 +54,13 @@ _sigpending(sigset_t *set)
ret = EINVAL;
}
else {
- *set = curthread->sigpend;
+ if (!_kse_isthreaded())
+ return __sys_sigpending(set);
+
crit = _kse_critical_enter();
+ KSE_SCHED_LOCK(curthread->kse, curthread->kseg);
+ *set = curthread->sigpend;
+ KSE_SCHED_UNLOCK(curthread->kse, curthread->kseg);
KSE_LOCK_ACQUIRE(curthread->kse, &_thread_signal_lock);
SIGSETOR(*set, _thr_proc_sigpending);
KSE_LOCK_RELEASE(curthread->kse, &_thread_signal_lock);
diff --git a/lib/libkse/thread/thr_sigprocmask.c b/lib/libkse/thread/thr_sigprocmask.c
index 9cb493a..262848a 100644
--- a/lib/libkse/thread/thr_sigprocmask.c
+++ b/lib/libkse/thread/thr_sigprocmask.c
@@ -46,8 +46,9 @@ _sigprocmask(int how, const sigset_t *set, sigset_t *oset)
{
int ret;
- ret = pthread_sigmask(how, set, oset);
- if ((ret == 0) && (_kse_isthreaded() == 0))
+ if (_kse_isthreaded() == 0)
ret = __sys_sigprocmask(how, set, oset);
+ else
+ ret = pthread_sigmask(how, set, oset);
return (ret);
}
diff --git a/lib/libkse/thread/thr_sigsuspend.c b/lib/libkse/thread/thr_sigsuspend.c
index 2da790d..8d087f5 100644
--- a/lib/libkse/thread/thr_sigsuspend.c
+++ b/lib/libkse/thread/thr_sigsuspend.c
@@ -44,14 +44,19 @@ _sigsuspend(const sigset_t *set)
{
struct pthread *curthread = _get_curthread();
int ret = -1;
+ sigset_t osigmask;
+
+ if (!_kse_isthreaded())
+ return __sys_sigsuspend(set);
/* Check if a new signal set was provided by the caller: */
if (set != NULL) {
THR_LOCK_SWITCH(curthread);
+ /* Save current sigmask */
+ memcpy(&osigmask, &curthread->sigmask, sizeof(osigmask));
/* Change the caller's mask: */
- memcpy(&curthread->tmbx.tm_context.uc_sigmask,
- set, sizeof(sigset_t));
+ memcpy(&curthread->sigmask, set, sizeof(sigset_t));
THR_SET_STATE(curthread, PS_SIGSUSPEND);
@@ -61,9 +66,15 @@ _sigsuspend(const sigset_t *set)
/* Always return an interrupted error: */
errno = EINTR;
+ THR_SCHED_LOCK(curthread, curthread);
/* Restore the signal mask: */
- memcpy(&curthread->tmbx.tm_context.uc_sigmask,
- &curthread->sigmask, sizeof(sigset_t));
+ memcpy(&curthread->sigmask, &osigmask, sizeof(sigset_t));
+ THR_SCHED_UNLOCK(curthread, curthread);
+ /*
+ * signal mask is reloaded, need to check if there is
+ * pending proc signal I can handle.
+ */
+ _thr_sig_check_pending(curthread);
} else {
/* Return an invalid argument error: */
errno = EINVAL;
diff --git a/lib/libkse/thread/thr_sigwait.c b/lib/libkse/thread/thr_sigwait.c
index c8c7762..4b9cb69 100644
--- a/lib/libkse/thread/thr_sigwait.c
+++ b/lib/libkse/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);
}
+
diff --git a/lib/libpthread/pthread.map b/lib/libpthread/pthread.map
index 1a4d540..c7bb4e4 100644
--- a/lib/libpthread/pthread.map
+++ b/lib/libpthread/pthread.map
@@ -138,6 +138,8 @@ global:
_sigprocmask;
_sigsuspend;
_sigwait;
+ _sigtimedwait;
+ _sigwaitinfo;
_sleep;
_spinlock;
_spinlock_debug;
@@ -271,6 +273,8 @@ global:
sigprocmask;
sigsuspend;
sigwait;
+ sigwaitinfo;
+ sigtimedwait;
sleep;
system;
tcdrain;
diff --git a/lib/libpthread/support/thr_support.c b/lib/libpthread/support/thr_support.c
index 1b3c4ef..ad40fec 100644
--- a/lib/libpthread/support/thr_support.c
+++ b/lib/libpthread/support/thr_support.c
@@ -54,5 +54,8 @@ __strong_reference(memcpy, _thr_memcpy);
__strong_reference(strcpy, _thr_strcpy);
__strong_reference(strlen, _thr_strlen);
__strong_reference(bzero, _thr_bzero);
+__strong_reference(bcopy, _thr_bcopy);
__strong_reference(__sys_write, _thr__sys_write);
+__strong_reference(__sys_sigtimedwait, _thr__sys_sigtimedwait);
+
diff --git a/lib/libpthread/thread/thr_info.c b/lib/libpthread/thread/thr_info.c
index 3218b5b..4410ace 100644
--- a/lib/libpthread/thread/thr_info.c
+++ b/lib/libpthread/thread/thr_info.c
@@ -77,7 +77,7 @@ _thread_dump_info(void)
int fd, i;
for (i = 0; i < 100000; i++) {
- snprintf(tmpfile, sizeof(tmpfile), "/tmp/uthread.dump.%u.%i",
+ snprintf(tmpfile, sizeof(tmpfile), "/tmp/pthread.dump.%u.%i",
getpid(), i);
/* Open the dump file for append and create it if necessary: */
if ((fd = __sys_open(tmpfile, O_RDWR | O_CREAT | O_EXCL,
@@ -166,6 +166,12 @@ dump_thread(int fd, pthread_t pthread, int long_version)
strcpy(s, "This is the initial thread\n");
__sys_write(fd, s, strlen(s));
}
+ /* Check if this is the signal daemon thread: */
+ if (pthread == _thr_sig_daemon) {
+ /* Output a record for the signal thread: */
+ strcpy(s, "This is the signal daemon thread\n");
+ __sys_write(fd, s, strlen(s));
+ }
/* Process according to thread state: */
switch (pthread->state) {
case PS_SIGWAIT:
@@ -173,6 +179,15 @@ dump_thread(int fd, pthread_t pthread, int long_version)
__sys_write(fd, s, strlen(s));
for (i = _SIG_WORDS - 1; i >= 0; i--) {
snprintf(s, sizeof(s), "%08x\n",
+ pthread->oldsigmask.__bits[i]);
+ __sys_write(fd, s, strlen(s));
+ }
+ snprintf(s, sizeof(s), "(lo)\n");
+ __sys_write(fd, s, strlen(s));
+ snprintf(s, sizeof(s), "waitset (hi)");
+ __sys_write(fd, s, strlen(s));
+ for (i = _SIG_WORDS - 1; i >= 0; i--) {
+ snprintf(s, sizeof(s), "%08x\n",
pthread->sigmask.__bits[i]);
__sys_write(fd, s, strlen(s));
}
diff --git a/lib/libpthread/thread/thr_init.c b/lib/libpthread/thread/thr_init.c
index 227bdf3..202db62 100644
--- a/lib/libpthread/thread/thr_init.c
+++ b/lib/libpthread/thread/thr_init.c
@@ -39,6 +39,7 @@
#include "namespace.h"
#include <sys/param.h>
#include <sys/types.h>
+#include <sys/signalvar.h>
#include <machine/reg.h>
#include <sys/ioctl.h>
@@ -304,7 +305,7 @@ _libpthread_init(struct pthread *curthread)
_thr_initial->kse->k_curthread = _thr_initial;
_thr_initial->kse->k_flags |= KF_INITIALIZED;
_kse_initial->k_curthread = _thr_initial;
-
+
_thr_rtld_init();
}
@@ -365,14 +366,13 @@ init_main_thread(struct pthread *thread)
thread->name = strdup("initial thread");
/* Initialize the thread for signals: */
- sigemptyset(&thread->sigmask);
+ SIGEMPTYSET(thread->sigmask);
/*
* Set up the thread mailbox. The threads saved context
* is also in the mailbox.
*/
thread->tmbx.tm_udata = thread;
- thread->tmbx.tm_context.uc_sigmask = thread->sigmask;
thread->tmbx.tm_context.uc_stack.ss_size = thread->attr.stacksize_attr;
thread->tmbx.tm_context.uc_stack.ss_sp = thread->attr.stackaddr_attr;
@@ -407,10 +407,8 @@ static void
init_private(void)
{
struct clockinfo clockinfo;
- struct sigaction act;
size_t len;
int mib[2];
- int i;
/*
* Avoid reinitializing some things if they don't need to be,
@@ -448,36 +446,6 @@ init_private(void)
_thr_page_size = getpagesize();
_thr_guard_default = _thr_page_size;
-
- /* Enter a loop to get the existing signal status: */
- for (i = 1; i < NSIG; i++) {
- /* Check for signals which cannot be trapped: */
- if (i == SIGKILL || i == SIGSTOP) {
- }
-
- /* Get the signal handler details: */
- else if (__sys_sigaction(i, NULL,
- &_thread_sigact[i - 1]) != 0) {
- /*
- * Abort this process if signal
- * initialisation fails:
- */
- PANIC("Cannot read signal handler info");
- }
- }
- /*
- * Install the signal handler for SIGINFO. It isn't
- * really needed, but it is nice to have for debugging
- * purposes.
- */
- if (__sys_sigaction(SIGINFO, &act, NULL) != 0) {
- /*
- * Abort this process if signal initialisation fails:
- */
- PANIC("Cannot initialize signal handler");
- }
- _thread_sigact[SIGINFO - 1].sa_flags = SA_SIGINFO | SA_RESTART;
-
init_once = 1; /* Don't do this again. */
} else {
/*
@@ -495,8 +463,6 @@ init_private(void)
TAILQ_INIT(&_thread_list);
TAILQ_INIT(&_thread_gc_list);
- /* Enter a loop to get the existing signal status: */
-
/* Initialize the SIG_DFL dummy handler count. */
bzero(_thread_dfl_count, sizeof(_thread_dfl_count));
@@ -520,8 +486,7 @@ init_private(void)
_thr_spinlock_init();
/* Clear pending signals and get the process signal mask. */
- sigemptyset(&_thr_proc_sigpending);
- __sys_sigprocmask(SIG_SETMASK, NULL, &_thr_proc_sigmask);
+ SIGEMPTYSET(_thr_proc_sigpending);
/*
* _thread_list_lock and _kse_count are initialized
diff --git a/lib/libpthread/thread/thr_kern.c b/lib/libpthread/thread/thr_kern.c
index d1a2006..8a1ecc3 100644
--- a/lib/libpthread/thread/thr_kern.c
+++ b/lib/libpthread/thread/thr_kern.c
@@ -40,6 +40,7 @@ __FBSDID("$FreeBSD$");
#include <sys/signalvar.h>
#include <sys/queue.h>
#include <machine/atomic.h>
+#include <machine/sigframe.h>
#include <assert.h>
#include <errno.h>
@@ -125,7 +126,6 @@ static void dump_queues(struct kse *curkse);
#endif
static void kse_check_completed(struct kse *kse);
static void kse_check_waitq(struct kse *kse);
-static void kse_check_signals(struct kse *kse);
static void kse_fini(struct kse *curkse);
static void kse_reinit(struct kse *kse);
static void kse_sched_multi(struct kse *curkse);
@@ -143,27 +143,39 @@ static void kse_wakeup_multi(struct kse *curkse);
static void kse_wakeup_one(struct pthread *thread);
static void thr_cleanup(struct kse *kse, struct pthread *curthread);
static void thr_link(struct pthread *thread);
-static void thr_resume_wrapper(int unused_1, siginfo_t *unused_2,
- ucontext_t *ucp);
+static void thr_resume_wrapper(int sig, siginfo_t *, ucontext_t *);
static void thr_resume_check(struct pthread *curthread, ucontext_t *ucp,
struct pthread_sigframe *psf);
static int thr_timedout(struct pthread *thread, struct timespec *curtime);
static void thr_unlink(struct pthread *thread);
+
/*
* This is called after a fork().
* No locks need to be taken here since we are guaranteed to be
* single threaded.
+ *
+ * XXX
+ * POSIX says for threaded process, fork() function is used
+ * only to run new programs, and the effects of calling functions
+ * that require certain resources between the call to fork() and
+ * the call to an exec function are undefined.
+ *
+ * Here it is not safe to reinitialize the library after fork().
+ * Because memory management may be corrupted, further calling
+ * malloc()/free() may cause undefined behavior.
*/
void
_kse_single_thread(struct pthread *curthread)
{
+#ifdef NOTYET
struct kse *kse;
struct kse_group *kseg;
struct pthread *thread;
kse_critical_t crit;
int i;
+
/*
* Disable upcalls and clear the threaded flag.
* XXX - I don't think we need to disable upcalls after a fork().
@@ -172,6 +184,7 @@ _kse_single_thread(struct pthread *curthread)
crit = _kse_critical_enter();
__isthreaded = 0;
active_threads = 1;
+ _thr_signal_deinit();
/*
* Enter a loop to remove and free all threads other than
@@ -201,7 +214,7 @@ _kse_single_thread(struct pthread *curthread)
TAILQ_INIT(&curthread->mutexq); /* initialize mutex queue */
curthread->joiner = NULL; /* no joining threads yet */
curthread->refcount = 0;
- sigemptyset(&curthread->sigpend); /* clear pending signals */
+ SIGEMPTYSET(curthread->sigpend); /* clear pending signals */
if (curthread->specific != NULL) {
free(curthread->specific);
curthread->specific = NULL;
@@ -307,6 +320,12 @@ _kse_single_thread(struct pthread *curthread)
curthread->kseg = NULL;
_kse_initial = NULL;
_libpthread_init(curthread);
+#else
+ _ksd_readandclear_tmbx();
+ __isthreaded = 0;
+ active_threads = 0;
+ _thr_signal_deinit();
+#endif
}
/*
@@ -363,15 +382,17 @@ _kse_setthreaded(int threaded)
* Tell the kernel to create a KSE for the initial thread
* and enable upcalls in it.
*/
+ _thr_signal_init();
_kse_initial->k_flags |= KF_STARTED;
if (kse_create(&_kse_initial->k_mbx, 0) != 0) {
_kse_initial->k_flags &= ~KF_STARTED;
__isthreaded = 0;
/* may abort() */
- DBG_MSG("kse_create failed\n");
+ PANIC("kse_create() failed\n");
return (-1);
}
KSE_SET_MBOX(_kse_initial, _thr_initial);
+ _thr_start_sig_daemon();
_thr_setmaxconcurrency();
}
return (0);
@@ -536,6 +557,7 @@ _thr_sched_switch_unlocked(struct pthread *curthread)
int ret;
volatile int uts_once;
volatile int resume_once = 0;
+ ucontext_t uc;
/* We're in the scheduler, 5 by 5: */
curkse = _get_curkse();
@@ -552,7 +574,7 @@ _thr_sched_switch_unlocked(struct pthread *curthread)
* a thread can be interrupted by other signals while
* it is running down pending signals.
*/
- sigemptyset(&psf.psf_sigset);
+ psf.psf_valid = 0;
curthread->curframe = &psf;
/*
@@ -561,6 +583,8 @@ _thr_sched_switch_unlocked(struct pthread *curthread)
* o The current thread is dead; it's stack needs to be
* cleaned up and it can't be done while operating on
* it.
+ * o The current thread has signals pending, should
+ * let scheduler install signal trampoline for us.
* o There are no runnable threads.
* o The next thread to run won't unlock the scheduler
* lock. A side note: the current thread may be run
@@ -570,8 +594,10 @@ _thr_sched_switch_unlocked(struct pthread *curthread)
if ((curthread->state == PS_DEAD) ||
(((td = KSE_RUNQ_FIRST(curkse)) == NULL) &&
(curthread->state != PS_RUNNING)) ||
- ((td != NULL) && (td->lock_switch == 0)))
+ ((td != NULL) && (td->lock_switch == 0))) {
+ curkse->k_switch = 1;
_thread_enter_uts(&curthread->tmbx, &curkse->k_mbx);
+ }
else {
uts_once = 0;
THR_GETCONTEXT(&curthread->tmbx.tm_context);
@@ -623,6 +649,15 @@ _thr_sched_switch_unlocked(struct pthread *curthread)
}
}
+ if (psf.psf_valid) {
+ /*
+ * It is ugly we must increase critical count, because we
+ * have a frame saved, we must backout state in psf
+ * before we can process signals.
+ */
+ curthread->critical_count++;
+ }
+
if (curthread->lock_switch != 0) {
/*
* Unlock the scheduling queue and leave the
@@ -638,11 +673,15 @@ _thr_sched_switch_unlocked(struct pthread *curthread)
/*
* This thread is being resumed; check for cancellations.
*/
- if ((resume_once == 0) && (!THR_IN_CRITICAL(curthread))) {
- resume_once = 1;
- thr_resume_check(curthread, &curthread->tmbx.tm_context, &psf);
+ if ((psf.psf_valid || curthread->check_pending)) {
+ resume_once = 0;
+ THR_GETCONTEXT(&uc);
+ if (resume_once == 0) {
+ resume_once = 1;
+ curthread->check_pending = 0;
+ thr_resume_check(curthread, &uc, &psf);
+ }
}
-
THR_ACTIVATE_LAST_LOCK(curthread);
}
@@ -747,9 +786,6 @@ kse_sched_single(struct kse *curkse)
KSE_WAITQ_REMOVE(curkse, td_wait);
}
}
- KSE_SCHED_UNLOCK(curkse, curkse->k_kseg);
- kse_check_signals(curkse);
- KSE_SCHED_LOCK(curkse, curkse->k_kseg);
}
/* Remove the frame reference. */
@@ -810,12 +846,12 @@ kse_sched_multi(struct kse *curkse)
KSE_CLEAR_WAIT(curkse);
}
- /* Lock the scheduling lock. */
- curthread = curkse->k_curthread;
- if ((curthread == NULL) || (curthread->need_switchout == 0)) {
- /* This is an upcall; take the scheduler lock. */
+ /*If this is an upcall; take the scheduler lock. */
+ if (curkse->k_switch == 0)
KSE_SCHED_LOCK(curkse, curkse->k_kseg);
- }
+ curkse->k_switch = 0;
+
+ curthread = curkse->k_curthread;
if (KSE_IS_IDLE(curkse)) {
KSE_CLEAR_IDLE(curkse);
@@ -879,11 +915,6 @@ kse_sched_multi(struct kse *curkse)
kse_wakeup_multi(curkse);
- /* This has to be done without the scheduling lock held. */
- KSE_SCHED_UNLOCK(curkse, curkse->k_kseg);
- kse_check_signals(curkse);
- KSE_SCHED_LOCK(curkse, curkse->k_kseg);
-
#ifdef DEBUG_THREAD_KERN
dump_queues(curkse);
#endif
@@ -899,9 +930,6 @@ kse_sched_multi(struct kse *curkse)
kse_wait(curkse, td_wait);
kse_check_completed(curkse);
kse_check_waitq(curkse);
- KSE_SCHED_UNLOCK(curkse, curkse->k_kseg);
- kse_check_signals(curkse);
- KSE_SCHED_LOCK(curkse, curkse->k_kseg);
}
/* Check for no more threads: */
@@ -966,15 +994,19 @@ kse_sched_multi(struct kse *curkse)
* signal frame to the thread's context.
*/
#ifdef NOT_YET
- if ((curframe == NULL) && ((curthread->have_signals != 0) ||
+ if ((((curframe == NULL) && (curthread->check_pending != 0)) ||
(((curthread->cancelflags & THR_AT_CANCEL_POINT) == 0) &&
- ((curthread->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS) != 0))))
+ ((curthread->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS) != 0))) &&
+ !THR_IN_CRITICAL(curthread))
signalcontext(&curthread->tmbx.tm_context, 0,
(__sighandler_t *)thr_resume_wrapper);
#else
- if ((curframe == NULL) && (curthread->have_signals != 0))
+ if ((curframe == NULL) && (curthread->check_pending != 0) &&
+ !THR_IN_CRITICAL(curthread)) {
+ curthread->check_pending = 0;
signalcontext(&curthread->tmbx.tm_context, 0,
(__sighandler_t *)thr_resume_wrapper);
+ }
#endif
/*
* Continue the thread at its current frame:
@@ -999,61 +1031,31 @@ kse_sched_multi(struct kse *curkse)
}
static void
-kse_check_signals(struct kse *curkse)
-{
- sigset_t sigset;
- int i;
-
- /* Deliver posted signals. */
- for (i = 0; i < _SIG_WORDS; i++) {
- atomic_swap_int(&curkse->k_mbx.km_sigscaught.__bits[i],
- 0, &sigset.__bits[i]);
- }
- if (SIGNOTEMPTY(sigset)) {
- /*
- * Dispatch each signal.
- *
- * XXX - There is no siginfo for any of these.
- * I think there should be, especially for
- * signals from other processes (si_pid, si_uid).
- */
- for (i = 1; i < NSIG; i++) {
- if (sigismember(&sigset, i) != 0) {
- DBG_MSG("Dispatching signal %d\n", i);
- _thr_sig_dispatch(curkse, i,
- NULL /* no siginfo */);
- }
- }
- sigemptyset(&sigset);
- __sys_sigprocmask(SIG_SETMASK, &sigset, NULL);
- }
-}
-
-static void
-thr_resume_wrapper(int unused_1, siginfo_t *unused_2, ucontext_t *ucp)
+thr_resume_wrapper(int sig, siginfo_t *siginfo, ucontext_t *ucp)
{
struct pthread *curthread = _get_curthread();
+ struct kse *curkse;
+ int ret;
+ DBG_MSG(">>> sig wrapper\n");
+ if (curthread->lock_switch)
+ PANIC("thr_resume_wrapper, lock_switch != 0\n");
thr_resume_check(curthread, ucp, NULL);
+ _kse_critical_enter();
+ curkse = _get_curkse();
+ curthread->tmbx.tm_context = *ucp;
+ ret = _thread_switch(&curthread->tmbx, &curkse->k_mbx.km_curthread);
+ if (ret != 0)
+ PANIC("thr_resume_wrapper: thread has returned "
+ "from _thread_switch");
+ /* THR_SETCONTEXT(ucp); */ /* not work, why ? */
}
static void
thr_resume_check(struct pthread *curthread, ucontext_t *ucp,
struct pthread_sigframe *psf)
{
- /* Check signals before cancellations. */
- while (curthread->have_signals != 0) {
- /* Clear the pending flag. */
- curthread->have_signals = 0;
-
- /*
- * It's perfectly valid, though not portable, for
- * signal handlers to munge their interrupted context
- * and expect to return to it. Ensure we use the
- * correct context when running down signals.
- */
- _thr_sig_rundown(curthread, ucp, psf);
- }
+ _thr_sig_rundown(curthread, ucp, psf);
#ifdef NOT_YET
if (((curthread->cancelflags & THR_AT_CANCEL_POINT) == 0) &&
@@ -1124,7 +1126,7 @@ thr_cleanup(struct kse *curkse, struct pthread *thread)
THR_GCLIST_ADD(thread);
/* Use thread_list_lock */
active_threads--;
- if (active_threads == 0) {
+ if (active_threads == 1) {
KSE_LOCK_RELEASE(curkse, &_thread_list_lock);
exit(0);
}
@@ -1203,8 +1205,15 @@ _thr_gc(struct pthread *curthread)
KSE_LOCK_RELEASE(curthread->kse, &kse_lock);
_kse_critical_leave(crit);
}
- DBG_MSG("Freeing thread %p\n", td);
- _thr_free(curthread, td);
+ /*
+ * XXX we don't free initial thread, because there might
+ * have some code referencing initial thread.
+ */
+ if (td != _thr_initial) {
+ DBG_MSG("Freeing thread %p\n", td);
+ _thr_free(curthread, td);
+ } else
+ DBG_MSG("Initial thread won't be freed\n");
}
/* XXX free kse and ksegrp list should be looked as well */
}
@@ -1216,7 +1225,6 @@ _thr_gc(struct pthread *curthread)
int
_thr_schedule_add(struct pthread *curthread, struct pthread *newthread)
{
- struct kse *curkse;
kse_critical_t crit;
int ret;
@@ -1250,15 +1258,11 @@ _thr_schedule_add(struct pthread *curthread, struct pthread *newthread)
/*
* This thread needs a new KSE and KSEG.
*/
- crit = _kse_critical_enter();
- curkse = _get_curkse();
- _ksd_setprivate(&newthread->kse->k_ksd);
- newthread->kse->k_flags |= KF_INITIALIZED|KF_STARTED;
+ newthread->kse->k_flags &= ~KF_INITIALIZED;
+ newthread->kse->k_flags |= KF_STARTED;
ret = kse_create(&newthread->kse->k_mbx, 1);
if (ret != 0)
ret = errno;
- _ksd_setprivate(&curkse->k_ksd);
- _kse_critical_leave(crit);
}
else {
/*
@@ -1266,6 +1270,7 @@ _thr_schedule_add(struct pthread *curthread, struct pthread *newthread)
* assigned threads. If the new thread is runnable, also
* add it to the KSE's run queue.
*/
+ crit = _kse_critical_enter();
KSE_SCHED_LOCK(curthread->kse, newthread->kseg);
KSEG_THRQ_ADD(newthread->kseg, newthread);
if (newthread->state == PS_RUNNING)
@@ -1288,6 +1293,7 @@ _thr_schedule_add(struct pthread *curthread, struct pthread *newthread)
kse_wakeup_one(newthread);
}
KSE_SCHED_UNLOCK(curthread->kse, newthread->kseg);
+ _kse_critical_leave(crit);
ret = 0;
}
if (ret != 0)
@@ -1328,6 +1334,7 @@ kse_check_completed(struct kse *kse)
{
struct pthread *thread;
struct kse_thr_mailbox *completed;
+ int sig;
if ((completed = kse->k_mbx.km_completed) != NULL) {
kse->k_mbx.km_completed = NULL;
@@ -1348,6 +1355,13 @@ kse_check_completed(struct kse *kse)
thread->active = 0;
}
}
+ if ((sig = thread->tmbx.tm_syncsig.si_signo) != 0) {
+ if (SIGISMEMBER(thread->sigmask, sig))
+ SIGADDSET(thread->sigpend, sig);
+ else
+ _thr_sig_add(thread, sig, &thread->tmbx.tm_syncsig);
+ thread->tmbx.tm_syncsig.si_signo = 0;
+ }
completed = completed->tm_next;
}
}
@@ -1446,6 +1460,8 @@ kse_switchout_thread(struct kse *kse, struct pthread *thread)
{
int level;
int i;
+ int restart;
+ siginfo_t siginfo;
/*
* Place the currently running thread into the
@@ -1459,15 +1475,25 @@ kse_switchout_thread(struct kse *kse, struct pthread *thread)
thread->need_switchout = 0;
/* This thread must have blocked in the kernel. */
/* thread->slice_usec = -1;*/ /* restart timeslice */
- /*
- * XXX - Check for pending signals for this thread to
- * see if we need to interrupt it in the kernel.
- */
- /* if (thread->check_pending != 0) */
if ((thread->slice_usec != -1) &&
(thread->attr.sched_policy != SCHED_FIFO))
thread->slice_usec += (thread->tmbx.tm_uticks
+ thread->tmbx.tm_sticks) * _clock_res_usec;
+ /*
+ * Check for pending signals for this thread to
+ * see if we need to interrupt it in the kernel.
+ */
+ if (thread->check_pending != 0) {
+ for (i = 1; i <= _SIG_MAXSIG; ++i) {
+ if (SIGISMEMBER(thread->sigpend, i) &&
+ !SIGISMEMBER(thread->sigmask, i)) {
+ restart = _thread_sigact[1 - 1].sa_flags & SA_RESTART;
+ kse_thr_interrupt(&thread->tmbx,
+ restart ? -2 : -1);
+ break;
+ }
+ }
+ }
}
else {
switch (thread->state) {
@@ -1507,10 +1533,12 @@ kse_switchout_thread(struct kse *kse, struct pthread *thread)
THR_SET_STATE(thread, PS_RUNNING);
break;
+ case PS_SIGWAIT:
+ KSE_WAITQ_INSERT(kse, thread);
+ break;
case PS_JOIN:
case PS_MUTEX_WAIT:
case PS_SIGSUSPEND:
- case PS_SIGWAIT:
case PS_SUSPENDED:
case PS_DEADLOCK:
default:
@@ -1564,11 +1592,18 @@ kse_switchout_thread(struct kse *kse, struct pthread *thread)
if (thread->check_pending != 0) {
/* Install pending signals into the frame. */
thread->check_pending = 0;
- for (i = 0; i < _SIG_MAXSIG; i++) {
- if (sigismember(&thread->sigpend, i) &&
- !sigismember(&thread->tmbx.tm_context.uc_sigmask, i))
+ KSE_LOCK_ACQUIRE(kse, &_thread_signal_lock);
+ for (i = 1; i <= _SIG_MAXSIG; i++) {
+ if (SIGISMEMBER(thread->sigmask, i))
+ continue;
+ if (SIGISMEMBER(thread->sigpend, i))
_thr_sig_add(thread, i, &thread->siginfo[i]);
+ else if (SIGISMEMBER(_thr_proc_sigpending, i) &&
+ _thr_getprocsig_unlocked(i, &siginfo)) {
+ _thr_sig_add(thread, i, &siginfo);
+ }
}
+ KSE_LOCK_RELEASE(kse, &_thread_signal_lock);
}
}
@@ -2016,6 +2051,10 @@ _kse_alloc(struct pthread *curthread)
_lockuser_destroy(&kse->k_lockusers[i]);
}
free(kse);
+ if (curthread != NULL) {
+ KSE_LOCK_RELEASE(curthread->kse, &kse_lock);
+ _kse_critical_leave(crit);
+ }
return (NULL);
}
kse->k_flags = 0;
@@ -2044,7 +2083,7 @@ kse_reinit(struct kse *kse)
kse->k_kseg = 0;
kse->k_schedq = 0;
kse->k_locklevel = 0;
- sigemptyset(&kse->k_sigmask);
+ SIGEMPTYSET(kse->k_sigmask);
bzero(&kse->k_sigq, sizeof(kse->k_sigq));
kse->k_check_sigq = 0;
kse->k_flags = 0;
@@ -2053,6 +2092,7 @@ kse_reinit(struct kse *kse)
kse->k_error = 0;
kse->k_cpu = 0;
kse->k_done = 0;
+ kse->k_switch = 0;
}
void
@@ -2171,10 +2211,12 @@ thr_link(struct pthread *thread)
{
kse_critical_t crit;
struct kse *curkse;
+ struct pthread *curthread;
crit = _kse_critical_enter();
curkse = _get_curkse();
-
+ curthread = _get_curthread();
+ thread->sigmask = curthread->sigmask;
KSE_LOCK_ACQUIRE(curkse, &_thread_list_lock);
/*
* Initialize the unique id (which GDB uses to track
diff --git a/lib/libpthread/thread/thr_kill.c b/lib/libpthread/thread/thr_kill.c
index 19f34bb..226cb86 100644
--- a/lib/libpthread/thread/thr_kill.c
+++ b/lib/libpthread/thread/thr_kill.c
@@ -45,7 +45,7 @@ _pthread_kill(pthread_t pthread, int sig)
int ret;
/* Check for invalid signal numbers: */
- if (sig < 0 || sig >= NSIG)
+ if (sig < 0 || sig > _SIG_MAXSIG)
/* Invalid signal: */
ret = EINVAL;
/*
diff --git a/lib/libpthread/thread/thr_private.h b/lib/libpthread/thread/thr_private.h
index 3672025..fefacd1 100644
--- a/lib/libpthread/thread/thr_private.h
+++ b/lib/libpthread/thread/thr_private.h
@@ -171,7 +171,7 @@ typedef struct kse_thr_mailbox *kse_critical_t;
struct kse_group;
-#define MAX_KSE_LOCKLEVEL 3
+#define MAX_KSE_LOCKLEVEL 5
struct kse {
struct kse_mailbox k_mbx; /* kernel kse mailbox */
/* -- location and order specific items for gdb -- */
@@ -190,7 +190,7 @@ struct kse {
struct lockuser k_lockusers[MAX_KSE_LOCKLEVEL];
int k_locklevel;
sigset_t k_sigmask;
- struct sigstatus k_sigq[NSIG];
+ struct sigstatus k_sigq[_SIG_MAXSIG];
stack_t k_stack;
int k_check_sigq;
int k_flags;
@@ -201,6 +201,7 @@ struct kse {
int k_error; /* syscall errno in critical */
int k_cpu; /* CPU ID when bound */
int k_done; /* this KSE is done */
+ int k_switch; /* thread switch in UTS */
};
/*
@@ -546,8 +547,8 @@ enum pthread_state {
union pthread_wait_data {
pthread_mutex_t mutex;
pthread_cond_t cond;
- const sigset_t *sigwait; /* Waiting on a signal in sigwait */
struct lock *lock;
+ siginfo_t *sigwaitinfo; /* used to save siginfo for sigwaitinfo() */
};
/*
@@ -563,6 +564,7 @@ typedef void (*thread_continuation_t) (void *);
* state is restored from here.
*/
struct pthread_sigframe {
+ int psf_valid;
int psf_flags;
int psf_interrupted;
int psf_signo;
@@ -586,7 +588,7 @@ struct pthread_specific_elem {
};
-#define MAX_THR_LOCKLEVEL 3
+#define MAX_THR_LOCKLEVEL 5
/*
* Thread structure.
*/
@@ -640,7 +642,7 @@ struct pthread {
* Used for tracking delivery of signal handlers.
*/
struct pthread_sigframe *curframe;
- siginfo_t siginfo[NSIG];
+ siginfo_t siginfo[_SIG_MAXSIG];
/*
* Cancelability flags - the lower 2 bits are used by cancel
@@ -657,11 +659,10 @@ struct pthread {
* The thread's base and pending signal masks. The active
* signal mask is stored in the thread's context (in mailbox).
*/
+ sigset_t oldsigmask;
sigset_t sigmask;
sigset_t sigpend;
- int sigmask_seqno;
int check_pending;
- int have_signals;
int refcount;
/* Thread state: */
@@ -997,14 +998,14 @@ SCLASS struct pthread_cond_attr _pthread_condattr_default
SCLASS int _clock_res_usec SCLASS_PRESET(CLOCK_RES_USEC);
/* Array of signal actions for this process: */
-SCLASS struct sigaction _thread_sigact[NSIG];
+SCLASS struct sigaction _thread_sigact[_SIG_MAXSIG];
/*
* 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];
+SCLASS int _thread_dfl_count[_SIG_MAXSIG];
/*
* Lock for above count of dummy handlers and for the process signal
@@ -1014,8 +1015,7 @@ SCLASS struct lock _thread_signal_lock;
/* Pending signals and mask for this process: */
SCLASS sigset_t _thr_proc_sigpending;
-SCLASS sigset_t _thr_proc_sigmask SCLASS_PRESET({{0, 0, 0, 0}});
-SCLASS siginfo_t _thr_proc_siginfo[NSIG];
+SCLASS siginfo_t _thr_proc_siginfo[_SIG_MAXSIG];
SCLASS pid_t _thr_pid SCLASS_PRESET(0);
@@ -1030,7 +1030,7 @@ SCLASS struct lock _keytable_lock;
SCLASS struct lock _thread_list_lock;
SCLASS int _thr_guard_default;
SCLASS int _thr_page_size;
-
+SCLASS pthread_t _thr_sig_daemon;
SCLASS int _thr_debug_flags SCLASS_PRESET(0);
/* Undefine the storage class and preset specifiers: */
@@ -1116,7 +1116,6 @@ void _thr_panic_exit(char *, int, char *);
void _thread_cleanupspecific(void);
void _thread_dump_info(void);
void _thread_printf(int, const char *, ...);
-void _thr_sched_frame(struct pthread_sigframe *);
void _thr_sched_switch(struct pthread *);
void _thr_sched_switch_unlocked(struct pthread *);
void _thr_set_timeout(const struct timespec *);
@@ -1126,13 +1125,17 @@ void _thr_sig_check_pending(struct pthread *);
void _thr_sig_rundown(struct pthread *, ucontext_t *,
struct pthread_sigframe *);
void _thr_sig_send(struct pthread *pthread, int sig);
-void _thr_sig_wrapper(void);
void _thr_sigframe_restore(struct pthread *thread, struct pthread_sigframe *psf);
void _thr_spinlock_init(void);
void _thr_enter_cancellation_point(struct pthread *);
void _thr_leave_cancellation_point(struct pthread *);
int _thr_setconcurrency(int new_level);
int _thr_setmaxconcurrency(void);
+int _thr_start_sig_daemon(void);
+int _thr_getprocsig(int sig, siginfo_t *siginfo);
+int _thr_getprocsig_unlocked(int sig, siginfo_t *siginfo);
+void _thr_signal_init(void);
+void _thr_signal_deinit(void);
/*
* Aliases for _pthread functions. Should be called instead of
@@ -1216,6 +1219,8 @@ int __sys_select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
ssize_t __sys_read(int, void *, size_t);
ssize_t __sys_write(int, const void *, size_t);
void __sys_exit(int);
+int __sys_sigwait(const sigset_t *, int *);
+int __sys_sigtimedwait(sigset_t *, siginfo_t *, struct timespec *);
#endif
/* #include <poll.h> */
diff --git a/lib/libpthread/thread/thr_sig.c b/lib/libpthread/thread/thr_sig.c
index 94e5630..d06db9d 100644
--- a/lib/libpthread/thread/thr_sig.c
+++ b/lib/libpthread/thread/thr_sig.c
@@ -45,19 +45,15 @@
/* Prototypes: */
static void build_siginfo(siginfo_t *info, int signo);
-/* static void thr_sig_add(struct pthread *pthread, int sig, siginfo_t *info); */
static void thr_sig_check_state(struct pthread *pthread, int sig);
static struct pthread *thr_sig_find(struct kse *curkse, int sig,
siginfo_t *info);
static void handle_special_signals(struct kse *curkse, int sig);
-static void thr_sigframe_add(struct pthread *thread, int sig,
- siginfo_t *info);
+static void thr_sigframe_add(struct pthread *thread);
static void thr_sigframe_restore(struct pthread *thread,
struct pthread_sigframe *psf);
static void thr_sigframe_save(struct pthread *thread,
struct pthread_sigframe *psf);
-static void thr_sig_invoke_handler(struct pthread *, int sig,
- siginfo_t *info, ucontext_t *ucp);
/* #define DEBUG_SIGNAL */
#ifdef DEBUG_SIGNAL
@@ -137,6 +133,65 @@ static void thr_sig_invoke_handler(struct pthread *, int sig,
* signal unmasked.
*/
+static void *
+sig_daemon(void *arg /* Unused */)
+{
+ int i;
+ kse_critical_t crit;
+ struct timespec ts;
+ sigset_t set;
+ struct kse *curkse;
+ struct pthread *curthread = _get_curthread();
+
+ DBG_MSG("signal daemon started");
+
+ curthread->name = strdup("signal thread");
+ crit = _kse_critical_enter();
+ curkse = _get_curkse();
+ SIGFILLSET(set);
+ __sys_sigprocmask(SIG_SETMASK, &set, NULL);
+ __sys_sigpending(&set);
+ ts.tv_sec = 0;
+ ts.tv_nsec = 0;
+ while (1) {
+ KSE_LOCK_ACQUIRE(curkse, &_thread_signal_lock);
+ _thr_proc_sigpending = set;
+ KSE_LOCK_RELEASE(curkse, &_thread_signal_lock);
+ for (i = 1; i <= _SIG_MAXSIG; i++) {
+ if (SIGISMEMBER(set, i) != 0)
+ _thr_sig_dispatch(curkse, i,
+ NULL /* no siginfo */);
+ }
+ ts.tv_sec = 30;
+ ts.tv_nsec = 0;
+ curkse->k_mbx.km_flags =
+ KMF_NOUPCALL | KMF_NOCOMPLETED | KMF_WAITSIGEVENT;
+ kse_release(&ts);
+ curkse->k_mbx.km_flags = 0;
+ set = curkse->k_mbx.km_sigscaught;
+ }
+ return (0);
+}
+
+/* Utility function to create signal daemon thread */
+int
+_thr_start_sig_daemon(void)
+{
+ pthread_attr_t attr;
+ sigset_t sigset, oldset;
+
+ SIGFILLSET(sigset);
+ pthread_sigmask(SIG_SETMASK, &sigset, &oldset);
+ pthread_attr_init(&attr);
+ pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
+ /* sigmask will be inherited */
+ if (pthread_create(&_thr_sig_daemon, &attr, sig_daemon, NULL))
+ PANIC("can not create signal daemon thread!\n");
+ pthread_attr_destroy(&attr);
+ pthread_sigmask(SIG_SETMASK, &oldset, NULL);
+ return (0);
+}
+
/*
* This signal handler only delivers asynchronous signals.
* This must be called with upcalls disabled and without
@@ -151,7 +206,6 @@ _thr_sig_dispatch(struct kse *curkse, int sig, siginfo_t *info)
/* Some signals need special handling: */
handle_special_signals(curkse, sig);
- DBG_MSG("dispatch sig:%d\n", sig);
while ((thread = thr_sig_find(curkse, sig, info)) != NULL) {
/*
* Setup the target thread to receive the signal:
@@ -163,18 +217,17 @@ _thr_sig_dispatch(struct kse *curkse, int sig, siginfo_t *info)
THR_IS_EXITING(thread) || THR_IS_SUSPENDED(thread)) {
KSE_SCHED_UNLOCK(curkse, thread->kseg);
_thr_ref_delete(NULL, thread);
- } else if (sigismember(&thread->tmbx.tm_context.uc_sigmask,
- sig)) {
+ } else if (SIGISMEMBER(thread->sigmask, sig)) {
KSE_SCHED_UNLOCK(curkse, thread->kseg);
_thr_ref_delete(NULL, thread);
- }
- else {
+ } else {
_thr_sig_add(thread, sig, info);
KSE_SCHED_UNLOCK(curkse, thread->kseg);
_thr_ref_delete(NULL, thread);
break;
}
}
+ DBG_MSG("<<< _thr_sig_dispatch\n");
}
void
@@ -187,7 +240,6 @@ _thr_sig_handler(int sig, siginfo_t *info, ucontext_t *ucp)
if ((curkse == NULL) || ((curkse->k_flags & KF_STARTED) == 0)) {
/* Upcalls are not yet started; just call the handler. */
sigfunc = _thread_sigact[sig - 1].sa_sigaction;
- ucp->uc_sigmask = _thr_proc_sigmask;
if (((__sighandler_t *)sigfunc != SIG_DFL) &&
((__sighandler_t *)sigfunc != SIG_IGN) &&
(sigfunc != (__siginfohandler_t *)_thr_sig_handler)) {
@@ -202,68 +254,119 @@ _thr_sig_handler(int sig, siginfo_t *info, ucontext_t *ucp)
else {
/* Nothing. */
DBG_MSG("Got signal %d\n", sig);
- sigaddset(&curkse->k_mbx.km_sigscaught, sig);
- ucp->uc_sigmask = _thr_proc_sigmask;
+ /* XXX Bound thread will fall into this... */
}
}
+/* Must be called with signal lock and schedule lock held in order */
static void
thr_sig_invoke_handler(struct pthread *curthread, int sig, siginfo_t *info,
ucontext_t *ucp)
{
void (*sigfunc)(int, siginfo_t *, void *);
- sigset_t saved_mask;
- int saved_seqno;
+ sigset_t sigmask;
+ int sa_flags;
+ struct sigaction act;
+ struct kse *curkse;
- /* Invoke the signal handler without going through the scheduler:
+ /*
+ * Invoke the signal handler without going through the scheduler:
*/
DBG_MSG("Got signal %d, calling handler for current thread %p\n",
sig, curthread);
- /*
- * Setup the threads signal mask.
- *
- * The mask is changed in the thread's active signal mask
- * (in the context) and not in the base signal mask because
- * a thread is allowed to change its signal mask within a
- * signal handler. If it does, the signal mask restored
- * after the handler should be the same as that set by the
- * thread during the handler, not the original mask from
- * before calling the handler. The thread could also
- * modify the signal mask in the context and expect this
- * mask to be used.
- */
- THR_SCHED_LOCK(curthread, curthread);
- saved_mask = curthread->tmbx.tm_context.uc_sigmask;
- saved_seqno = curthread->sigmask_seqno;
- SIGSETOR(curthread->tmbx.tm_context.uc_sigmask,
- _thread_sigact[sig - 1].sa_mask);
- sigaddset(&curthread->tmbx.tm_context.uc_sigmask, sig);
- THR_SCHED_UNLOCK(curthread, curthread);
-
+ if (!_kse_in_critical())
+ PANIC("thr_sig_invoke_handler without in critical\n");
+ curkse = _get_curkse();
/*
* Check that a custom handler is installed and if
* the signal is not blocked:
*/
sigfunc = _thread_sigact[sig - 1].sa_sigaction;
- ucp->uc_sigmask = _thr_proc_sigmask;
+ sa_flags = _thread_sigact[sig - 1].sa_flags & SA_SIGINFO;
+ sigmask = curthread->sigmask;
+ SIGSETOR(curthread->sigmask, _thread_sigact[sig - 1].sa_mask);
+ if (!(sa_flags & (SA_NODEFER | SA_RESETHAND)))
+ SIGADDSET(curthread->sigmask, sig);
+ if ((sig != SIGILL) && (sa_flags & SA_RESETHAND)) {
+ if (_thread_dfl_count[sig - 1] == 0) {
+ act.sa_handler = SIG_DFL;
+ act.sa_flags = SA_RESTART;
+ SIGEMPTYSET(act.sa_mask);
+ __sys_sigaction(sig, &act, NULL);
+ __sys_sigaction(sig, NULL, &_thread_sigact[sig - 1]);
+ }
+ }
+ KSE_LOCK_RELEASE(curkse, &_thread_signal_lock);
+ KSE_SCHED_UNLOCK(curkse, curkse->k_kseg);
+ _kse_critical_leave(&curthread->tmbx);
+ ucp->uc_sigmask = sigmask;
+
if (((__sighandler_t *)sigfunc != SIG_DFL) &&
((__sighandler_t *)sigfunc != SIG_IGN)) {
- if (((_thread_sigact[sig - 1].sa_flags & SA_SIGINFO) != 0) ||
- (info == NULL))
+ if ((sa_flags & SA_SIGINFO) != 0 || info == NULL)
(*(sigfunc))(sig, info, ucp);
else
(*(sigfunc))(sig, (siginfo_t*)(intptr_t)info->si_code,
ucp);
+ } else {
+ /* XXX
+ * TODO: exit process if signal would kill it.
+ */
+#ifdef NOTYET
+ if (sigprop(sig) & SA_KILL)
+ kse_sigexit(sig);
+#endif
}
-
+ _kse_critical_enter();
+ /* Don't trust after critical leave/enter */
+ curkse = _get_curkse();
+ KSE_SCHED_LOCK(curkse, curkse->k_kseg);
+ KSE_LOCK_ACQUIRE(curkse, &_thread_signal_lock);
/*
* Restore the thread's signal mask.
*/
- if (saved_seqno == curthread->sigmask_seqno)
- curthread->tmbx.tm_context.uc_sigmask = saved_mask;
- else
- curthread->tmbx.tm_context.uc_sigmask = curthread->sigmask;
+ curthread->sigmask = ucp->uc_sigmask;
+
+ DBG_MSG("Got signal %d, handler returned %p\n", sig, curthread);
+}
+
+int
+_thr_getprocsig(int sig, siginfo_t *siginfo)
+{
+ kse_critical_t crit;
+ struct kse *curkse;
+ int ret;
+
+ DBG_MSG(">>> _thr_getprocsig\n");
+
+ crit = _kse_critical_enter();
+ curkse = _get_curkse();
+ KSE_LOCK_ACQUIRE(curkse, &_thread_signal_lock);
+ ret = _thr_getprocsig_unlocked(sig, siginfo);
+ KSE_LOCK_RELEASE(curkse, &_thread_signal_lock);
+ _kse_critical_leave(crit);
+
+ DBG_MSG("<<< _thr_getprocsig\n");
+ return (ret);
+}
+
+int
+_thr_getprocsig_unlocked(int sig, siginfo_t *siginfo)
+{
+ sigset_t sigset;
+ struct timespec ts;
+
+ /* try to retrieve signal from kernel */
+ SIGEMPTYSET(sigset);
+ SIGADDSET(sigset, sig);
+ ts.tv_sec = 0;
+ ts.tv_nsec = 0;
+ if (__sys_sigtimedwait(&sigset, siginfo, &ts) > 0) {
+ SIGDELSET(_thr_proc_sigpending, sig);
+ return (sig);
+ }
+ return (0);
}
/*
@@ -273,15 +376,12 @@ thr_sig_invoke_handler(struct pthread *curthread, int sig, siginfo_t *info,
struct pthread *
thr_sig_find(struct kse *curkse, int sig, siginfo_t *info)
{
- int handler_installed;
struct pthread *pthread;
struct pthread *suspended_thread, *signaled_thread;
+ siginfo_t si;
DBG_MSG("Looking for thread to handle signal %d\n", sig);
- handler_installed = (_thread_sigact[sig - 1].sa_handler != SIG_IGN) &&
- (_thread_sigact[sig - 1].sa_handler != SIG_DFL);
-
/* Check if the signal requires a dump of thread information: */
if (sig == SIGINFO) {
/* Dump thread information to file: */
@@ -302,19 +402,39 @@ thr_sig_find(struct kse *curkse, int sig, siginfo_t *info)
KSE_LOCK_ACQUIRE(curkse, &_thread_list_lock);
TAILQ_FOREACH(pthread, &_thread_list, tle) {
+ if (pthread == _thr_sig_daemon)
+ continue;
+#ifdef NOTYET
+ /* Signal delivering to bound thread is done by kernel */
+ if (pthread->attr.flags & PTHREAD_SCOPE_SYSTEM)
+ continue;
+#endif
+
/* Take the scheduling lock. */
KSE_SCHED_LOCK(curkse, pthread->kseg);
- if ((pthread->state == PS_SIGWAIT) &&
- sigismember(pthread->data.sigwait, sig)) {
+ if ((pthread->state == PS_DEAD) ||
+ (pthread->state == PS_DEADLOCK) ||
+ THR_IS_EXITING(pthread) ||
+ THR_IS_SUSPENDED(pthread) ||
+ SIGISMEMBER(pthread->sigmask, sig)) {
+ ; /* Skip this thread. */
+ } else if (pthread->state == PS_SIGWAIT) {
/*
- * Return the signal number and make the
- * thread runnable.
+ * retrieve signal from kernel, if it is job control
+ * signal, and sigaction is SIG_DFL, then we will
+ * be stopped in kernel, we hold lock here, but that
+ * does not matter, because that's job control, and
+ * whole process should be stopped.
*/
- pthread->signo = sig;
- _thr_setrunnable_unlocked(pthread);
-
+ if (_thr_getprocsig(sig, &si)) {
+ DBG_MSG("Waking thread %p in sigwait"
+ " with signal %d\n", pthread, sig);
+ /* where to put siginfo ? */
+ *(pthread->data.sigwaitinfo) = si;
+ pthread->sigmask = pthread->oldsigmask;
+ _thr_setrunnable_unlocked(pthread);
+ }
KSE_SCHED_UNLOCK(curkse, pthread->kseg);
-
/*
* POSIX doesn't doesn't specify which thread
* will get the signal if there are multiple
@@ -326,16 +446,8 @@ thr_sig_find(struct kse *curkse, int sig, siginfo_t *info)
* to the process pending set.
*/
KSE_LOCK_RELEASE(curkse, &_thread_list_lock);
- DBG_MSG("Waking thread %p in sigwait with signal %d\n",
- pthread, sig);
return (NULL);
- }
- else if ((pthread->state == PS_DEAD) ||
- (pthread->state == PS_DEADLOCK) ||
- THR_IS_EXITING(pthread) || THR_IS_SUSPENDED(pthread))
- ; /* Skip this thread. */
- else if ((handler_installed != 0) &&
- !sigismember(&pthread->tmbx.tm_context.uc_sigmask, sig)) {
+ } else {
if (pthread->state == PS_SIGSUSPEND) {
if (suspended_thread == NULL) {
suspended_thread = pthread;
@@ -344,49 +456,22 @@ thr_sig_find(struct kse *curkse, int sig, siginfo_t *info)
} else if (signaled_thread == NULL) {
signaled_thread = pthread;
signaled_thread->refcount++;
- }
+ }
}
KSE_SCHED_UNLOCK(curkse, pthread->kseg);
}
KSE_LOCK_RELEASE(curkse, &_thread_list_lock);
- /*
- * Only perform wakeups and signal delivery if there is a
- * custom handler installed:
- */
- if (handler_installed == 0) {
- /*
- * There is no handler installed; nothing to do here.
- */
- } else if (suspended_thread == NULL &&
- signaled_thread == NULL) {
- /*
- * Add it to the set of signals pending
- * on the process:
- */
- KSE_LOCK_ACQUIRE(curkse, &_thread_signal_lock);
- if (!sigismember(&_thr_proc_sigpending, sig)) {
- sigaddset(&_thr_proc_sigpending, sig);
- if (info == NULL)
- build_siginfo(&_thr_proc_siginfo[sig], sig);
- else
- memcpy(&_thr_proc_siginfo[sig], info,
- sizeof(*info));
- }
- KSE_LOCK_RELEASE(curkse, &_thread_signal_lock);
- } else {
- /*
- * We only deliver the signal to one thread;
- * give preference to the suspended thread:
- */
- if (suspended_thread != NULL) {
- pthread = suspended_thread;
+ if (suspended_thread != NULL) {
+ pthread = suspended_thread;
+ if (signaled_thread)
_thr_ref_delete(NULL, signaled_thread);
- } else
- pthread = signaled_thread;
- return (pthread);
+ } else if (signaled_thread) {
+ pthread = signaled_thread;
+ } else {
+ pthread = NULL;
}
- return (NULL);
+ return (pthread);
}
static void
@@ -405,64 +490,80 @@ void
_thr_sig_rundown(struct pthread *curthread, ucontext_t *ucp,
struct pthread_sigframe *psf)
{
- struct pthread_sigframe psf_save;
- sigset_t sigset;
+ siginfo_t siginfo;
int i;
+ kse_critical_t crit;
+ struct kse *curkse;
- THR_SCHED_LOCK(curthread, curthread);
- memcpy(&sigset, &curthread->sigpend, sizeof(sigset));
- sigemptyset(&curthread->sigpend);
- if (psf != NULL) {
- memcpy(&psf_save, psf, sizeof(*psf));
- SIGSETOR(sigset, psf_save.psf_sigset);
- sigemptyset(&psf->psf_sigset);
- }
- THR_SCHED_UNLOCK(curthread, curthread);
-
+ DBG_MSG(">>> thr_sig_rundown %p\n", curthread);
/* Check the threads previous state: */
- if ((psf != NULL) && (psf_save.psf_state != PS_RUNNING)) {
+ if ((psf != NULL) && (psf->psf_valid != 0)) {
/*
* Do a little cleanup handling for those threads in
* queues before calling the signal handler. Signals
* for these threads are temporarily blocked until
* after cleanup handling.
*/
- switch (psf_save.psf_state) {
+ switch (psf->psf_state) {
case PS_COND_WAIT:
_cond_wait_backout(curthread);
- psf_save.psf_state = PS_RUNNING;
+ psf->psf_state = PS_RUNNING;
break;
case PS_MUTEX_WAIT:
_mutex_lock_backout(curthread);
- psf_save.psf_state = PS_RUNNING;
+ psf->psf_state = PS_RUNNING;
break;
+ case PS_RUNNING:
+ break;
+
default:
+ psf->psf_state = PS_RUNNING;
break;
}
+ /* XXX see comment in thr_sched_switch_unlocked */
+ curthread->critical_count--;
}
+
/*
* Lower the priority before calling the handler in case
* it never returns (longjmps back):
*/
+ crit = _kse_critical_enter();
+ curkse = _get_curkse();
+ KSE_SCHED_LOCK(curkse, curkse->k_kseg);
+ KSE_LOCK_ACQUIRE(curkse, &_thread_signal_lock);
curthread->active_priority &= ~THR_SIGNAL_PRIORITY;
- for (i = 1; i < NSIG; i++) {
- if (sigismember(&sigset, i) != 0) {
- /* Call the handler: */
- thr_sig_invoke_handler(curthread, i,
- &curthread->siginfo[i], ucp);
+ while (1) {
+ for (i = 1; i <= _SIG_MAXSIG; i++) {
+ if (SIGISMEMBER(curthread->sigmask, i))
+ continue;
+ if (SIGISMEMBER(curthread->sigpend, i)) {
+ SIGDELSET(curthread->sigpend, i);
+ siginfo = curthread->siginfo[i];
+ break;
+ }
+ if (SIGISMEMBER(_thr_proc_sigpending, i)) {
+ if (_thr_getprocsig_unlocked(i, &siginfo))
+ break;
+ }
}
+ if (i <= _SIG_MAXSIG)
+ thr_sig_invoke_handler(curthread, i, &siginfo, ucp);
+ else
+ break;
}
- THR_SCHED_LOCK(curthread, curthread);
- if (psf != NULL)
- thr_sigframe_restore(curthread, &psf_save);
- /* Restore the signal mask. */
- curthread->tmbx.tm_context.uc_sigmask = curthread->sigmask;
- THR_SCHED_UNLOCK(curthread, curthread);
- _thr_sig_check_pending(curthread);
+ if (psf != NULL && psf->psf_valid != 0)
+ thr_sigframe_restore(curthread, psf);
+ curkse = _get_curkse();
+ KSE_LOCK_RELEASE(curkse, &_thread_signal_lock);
+ KSE_SCHED_UNLOCK(curkse, curkse->k_kseg);
+ _kse_critical_leave(&curthread->tmbx);
+
+ DBG_MSG("<<< thr_sig_rundown %p\n", curthread);
}
/*
@@ -477,87 +578,19 @@ _thr_sig_rundown(struct pthread *curthread, ucontext_t *ucp,
void
_thr_sig_check_pending(struct pthread *curthread)
{
- sigset_t sigset;
- sigset_t pending_process;
- sigset_t pending_thread;
- kse_critical_t crit;
- int i;
-
- curthread->check_pending = 0;
-
- /*
- * Check if there are pending signals for the running
- * thread or process that aren't blocked:
- */
- crit = _kse_critical_enter();
- KSE_LOCK_ACQUIRE(curthread->kse, &_thread_signal_lock);
- sigset = _thr_proc_sigpending;
- KSE_LOCK_RELEASE(curthread->kse, &_thread_signal_lock);
- _kse_critical_leave(crit);
+ ucontext_t uc;
+ volatile int once;
- THR_SCHED_LOCK(curthread, curthread);
- SIGSETOR(sigset, curthread->sigpend);
- SIGSETNAND(sigset, curthread->tmbx.tm_context.uc_sigmask);
- if (SIGNOTEMPTY(sigset)) {
- ucontext_t uc;
- volatile int once;
+ if (THR_IN_CRITICAL(curthread))
+ return;
+ once = 0;
+ THR_GETCONTEXT(&uc);
+ if (once == 0) {
+ once = 1;
curthread->check_pending = 0;
- THR_SCHED_UNLOCK(curthread, curthread);
-
- /*
- * Split the pending signals into those that were
- * pending on the process and those that were pending
- * on the thread.
- */
- sigfillset(&pending_process);
- sigfillset(&pending_thread);
- for (i = 1; i < NSIG; i++) {
- if (sigismember(&sigset, i) != 0) {
- if (sigismember(&curthread->sigpend, i) != 0) {
- build_siginfo(&curthread->siginfo[i], i);
- sigdelset(&pending_thread, i);
- } else {
- memcpy(&curthread->siginfo[i],
- &_thr_proc_siginfo[i],
- sizeof(siginfo_t));
- sigdelset(&pending_process, i);
- }
- }
- }
- /*
- * Remove any process pending signals that were scheduled
- * to be delivered from process' pending set.
- */
- crit = _kse_critical_enter();
- KSE_LOCK_ACQUIRE(curthread->kse, &_thread_signal_lock);
- SIGSETAND(_thr_proc_sigpending, pending_process);
- KSE_LOCK_RELEASE(curthread->kse, &_thread_signal_lock);
- _kse_critical_leave(crit);
-
- /*
- * Remove any thread pending signals that were scheduled
- * to be delivered from thread's pending set.
- */
- THR_SCHED_LOCK(curthread, curthread);
- SIGSETAND(curthread->sigpend, pending_thread);
- THR_SCHED_UNLOCK(curthread, curthread);
-
- once = 0;
- THR_GETCONTEXT(&uc);
- if (once == 0) {
- once = 1;
- for (i = 1; i < NSIG; i++) {
- if (sigismember(&sigset, i) != 0) {
- /* Call the handler: */
- thr_sig_invoke_handler(curthread, i,
- &curthread->siginfo[i], &uc);
- }
- }
- }
+ _thr_sig_rundown(curthread, &uc, NULL);
}
- else
- THR_SCHED_UNLOCK(curthread, curthread);
}
/*
@@ -575,10 +608,15 @@ handle_special_signals(struct kse *curkse, int sig)
case SIGTTIN:
case SIGTTOU:
KSE_LOCK_ACQUIRE(curkse, &_thread_signal_lock);
- sigdelset(&_thr_proc_sigpending, SIGCONT);
+ SIGDELSET(_thr_proc_sigpending, SIGCONT);
KSE_LOCK_RELEASE(curkse, &_thread_signal_lock);
break;
-
+ case SIGCONT:
+ KSE_LOCK_ACQUIRE(curkse, &_thread_signal_lock);
+ SIGDELSET(_thr_proc_sigpending, SIGTSTP);
+ SIGDELSET(_thr_proc_sigpending, SIGTTIN);
+ SIGDELSET(_thr_proc_sigpending, SIGTTOU);
+ KSE_LOCK_RELEASE(curkse, &_thread_signal_lock);
default:
break;
}
@@ -597,72 +635,92 @@ _thr_sig_add(struct pthread *pthread, int sig, siginfo_t *info)
{
int restart;
int suppress_handler = 0;
+ int fromproc = 0;
+ struct pthread *curthread = _get_curthread();
+ struct kse *curkse;
+ siginfo_t siginfo;
- if (pthread->curframe == NULL) {
- /*
- * This thread is active. Just add it to the
- * thread's pending set.
- */
- sigaddset(&pthread->sigpend, sig);
- pthread->check_pending = 1;
- if (info == NULL)
- build_siginfo(&pthread->siginfo[sig], sig);
- else if (info != &pthread->siginfo[sig])
- memcpy(&pthread->siginfo[sig], info,
- sizeof(*info));
- if ((pthread->blocked != 0) && !THR_IN_CRITICAL(pthread))
- kse_thr_interrupt(&pthread->tmbx /* XXX - restart?!?! */);
- }
- else {
- restart = _thread_sigact[sig - 1].sa_flags & SA_RESTART;
+ DBG_MSG(">>> _thr_sig_add\n");
- /* Make sure this signal isn't still in the pending set: */
- sigdelset(&pthread->sigpend, sig);
+ curkse = _get_curkse();
+ restart = _thread_sigact[sig - 1].sa_flags & SA_RESTART;
+ fromproc = (curthread == _thr_sig_daemon);
+
+ if (pthread->state == PS_DEAD || pthread->state == PS_DEADLOCK ||
+ pthread->state == PS_STATE_MAX)
+ return; /* return false */
+
+#ifdef NOTYET
+ if ((pthread->attrs.flags & PTHREAD_SCOPE_SYSTEM) != 0) {
+ if (!fromproc)
+ kse_thr_interrupt(&pthread->tmbx, 0, sig);
+ return;
+ }
+#endif
+ if (pthread->curframe == NULL ||
+ SIGISMEMBER(pthread->sigmask, sig) ||
+ THR_IN_CRITICAL(pthread)) {
+ /* thread is running or signal was being masked */
+ if (!fromproc) {
+ SIGADDSET(pthread->sigpend, sig);
+ if (info == NULL)
+ build_siginfo(&pthread->siginfo[sig], sig);
+ else if (info != &pthread->siginfo[sig])
+ memcpy(&pthread->siginfo[sig], info,
+ sizeof(*info));
+ } else {
+ if (!_thr_getprocsig(sig, &pthread->siginfo[sig]))
+ return;
+ SIGADDSET(pthread->sigpend, sig);
+ }
+ if (!SIGISMEMBER(pthread->sigmask, sig)) {
+ pthread->check_pending = 1;
+ if (pthread->blocked != 0 && !THR_IN_CRITICAL(pthread))
+ kse_thr_interrupt(&pthread->tmbx,
+ restart ? -2 : -1);
+ }
+ }
+ else {
+ /* if process signal not exists, just return */
+ if (fromproc) {
+ if (!_thr_getprocsig(sig, &siginfo))
+ return;
+ info = &siginfo;
+ }
/*
* Process according to thread state:
*/
switch (pthread->state) {
- /*
- * States which do not change when a signal is trapped:
- */
case PS_DEAD:
case PS_DEADLOCK:
+ case PS_STATE_MAX:
+ return; /* XXX return false */
case PS_LOCKWAIT:
case PS_SUSPENDED:
- case PS_STATE_MAX:
/*
* You can't call a signal handler for threads in these
* states.
*/
suppress_handler = 1;
break;
-
- /*
- * States which do not need any cleanup handling when signals
- * occur:
- */
case PS_RUNNING:
- /*
- * Remove the thread from the queue before changing its
- * priority:
- */
- if ((pthread->flags & THR_FLAGS_IN_RUNQ) != 0)
+ if ((pthread->flags & THR_FLAGS_IN_RUNQ)) {
THR_RUNQ_REMOVE(pthread);
+ pthread->active_priority |= THR_SIGNAL_PRIORITY;
+ THR_RUNQ_INSERT_TAIL(pthread);
+ } else {
+ /* Possible not in RUNQ and has curframe ? */
+ pthread->active_priority |= THR_SIGNAL_PRIORITY;
+ }
+ suppress_handler = 1;
break;
-
/*
* States which cannot be interrupted but still require the
* signal handler to run:
*/
case PS_COND_WAIT:
case PS_MUTEX_WAIT:
- /*
- * Remove the thread from the wait queue. It will
- * be added back to the wait queue once all signal
- * handlers have been invoked.
- */
- KSE_WAITQ_REMOVE(pthread->kse, pthread);
break;
case PS_SLEEP_WAIT:
@@ -671,60 +729,64 @@ _thr_sig_add(struct pthread *pthread, int sig, siginfo_t *info)
* early regardless of SA_RESTART:
*/
pthread->interrupted = 1;
- KSE_WAITQ_REMOVE(pthread->kse, pthread);
- THR_SET_STATE(pthread, PS_RUNNING);
break;
case PS_JOIN:
+ break;
+
case PS_SIGSUSPEND:
- KSE_WAITQ_REMOVE(pthread->kse, pthread);
- THR_SET_STATE(pthread, PS_RUNNING);
+ pthread->interrupted = 1;
break;
case PS_SIGWAIT:
+ if (info == NULL)
+ build_siginfo(&pthread->siginfo[sig], sig);
+ else if (info != &pthread->siginfo[sig])
+ memcpy(&pthread->siginfo[sig], info,
+ sizeof(*info));
/*
* The signal handler is not called for threads in
* SIGWAIT.
*/
suppress_handler = 1;
- /* Wake up the thread if the signal is blocked. */
- if (sigismember(pthread->data.sigwait, sig)) {
+ /* Wake up the thread if the signal is not blocked. */
+ if (!SIGISMEMBER(pthread->sigmask, sig)) {
/* Return the signal number: */
- pthread->signo = sig;
-
+ *(pthread->data.sigwaitinfo) = pthread->siginfo[sig];
+ pthread->sigmask = pthread->oldsigmask;
/* Make the thread runnable: */
_thr_setrunnable_unlocked(pthread);
- } else
+ } else {
/* Increment the pending signal count. */
- sigaddset(&pthread->sigpend, sig);
- break;
+ SIGADDSET(pthread->sigpend, sig);
+ pthread->check_pending = 1;
+ }
+
+ return;
}
+ SIGADDSET(pthread->sigpend, sig);
+ if (info == NULL)
+ build_siginfo(&pthread->siginfo[sig], sig);
+ else if (info != &pthread->siginfo[sig])
+ memcpy(&pthread->siginfo[sig], info, sizeof(*info));
+
if (suppress_handler == 0) {
/*
* Setup a signal frame and save the current threads
* state:
*/
- thr_sigframe_add(pthread, sig, info);
-
- if (pthread->state != PS_RUNNING)
- THR_SET_STATE(pthread, PS_RUNNING);
-
- /*
- * The thread should be removed from all scheduling
- * queues at this point. Raise the priority and
- * place the thread in the run queue. It is also
- * possible for a signal to be sent to a suspended
- * thread, mostly via pthread_kill(). If a thread
- * is suspended, don't insert it into the priority
- * queue; just set its state to suspended and it
- * will run the signal handler when it is resumed.
- */
+ thr_sigframe_add(pthread);
+ if (pthread->flags & THR_FLAGS_IN_RUNQ)
+ THR_RUNQ_REMOVE(pthread);
pthread->active_priority |= THR_SIGNAL_PRIORITY;
- if ((pthread->flags & THR_FLAGS_IN_RUNQ) == 0)
- THR_RUNQ_INSERT_TAIL(pthread);
+ _thr_setrunnable_unlocked(pthread);
+ } else {
+ pthread->check_pending = 1;
}
}
+
+ DBG_MSG("<<< _thr_sig_add\n");
}
static void
@@ -749,16 +811,19 @@ thr_sig_check_state(struct pthread *pthread, int sig)
break;
case PS_SIGWAIT:
+ build_siginfo(&pthread->siginfo[sig], sig);
/* Wake up the thread if the signal is blocked. */
- if (sigismember(pthread->data.sigwait, sig)) {
+ if (!SIGISMEMBER(pthread->sigmask, sig)) {
/* Return the signal number: */
- pthread->signo = sig;
-
+ *(pthread->data.sigwaitinfo) = pthread->siginfo[sig];
+ pthread->sigmask = pthread->oldsigmask;
/* Change the state of the thread to run: */
_thr_setrunnable_unlocked(pthread);
- } else
+ } else {
/* Increment the pending signal count. */
- sigaddset(&pthread->sigpend, sig);
+ SIGADDSET(pthread->sigpend, sig);
+ pthread->check_pending = 1;
+ }
break;
case PS_SIGSUSPEND:
@@ -783,6 +848,12 @@ _thr_sig_send(struct pthread *pthread, int sig)
{
struct pthread *curthread = _get_curthread();
+#ifdef NOTYET
+ if ((pthread->attr.flags & PTHREAD_SCOPE_SYSTEM) == 0) {
+ kse_thr_interrupt(&pthread->tmbx, sig);
+ return;
+ }
+#endif
/* Lock the scheduling queue of the target thread. */
THR_SCHED_LOCK(curthread, pthread);
@@ -792,7 +863,7 @@ _thr_sig_send(struct pthread *pthread, int sig)
* Check to see if a temporary signal handler is
* installed for sigwaiters:
*/
- if (_thread_dfl_count[sig] == 0) {
+ if (_thread_dfl_count[sig - 1] == 0) {
/*
* Deliver the signal to the process if a handler
* is not installed:
@@ -812,87 +883,47 @@ _thr_sig_send(struct pthread *pthread, int sig)
* Check that the signal is not being ignored:
*/
else if (_thread_sigact[sig - 1].sa_handler != SIG_IGN) {
- if (pthread->state == PS_SIGWAIT &&
- sigismember(pthread->data.sigwait, sig)) {
- /* Return the signal number: */
- pthread->signo = sig;
-
- /* Change the state of the thread to run: */
- _thr_setrunnable_unlocked(pthread);
- THR_SCHED_UNLOCK(curthread, pthread);
- } else if (sigismember(&pthread->tmbx.tm_context.uc_sigmask, sig)) {
- /* Add the signal to the pending set: */
- sigaddset(&pthread->sigpend, sig);
- THR_SCHED_UNLOCK(curthread, pthread);
- } else if (pthread == curthread) {
- ucontext_t uc;
- siginfo_t info;
- volatile int once;
-
- THR_SCHED_UNLOCK(curthread, pthread);
- build_siginfo(&info, sig);
- once = 0;
- THR_GETCONTEXT(&uc);
- if (once == 0) {
- once = 1;
- /*
- * Call the signal handler for the current
- * thread:
- */
- thr_sig_invoke_handler(curthread, sig,
- &info, &uc);
- }
- } else {
- /*
- * Perform any state changes due to signal
- * arrival:
- */
- _thr_sig_add(pthread, sig, NULL);
- THR_SCHED_UNLOCK(curthread, pthread);
- }
+ _thr_sig_add(pthread, sig, NULL);
+ THR_SCHED_UNLOCK(curthread, pthread);
+ /* XXX
+ * If thread sent signal to itself, check signals now.
+ * It is not really needed, _kse_critical_leave should
+ * have already checked signals.
+ */
+ if (pthread == curthread && curthread->check_pending)
+ _thr_sig_check_pending(curthread);
+ } else {
+ THR_SCHED_UNLOCK(curthread, pthread);
}
}
static void
-thr_sigframe_add(struct pthread *thread, int sig, siginfo_t *info)
+thr_sigframe_add(struct pthread *thread)
{
if (thread->curframe == NULL)
PANIC("Thread doesn't have signal frame ");
- if (thread->have_signals == 0) {
+ if (thread->curframe->psf_valid == 0) {
+ thread->curframe->psf_valid = 1;
/*
* Multiple signals can be added to the same signal
* frame. Only save the thread's state the first time.
*/
thr_sigframe_save(thread, thread->curframe);
- thread->have_signals = 1;
- thread->flags &= THR_FLAGS_PRIVATE;
}
- sigaddset(&thread->curframe->psf_sigset, sig);
- if (info == NULL)
- build_siginfo(&thread->siginfo[sig], sig);
- else if (info != &thread->siginfo[sig])
- memcpy(&thread->siginfo[sig], info, sizeof(*info));
-
- /* Setup the new signal mask. */
- SIGSETOR(thread->tmbx.tm_context.uc_sigmask,
- _thread_sigact[sig - 1].sa_mask);
- sigaddset(&thread->tmbx.tm_context.uc_sigmask, sig);
}
-void
+static void
thr_sigframe_restore(struct pthread *thread, struct pthread_sigframe *psf)
{
+ if (psf->psf_valid == 0)
+ PANIC("invalid pthread_sigframe\n");
thread->flags = psf->psf_flags;
thread->interrupted = psf->psf_interrupted;
thread->signo = psf->psf_signo;
thread->state = psf->psf_state;
thread->data = psf->psf_wait_data;
thread->wakeup_time = psf->psf_wakeup_time;
- if (thread->sigmask_seqno == psf->psf_seqno)
- thread->tmbx.tm_context.uc_sigmask = psf->psf_sigmask;
- else
- thread->tmbx.tm_context.uc_sigmask = thread->sigmask;
}
static void
@@ -906,7 +937,74 @@ thr_sigframe_save(struct pthread *thread, struct pthread_sigframe *psf)
psf->psf_state = thread->state;
psf->psf_wait_data = thread->data;
psf->psf_wakeup_time = thread->wakeup_time;
- psf->psf_sigmask = thread->tmbx.tm_context.uc_sigmask;
- psf->psf_seqno = thread->sigmask_seqno;
- sigemptyset(&psf->psf_sigset);
}
+
+void
+_thr_signal_init(void)
+{
+ sigset_t sigset;
+ struct sigaction act;
+ int i;
+
+ SIGFILLSET(sigset);
+ __sys_sigprocmask(SIG_SETMASK, &sigset, &_thr_initial->sigmask);
+ /* Enter a loop to get the existing signal status: */
+ for (i = 1; i <= _SIG_MAXSIG; i++) {
+ /* Check for signals which cannot be trapped: */
+ if (i == SIGKILL || i == SIGSTOP) {
+ }
+
+ /* Get the signal handler details: */
+ else if (__sys_sigaction(i, NULL,
+ &_thread_sigact[i - 1]) != 0) {
+ /*
+ * Abort this process if signal
+ * initialisation fails:
+ */
+ PANIC("Cannot read signal handler info");
+ }
+ }
+ /*
+ * Install the signal handler for SIGINFO. It isn't
+ * really needed, but it is nice to have for debugging
+ * purposes.
+ */
+ _thread_sigact[SIGINFO - 1].sa_flags = SA_SIGINFO | SA_RESTART;
+ SIGEMPTYSET(act.sa_mask);
+ act.sa_flags = SA_SIGINFO | SA_RESTART;
+ act.sa_sigaction = (__siginfohandler_t *)&_thr_sig_handler;
+ if (__sys_sigaction(SIGINFO, &act, NULL) != 0) {
+ /*
+ * Abort this process if signal initialisation fails:
+ */
+ PANIC("Cannot initialize signal handler");
+ }
+}
+
+void
+_thr_signal_deinit(void)
+{
+ sigset_t tmpmask, oldmask;
+ int i;
+
+ SIGFILLSET(tmpmask);
+ SIG_CANTMASK(tmpmask);
+ __sys_sigprocmask(SIG_SETMASK, &tmpmask, &oldmask);
+ /* Enter a loop to get the existing signal status: */
+ for (i = 1; i <= _SIG_MAXSIG; i++) {
+ /* Check for signals which cannot be trapped: */
+ if (i == SIGKILL || i == SIGSTOP) {
+ }
+
+ /* Set the signal handler details: */
+ else if (__sys_sigaction(i, &_thread_sigact[i - 1], NULL) != 0) {
+ /*
+ * Abort this process if signal
+ * initialisation fails:
+ */
+ PANIC("Cannot set signal handler info");
+ }
+ }
+ __sys_sigprocmask(SIG_SETMASK, &oldmask, NULL);
+}
+
diff --git a/lib/libpthread/thread/thr_sigaction.c b/lib/libpthread/thread/thr_sigaction.c
index 7ede6d2..2bef7f2 100644
--- a/lib/libpthread/thread/thr_sigaction.c
+++ b/lib/libpthread/thread/thr_sigaction.c
@@ -43,16 +43,21 @@ _sigaction(int sig, const struct sigaction * act, struct sigaction * oact)
{
int ret = 0;
struct sigaction gact;
+ struct pthread *curthread;
+ kse_critical_t crit;
/* Check if the signal number is out of range: */
- if (sig < 1 || sig > NSIG) {
+ if (sig < 1 || sig > _SIG_MAXSIG) {
/* Return an invalid argument: */
errno = EINVAL;
ret = -1;
} else {
- if (_thr_initial == NULL)
- _libpthread_init(NULL);
+ if (!_kse_isthreaded())
+ return __sys_sigaction(sig, act, oact);
+ crit = _kse_critical_enter();
+ curthread = _get_curthread();
+ KSE_LOCK_ACQUIRE(curthread->kse, &_thread_signal_lock);
/*
* Check if the existing signal action structure contents are
* to be returned:
@@ -99,6 +104,8 @@ _sigaction(int sig, const struct sigaction * act, struct sigaction * oact)
if (__sys_sigaction(sig, &gact, NULL) != 0)
ret = -1;
}
+ KSE_LOCK_RELEASE(curthread->kse, &_thread_signal_lock);
+ _kse_critical_leave(crit);
}
/* Return the completion status: */
diff --git a/lib/libpthread/thread/thr_sigmask.c b/lib/libpthread/thread/thr_sigmask.c
index d9cb839..c8fcec8 100644
--- a/lib/libpthread/thread/thr_sigmask.c
+++ b/lib/libpthread/thread/thr_sigmask.c
@@ -48,33 +48,35 @@ _pthread_sigmask(int how, const sigset_t *set, sigset_t *oset)
struct pthread *curthread = _get_curthread();
int ret;
+ if (! _kse_isthreaded())
+ _kse_setthreaded(1);
+
+ THR_SCHED_LOCK(curthread, curthread);
ret = 0;
if (oset != NULL)
/* Return the current mask: */
- *oset = curthread->tmbx.tm_context.uc_sigmask;
+ *oset = curthread->sigmask;
/* Check if a new signal set was provided by the caller: */
if (set != NULL) {
- THR_SCHED_LOCK(curthread, curthread);
-
/* Process according to what to do: */
switch (how) {
/* Block signals: */
case SIG_BLOCK:
/* Add signals to the existing mask: */
- SIGSETOR(curthread->tmbx.tm_context.uc_sigmask, *set);
+ SIGSETOR(curthread->sigmask, *set);
break;
/* Unblock signals: */
case SIG_UNBLOCK:
/* Clear signals from the existing mask: */
- SIGSETNAND(curthread->tmbx.tm_context.uc_sigmask, *set);
+ SIGSETNAND(curthread->sigmask, *set);
break;
/* Set the signal process mask: */
case SIG_SETMASK:
/* Set the new mask: */
- curthread->tmbx.tm_context.uc_sigmask = *set;
+ curthread->sigmask = *set;
break;
/* Trap invalid actions: */
@@ -84,13 +86,7 @@ _pthread_sigmask(int how, const sigset_t *set, sigset_t *oset)
ret = -1;
break;
}
-
- if (ret == 0) {
- curthread->sigmask =
- curthread->tmbx.tm_context.uc_sigmask;
- curthread->sigmask_seqno++;
- }
-
+ SIG_CANTMASK(curthread->sigmask);
THR_SCHED_UNLOCK(curthread, curthread);
/*
@@ -98,6 +94,7 @@ _pthread_sigmask(int how, const sigset_t *set, sigset_t *oset)
*/
if (ret == 0)
_thr_sig_check_pending(curthread);
- }
+ } else
+ THR_SCHED_UNLOCK(curthread, curthread);
return (ret);
}
diff --git a/lib/libpthread/thread/thr_sigpending.c b/lib/libpthread/thread/thr_sigpending.c
index 7f42ff3..1b9b502 100644
--- a/lib/libpthread/thread/thr_sigpending.c
+++ b/lib/libpthread/thread/thr_sigpending.c
@@ -54,8 +54,13 @@ _sigpending(sigset_t *set)
ret = EINVAL;
}
else {
- *set = curthread->sigpend;
+ if (!_kse_isthreaded())
+ return __sys_sigpending(set);
+
crit = _kse_critical_enter();
+ KSE_SCHED_LOCK(curthread->kse, curthread->kseg);
+ *set = curthread->sigpend;
+ KSE_SCHED_UNLOCK(curthread->kse, curthread->kseg);
KSE_LOCK_ACQUIRE(curthread->kse, &_thread_signal_lock);
SIGSETOR(*set, _thr_proc_sigpending);
KSE_LOCK_RELEASE(curthread->kse, &_thread_signal_lock);
diff --git a/lib/libpthread/thread/thr_sigprocmask.c b/lib/libpthread/thread/thr_sigprocmask.c
index 9cb493a..262848a 100644
--- a/lib/libpthread/thread/thr_sigprocmask.c
+++ b/lib/libpthread/thread/thr_sigprocmask.c
@@ -46,8 +46,9 @@ _sigprocmask(int how, const sigset_t *set, sigset_t *oset)
{
int ret;
- ret = pthread_sigmask(how, set, oset);
- if ((ret == 0) && (_kse_isthreaded() == 0))
+ if (_kse_isthreaded() == 0)
ret = __sys_sigprocmask(how, set, oset);
+ else
+ ret = pthread_sigmask(how, set, oset);
return (ret);
}
diff --git a/lib/libpthread/thread/thr_sigsuspend.c b/lib/libpthread/thread/thr_sigsuspend.c
index 2da790d..8d087f5 100644
--- a/lib/libpthread/thread/thr_sigsuspend.c
+++ b/lib/libpthread/thread/thr_sigsuspend.c
@@ -44,14 +44,19 @@ _sigsuspend(const sigset_t *set)
{
struct pthread *curthread = _get_curthread();
int ret = -1;
+ sigset_t osigmask;
+
+ if (!_kse_isthreaded())
+ return __sys_sigsuspend(set);
/* Check if a new signal set was provided by the caller: */
if (set != NULL) {
THR_LOCK_SWITCH(curthread);
+ /* Save current sigmask */
+ memcpy(&osigmask, &curthread->sigmask, sizeof(osigmask));
/* Change the caller's mask: */
- memcpy(&curthread->tmbx.tm_context.uc_sigmask,
- set, sizeof(sigset_t));
+ memcpy(&curthread->sigmask, set, sizeof(sigset_t));
THR_SET_STATE(curthread, PS_SIGSUSPEND);
@@ -61,9 +66,15 @@ _sigsuspend(const sigset_t *set)
/* Always return an interrupted error: */
errno = EINTR;
+ THR_SCHED_LOCK(curthread, curthread);
/* Restore the signal mask: */
- memcpy(&curthread->tmbx.tm_context.uc_sigmask,
- &curthread->sigmask, sizeof(sigset_t));
+ memcpy(&curthread->sigmask, &osigmask, sizeof(sigset_t));
+ THR_SCHED_UNLOCK(curthread, curthread);
+ /*
+ * signal mask is reloaded, need to check if there is
+ * pending proc signal I can handle.
+ */
+ _thr_sig_check_pending(curthread);
} else {
/* Return an invalid argument error: */
errno = EINVAL;
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