diff options
Diffstat (limited to 'lib/qpnexus.c')
-rw-r--r-- | lib/qpnexus.c | 100 |
1 files changed, 56 insertions, 44 deletions
diff --git a/lib/qpnexus.c b/lib/qpnexus.c index 001d5049..8a805900 100644 --- a/lib/qpnexus.c +++ b/lib/qpnexus.c @@ -36,18 +36,39 @@ static void qpn_in_thread_init(qpn_nexus qpn); */ +/*------------------------------------------------------------------------------ + * Initialise the qpnexus handling -- to be done as soon as state of + * qpthreads_enabled is established. + */ +extern void +qpn_init(void) +{ + qpt_data_create(qpn_self) ; /* thread specific data */ +} ; + +/*------------------------------------------------------------------------------ + * Set the thread's qpn_self to point at its qpnexus. + */ +static void +qpn_self_knowledge(qpn_nexus qpn) +{ + qpt_data_set_value(qpn_self, qpn) ; +} ; + /*============================================================================== * Initialisation, add hook, free etc. * */ /*------------------------------------------------------------------------------ - * Initialise a nexus -- allocating it if required. + * Initialise a nexus -- allocating it if required. * - * If main_thread is set then no new thread will be created - * when qpn_exec() is called, instead the finite state machine will be - * run in the calling thread. The main thread will only block the - * message queue's signal. Non-main threads will block most signals. + * If main_thread is set then no new thread will be created when qpn_exec() is + * called, instead the finite state machine will be run in the calling thread. + * + * The main thread will only block the message queue's signal. + * + * Non-main threads will block most signals. * * Returns the qpn_nexus. */ @@ -66,10 +87,13 @@ qpn_init_new(qpn_nexus qpn, bool main_thread) qpn->start = qpn_start; if (main_thread) - qpn->thread_id = qpt_thread_self(); + { + qpn->thread_id = qpt_thread_self(); + qpn_self_knowledge(qpn) ; + } ; return qpn; -} +} ; /*------------------------------------------------------------------------------ * Add a hook function to the given nexus. @@ -259,50 +283,38 @@ qpn_start(void* arg) static void qpn_in_thread_init(qpn_nexus qpn) { - sigset_t newmask; + sigset_t sigmask[1]; qpn->thread_id = qpt_thread_self(); - + qpn_self_knowledge(qpn) ; + + /* Signal mask. + * + * The main thread blocks nothing, except SIG_INTERRUPT. So (a) all + * signals other than the "hard cases" are routed to the main thread, and + * (b) SIG_INTERRUPT is masked until it is unmasked in pselect. + * + * Other threads block everything except the hard cases and SIG_INTERRUPT. + */ if (qpn->main_thread) - { - /* Main thread, block the message queue's signal */ - sigemptyset (&newmask); - sigaddset (&newmask, SIGMQUEUE); - } + sigmakeset(sigmask, SIG_INTERRUPT, -1) ; else - { - /* - * Not main thread. Block most signals, but be careful not to - * defer SIGTRAP because doing so breaks gdb, at least on - * NetBSD 2.0. Avoid asking to block SIGKILL, just because - * we shouldn't be able to do so. Avoid blocking SIGFPE, - * SIGILL, SIGSEGV, SIGBUS as this is undefined by POSIX. - * Don't block SIGPIPE so that is gets ignored on this thread. - */ - sigfillset (&newmask); - sigdelset (&newmask, SIGTRAP); - sigdelset (&newmask, SIGKILL); - sigdelset (&newmask, SIGPIPE); - sigdelset (&newmask, SIGFPE); - sigdelset (&newmask, SIGILL); - sigdelset (&newmask, SIGSEGV); - sigdelset (&newmask, SIGBUS); - } + siginvset(sigmask, signal_get_hard_set()) ; - if (qpthreads_enabled) - qpt_thread_sigmask(SIG_BLOCK, &newmask, NULL); - else - { - if (sigprocmask(SIG_BLOCK, &newmask, NULL) != 0) - zabort_errno("sigprocmask failed") ; - } + qpt_thread_sigmask(SIG_BLOCK, sigmask, NULL); - /* Now we have thread_id and mask, prep for using message queue. */ + /* The signal mask to be used during pselect() */ + sigcopyset(qpn->pselect_mask, sigmask) ; + sigdelset(qpn->pselect_mask, SIG_INTERRUPT) ; + qpn->pselect_signal = SIG_INTERRUPT ; + + /* Now we have thread_id and mask, prep for using message queue. */ if (qpn->queue != NULL) - qpn->mts = mqueue_thread_signal_init(qpn->mts, qpn->thread_id, SIGMQUEUE); + qpn->mts = mqueue_thread_signal_init(qpn->mts, qpn->thread_id, + SIG_INTERRUPT) ; if (qpn->selection != NULL) - qps_set_signal(qpn->selection, SIGMQUEUE, newmask); -} + qps_set_signal(qpn->selection, qpn->pselect_mask); +} ; /*------------------------------------------------------------------------------ * Ask the thread to terminate itself quickly and cleanly. @@ -318,6 +330,6 @@ qpn_terminate(qpn_nexus qpn) /* wake up any pselect */ if (qpthreads_enabled) - qpt_thread_signal(qpn->thread_id, SIGMQUEUE); + qpt_thread_signal(qpn->thread_id, SIG_INTERRUPT); } ; } |