672 lines
17 KiB
C
Executable File
672 lines
17 KiB
C
Executable File
/* Copyright (c) 1993 SMI */
|
|
/* All Rights Reserved */
|
|
|
|
/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF SMI */
|
|
/* The copyright notice above does not evidence any */
|
|
/* actual or intended publication of such source code. */
|
|
|
|
#pragma ident "@(#)sig.c 1.74 95/05/10 SMI"
|
|
|
|
|
|
#include "libthread.h"
|
|
#include <sys/reg.h>
|
|
#include <errno.h>
|
|
|
|
/*
|
|
* Global variable
|
|
*/
|
|
sigset_t _cantmask; /* initialized in _t0init() */
|
|
sigset_t _lcantmask; /* set of signals libthread can't mask */
|
|
int _sigwaitingset = 0; /* tells when SIGWAITING is enabled */
|
|
thread_t __dynamic_tid; /* aslwp's tid */
|
|
|
|
/*
|
|
* Static function
|
|
*/
|
|
static void _resetsig();
|
|
static void _bouncesigs();
|
|
static void _dodynamiclwps();
|
|
|
|
/*
|
|
* Static variables
|
|
*/
|
|
static struct sigaction _acton =
|
|
{SA_RESTART|SA_WAITSIG, _dodynamiclwps, 0};
|
|
static struct sigaction _actoff = {0, SIG_IGN, 0};
|
|
|
|
|
|
void
|
|
_sigon()
|
|
{
|
|
extern void __sendsig();
|
|
extern void __bounceself();
|
|
uthread_t *t = curthread;
|
|
uthread_t *tt;
|
|
|
|
again:
|
|
/*
|
|
* Bail out if nosig is on.
|
|
* If we're in the SIGLWP handler, bail out now because we'll handle
|
|
* any pending signals at the end of the handler instead.
|
|
*/
|
|
if (--t->t_nosig || (t->t_flag & T_INSIGLWP))
|
|
return;
|
|
if (t->t_preempt | t->t_pending | t->t_stop | t->t_bdirpend
|
|
| t->t_sig) {
|
|
if (t->t_preempt | t->t_stop) {
|
|
/*
|
|
* This thread could have been preempted while in a
|
|
* critical section (t->t_nosig > 0) or the thread was
|
|
* preempted while being dispatched.
|
|
*/
|
|
t->t_preempt = 0;
|
|
/* disable preemption */
|
|
t->t_nosig++;
|
|
_sched_lock_nosig();
|
|
_dopreempt();
|
|
/* sched lock is unlocked by _dopreempt() */
|
|
/*
|
|
* check if thread was preempted on its return
|
|
* from _dopreempt(). if it wasn't preempted, then
|
|
* preemption is enabled by decrementing t_nosig
|
|
* at the top of this loop.
|
|
*/
|
|
goto again;
|
|
}
|
|
/*
|
|
* If a signal was received while in the critical section, but
|
|
* which was blocked by the current thread, it needs to be
|
|
* re-directed to other threads now.
|
|
* Note that there could be more than one signal (recorded in
|
|
* _bpending) - this is because all signals are not blocked
|
|
* as soon as the first such signal is received as is done in
|
|
* the case of t_sig. Other threads also could have contributed.
|
|
*/
|
|
/*
|
|
* Handle stored signal first!
|
|
*/
|
|
|
|
if (t->t_sig) {
|
|
/*
|
|
* The following two lines are CRUCIAL! Otherwise, the
|
|
* linker could be invoked on the call to __sendsig().
|
|
* The linker calls _sigon()/_sigoff() indirectly via
|
|
* the _lrw_lock()/unlock() calls and this would result
|
|
* in a recursive call which ends up here - unless t_sig
|
|
* is cleared before calling __sendsig().
|
|
*/
|
|
int sig = t->t_sig;
|
|
t->t_sig = 0;
|
|
__sendsig(sig);
|
|
}
|
|
if (t->t_pending)
|
|
_resetsig();
|
|
if (t->t_bdirpend)
|
|
__bounceself();
|
|
}
|
|
}
|
|
|
|
void
|
|
_sigoff()
|
|
{
|
|
curthread->t_nosig++;
|
|
}
|
|
|
|
/*
|
|
* _deliversigs() is used to deliver signals which were sent via
|
|
* _thr_kill() but have not yet been received by the target thread
|
|
* or those which are blocked in the process virtual signal mask and this
|
|
* thread unblocked one of them.
|
|
* Note that _deliversigs() will not result in "multiplication" of signals,
|
|
* since signals received via lwp_kill() are matched with the t_ssig mask.
|
|
* If the signal is not in the mask, it is ignored.
|
|
*/
|
|
void
|
|
_deliversigs(const sigset_t *nmask)
|
|
{
|
|
sigset_t olwpmask;
|
|
sigset_t resend;
|
|
uthread_t *t = curthread;
|
|
register int sig;
|
|
|
|
if (!sigisempty(&t->t_ssig)) {
|
|
/* block all signals */
|
|
__sigprocmask(SIG_SETMASK, &_totalmasked, &olwpmask);
|
|
_sched_lock_nosig();
|
|
if (_blocking(&t->t_ssig, &t->t_hold, (sigset_t *)nmask,
|
|
&resend)) {
|
|
_sched_unlock_nosig();
|
|
ASSERT(!sigcmpset(&olwpmask, &_totalmasked) ||
|
|
(!sigand(&olwpmask, &resend)));
|
|
while (sig = _fsig(&resend)) {
|
|
sigdelset(&resend, sig);
|
|
if (_lwp_kill(LWPID(t), sig) != 0)
|
|
_panic("_deliversigs: _lwp_kill");
|
|
}
|
|
} else
|
|
_sched_unlock_nosig();
|
|
__sigprocmask(SIG_SETMASK, &olwpmask, NULL);
|
|
}
|
|
}
|
|
|
|
void
|
|
__unsafe_bsigs(sigset_t *sigs)
|
|
{
|
|
register int sig;
|
|
uthread_t *t = curthread;
|
|
|
|
while (sig = _fsig(sigs)) {
|
|
sigdelset(sigs, sig);
|
|
while (_lwp_sigredirect(LWPID(t), sig) == 0);
|
|
}
|
|
}
|
|
|
|
void
|
|
_bsigs(sigset_t *sigs)
|
|
{
|
|
sigset_t olwpmask;
|
|
|
|
__sigprocmask(SIG_SETMASK, &_totalmasked, &olwpmask);
|
|
ASSERT(!sigand(&olwpmask, sigs));
|
|
__unsafe_bsigs(sigs);
|
|
__sigprocmask(SIG_SETMASK, &olwpmask, NULL);
|
|
}
|
|
|
|
void
|
|
__bounceself()
|
|
{
|
|
sigset_t olwpmask;
|
|
sigset_t sigs;
|
|
uthread_t *t = curthread;
|
|
extern void _sigunblock();
|
|
|
|
__sigprocmask(SIG_SETMASK, &_totalmasked, &olwpmask);
|
|
if (sigcmpset(&_totalmasked, &olwpmask) == 0)
|
|
return;
|
|
if (t->t_bdirpend) {
|
|
_sched_lock_nosig();
|
|
_sigunblock(&t->t_bsig, &t->t_hold, &sigs);
|
|
if (!sigisempty(&sigs)) {
|
|
t->t_bdirpend = !sigisempty(&t->t_bsig);
|
|
if (t->t_bdirpend == 0)
|
|
t->t_flag &= ~T_BSSIG;
|
|
_sched_unlock_nosig();
|
|
__unsafe_bsigs(&sigs);
|
|
ASSERT(!sigand(&olwpmask, &sigs));
|
|
} else
|
|
_sched_unlock_nosig();
|
|
}
|
|
__sigprocmask(SIG_SETMASK, &olwpmask, NULL);
|
|
}
|
|
|
|
/*
|
|
* redispatch the set of currently unblocked signals to the active
|
|
* thread. signals are masked while resending the signals but are
|
|
* delivered when the thread's mask is restored.
|
|
*/
|
|
static void
|
|
_resetsig()
|
|
{
|
|
uthread_t *t = curthread;
|
|
int sig;
|
|
sigset_t signalled;
|
|
sigset_t psig;
|
|
sigset_t olwpmask;
|
|
|
|
__sigprocmask(SIG_SETMASK, &_totalmasked, &olwpmask);
|
|
/*
|
|
* When all signals are already masked in this LWP
|
|
* (olwpmask == _totalmasked), no pending signals should
|
|
* be resent. This is a hack that prevents the linker from
|
|
* calling _resetsig() recursively. It shall be removed
|
|
* when the library is rebuilt with -Bsymbolic.
|
|
*/
|
|
if (sigcmpset(&_totalmasked, &olwpmask) == 0)
|
|
return;
|
|
/*
|
|
* t_pending could be zero here since the corresponding
|
|
* signal could have occurred in the window between the
|
|
* check for t_pending and the call to _resetsig() in _sigon().
|
|
*/
|
|
if (t->t_pending) {
|
|
_sched_lock_nosig();
|
|
_sigmaskset(&t->t_psig, &t->t_hold, &psig);
|
|
t->t_pending = !sigisempty(&t->t_psig);
|
|
_sched_unlock_nosig();
|
|
|
|
signalled = psig;
|
|
while (sig = _fsig(&psig)) {
|
|
sigdelset(&psig, sig);
|
|
if (_lwp_kill(LWPID(t), sig) < 0)
|
|
_panic("_resetsig: _lwp_kill");
|
|
}
|
|
_sched_lock_nosig();
|
|
sigorset(&t->t_ssig, &signalled);
|
|
ASSERT(sigisempty(&signalled) || !sigisempty(&t->t_ssig));
|
|
ASSERT((t->t_flag & T_TEMPBOUND) ||
|
|
!sigand(&olwpmask, &signalled));
|
|
_sched_unlock_nosig();
|
|
}
|
|
__sigprocmask(SIG_SETMASK, &olwpmask, NULL);
|
|
}
|
|
|
|
/*
|
|
* The following depends on the HASH_TID function to be (tid % ALLTHR_TBLSIZ).
|
|
* If this function changes in the future, the traversal of the allthreads
|
|
* list below has to be always from 1 to (ALLTHR_TBLSIZ - 1). Then you
|
|
* may not be able to optimize such that the search can stop at maxtid as
|
|
* is being done below. Returns 0 on success and 1 on failure.
|
|
*/
|
|
int
|
|
_sigredirect(int sig)
|
|
{
|
|
|
|
register int i, maxtid;
|
|
uthread_t *first, *t;
|
|
lwpid_t lwpid;
|
|
|
|
|
|
/*
|
|
* Called with all signals blocked.
|
|
* First record the signal to be bounced in the virtual process mask.
|
|
* This is important and has to be done before reading _lasttid.
|
|
*/
|
|
|
|
_lwp_mutex_lock(&_pmasklock);
|
|
dbg_sigaddset(&_tpmask, sig);
|
|
sigaddset(&_pmask, sig);
|
|
_lwp_mutex_unlock(&_pmasklock);
|
|
|
|
_lmutex_lock(&_tidlock);
|
|
maxtid = _lasttid;
|
|
_lmutex_unlock(&_tidlock);
|
|
|
|
if (maxtid >= ALLTHR_TBLSIZ)
|
|
maxtid = ALLTHR_TBLSIZ - 1;
|
|
/*
|
|
* Now start the search for a candidate recipient thread.
|
|
* Note that it is OK to NOT hold _schedlock over the whole search
|
|
* to prevent threads from changing their signal masks.
|
|
* Reason this algorithm works:
|
|
* Since sig has already been recorded above, if a thread which has
|
|
* been passed over in the search, now unblocks sig, it will get the
|
|
* signal. Now, when and if a candidate is found, check if the sig is
|
|
* still in the _pmask. If not, you are done, since this means some
|
|
* other thread self-delivered it. If yes, then send the sig to the
|
|
* candidate thread which is guaranteed to receive it. If a candidate
|
|
* thread is not found, just return.
|
|
*/
|
|
for (i = 1; i <= maxtid; i++) {
|
|
_restartbkt:
|
|
_lock_bucket(i);
|
|
if ((first = _allthreads[i].first) == NULL) {
|
|
_unlock_bucket(i);
|
|
continue;
|
|
}
|
|
_sched_lock_nosig();
|
|
t = first;
|
|
do {
|
|
if (!(t->t_usropts & THR_DAEMON) &&
|
|
!sigismember(&t->t_hold, sig) &&
|
|
t->t_state != TS_ZOMB &&
|
|
t->t_state != TS_STOPPED &&
|
|
t->t_preempt != 1 &&
|
|
t->t_stop != 1) {
|
|
/* found candidate */
|
|
_lwp_mutex_lock(&_pmasklock);
|
|
if (sigismember(&_pmask, sig)) {
|
|
sigdelset(&_pmask, sig);
|
|
dbg_delset(&_tpmask, sig);
|
|
_lwp_mutex_unlock(&_pmasklock);
|
|
if (_tsiguhandler[sig-1] == SIG_IGN ||
|
|
(_tsiguhandler[sig-1] == SIG_DFL &&
|
|
sigismember(&_ignoredefault,
|
|
sig))) {
|
|
/*
|
|
* ignore this signal
|
|
*/
|
|
_sched_unlock_nosig();
|
|
_unlock_bucket(i);
|
|
return (1);
|
|
}
|
|
if (__thr_sigredirect(t, i, sig,
|
|
&lwpid)) {
|
|
/* __thr_sigredirect failed */
|
|
_lwp_mutex_lock(&_pmasklock);
|
|
dbg_sigaddset(&_tpmask, sig);
|
|
sigaddset(&_pmask, sig);
|
|
_lwp_mutex_unlock(&_pmasklock);
|
|
continue;
|
|
} else if (lwpid != NULL) {
|
|
_sched_unlock_nosig();
|
|
_unlock_bucket(i);
|
|
_lwp_sigredirect(lwpid, sig);
|
|
return (1);
|
|
}
|
|
} else {
|
|
dbg_delset(&_tpmask, sig);
|
|
_lwp_mutex_unlock(&_pmasklock);
|
|
}
|
|
/*
|
|
* either sig was delivered by some other thread
|
|
* or the above _thr_kill() was successful.
|
|
*/
|
|
_sched_unlock_nosig();
|
|
_unlock_bucket(i);
|
|
return (1); /* success */
|
|
}
|
|
} while ((t = t->t_next) != first);
|
|
_sched_unlock_nosig();
|
|
_unlock_bucket(i);
|
|
/*
|
|
* Quick check to see if some other thread delivered sig.
|
|
*/
|
|
_lwp_mutex_lock(&_pmasklock);
|
|
if (!sigismember(&_pmask, sig)) {
|
|
dbg_delset(&_tpmask, sig);
|
|
_lwp_mutex_unlock(&_pmasklock);
|
|
return (1); /* success */
|
|
}
|
|
_lwp_mutex_unlock(&_pmasklock);
|
|
}
|
|
_lwp_mutex_lock(&_pmasklock);
|
|
dbg_delset(&_tpmask, sig);
|
|
_lwp_mutex_unlock(&_pmasklock);
|
|
_cond_broadcast(&_sigwait_cv);
|
|
return (0); /* failed to find a thread to send the signal to */
|
|
}
|
|
|
|
/*
|
|
* _siglwp: SIGLWP handler
|
|
*/
|
|
void
|
|
_siglwp(int sig, siginfo_t *sip, ucontext_t *uap)
|
|
{
|
|
uthread_t *t = curthread;
|
|
int switched;
|
|
|
|
_sched_lock();
|
|
ASSERT(sigismember(&curthread->t_hold, SIGLWP));
|
|
if (!ONPROCQ(t) || STOPPED(t)) {
|
|
ASSERT(curthread->t_state != TS_SLEEP);
|
|
if (ISBOUND(t) && !t->t_stop)
|
|
_panic("_siglwp: preempting bound thread");
|
|
#ifdef DEBUG
|
|
if (STOPPED(t)) {
|
|
ASSERT((curthread->t_forw == curthread->t_backw) &&
|
|
curthread->t_forw == NULL);
|
|
}
|
|
#endif
|
|
_dopreempt();
|
|
/*
|
|
* Turn off T_INSIGLWP flag to allow _sigon() to handle any
|
|
* pending signals before we leave the handler.
|
|
*/
|
|
t->t_flag &= ~T_INSIGLWP;
|
|
_sigon();
|
|
/*
|
|
* signals are left disabled on return from _dopreempt().
|
|
* _sigon() checks if a signal was sent to this thread
|
|
* when it had signals disabled.
|
|
*/
|
|
} else
|
|
_sched_unlock();
|
|
}
|
|
|
|
/*
|
|
* A dummy signal handler that enables the dynamiclwps() thread
|
|
* to catch SIGWAITING signals. This routine will never be called
|
|
* because the dynamiclwps() thread synchronously waits for a SIGWAITING
|
|
* signal by doing a sigwait(). This routine enables the process to
|
|
* catch SIGWAITING by registering a handle with sigaction(). A SIGWAITING
|
|
* signal, however, will always be sent to the dynamiclwps() thread because
|
|
* all threads except the dynamiclwps() thread have SIGWAITING blocked.
|
|
*/
|
|
static void
|
|
_dodynamiclwps()
|
|
{}
|
|
|
|
/*
|
|
* This is the thread that blocks waiting to receive SIGWAITING
|
|
* signals when SIGWAITING is enabled.
|
|
*/
|
|
void
|
|
_dynamiclwps()
|
|
{
|
|
int sig = 0;
|
|
int sig2 = 0;
|
|
char msg[120];
|
|
sigset_t sigs;
|
|
|
|
while (1) {
|
|
sig = _signotifywait();
|
|
if (sig == SIGWAITING) {
|
|
sigemptyset(&sigs);
|
|
sigaddset(&sigs, sig);
|
|
sig2 = (*__sigtimedwait_trap)(&sigs, NULL, NULL);
|
|
ASSERT(sig == sig2);
|
|
_sched_lock_nosig();
|
|
if (!_nrunnable ||(_nrunnable - _nidlecnt) <= _naging) {
|
|
/* disable sigwaiting */
|
|
if (_sigwaitingset) {
|
|
_sigwaitingset = 0;
|
|
__sigaction(SIGWAITING, &_actoff, NULL);
|
|
}
|
|
_sched_unlock_nosig();
|
|
} else {
|
|
_sched_unlock_nosig();
|
|
if (_new_lwp(NULL, _age))
|
|
_panic("cannot create new lwp");
|
|
}
|
|
} else if (sig > 0) {
|
|
ASSERT(!sigismember(&_pmask, sig));
|
|
_sigredirect(sig);
|
|
} else if (sig != -1 ||
|
|
(errno != EINTR && errno != EACCES && errno != EAGAIN)) {
|
|
_panic("_dynamiclwps(): bad return: _signotifywait()");
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* enable the SIGWAITING handler. this only happens when there are
|
|
* more runnable threads than there are lwps. SIGWAITING notifies the
|
|
* thread library to allocate more lwps because the current set of lwps
|
|
* are blocked on system calls.
|
|
*/
|
|
void
|
|
_sigwaiting_enabled()
|
|
{
|
|
|
|
ASSERT(_sigwaitingset == 0);
|
|
__sigaction(SIGWAITING, &_acton, NULL);
|
|
_sigwaitingset = 1;
|
|
}
|
|
|
|
void
|
|
_dynamic_create()
|
|
{
|
|
uthread_t *t;
|
|
caddr_t stk, tls;
|
|
char buf[64];
|
|
int ret;
|
|
int ix;
|
|
uthread_t *first;
|
|
|
|
|
|
/*
|
|
* XXX: Use big, default stacks for now, since the dynamic linker may
|
|
* use a huge stack. When this linker bug gets fixed, revert back to
|
|
* using smaller stacks for daemon threads like the sigwaiting lwp.
|
|
*/
|
|
if (!_alloc_thread(NULL, 0, &t)) {
|
|
_panic("_dynamic_create():alloc_thread returns 0(no memory)");
|
|
}
|
|
/*
|
|
* do this only if you want this lwp to appear as a thread
|
|
* to the user.
|
|
*/
|
|
_mutex_lock(&_tidlock);
|
|
t->t_tid = (thread_t) ++_lasttid;
|
|
_mutex_unlock(&_tidlock);
|
|
__dynamic_tid = t->t_tid;
|
|
ix = HASH_TID(t->t_tid);
|
|
_mutex_lock(&(_allthreads[ix].lock));
|
|
if ((first = _allthreads[ix].first) == NULL)
|
|
_allthreads[ix].first = t->t_next =
|
|
t->t_prev = t;
|
|
else {
|
|
t->t_prev = first->t_prev;
|
|
t->t_next = first;
|
|
first->t_prev->t_next = t;
|
|
first->t_prev = t;
|
|
}
|
|
_mutex_unlock(&(_allthreads[ix].lock));
|
|
masktotalsigs(&t->t_hold);
|
|
t->t_usropts = THR_BOUND | THR_DETACHED | THR_DAEMON;
|
|
t->t_flag |= T_INTERNAL;
|
|
_lwp_sema_init(&t->t_park, NULL);
|
|
t->t_state = TS_ONPROC;
|
|
ret = _lwp_exec(t, (int)_thr_exit, (caddr_t)t->t_sp, _dynamiclwps,
|
|
__LWP_ASLWP, &LWPID(t));
|
|
if (ret) {
|
|
sprintf(buf, "_dynamic_create() failed, errno = %d\n", ret);
|
|
_write(1, buf, strlen(buf));
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
static unsigned char highbit_table[256] = {
|
|
0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4,
|
|
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
|
|
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
|
|
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
|
|
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
|
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
|
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
|
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
|
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
|
|
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
|
|
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
|
|
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
|
|
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
|
|
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
|
|
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
|
|
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
|
|
};
|
|
|
|
/*
|
|
* Find high bit set. returns bit number + 1, otherwise 0.
|
|
*/
|
|
int
|
|
_hibit(register unsigned long i)
|
|
{
|
|
register unsigned long j;
|
|
register unsigned long k;
|
|
|
|
|
|
if (i == 0)
|
|
return (0);
|
|
if (j = (i >> 16)) {
|
|
if (k = (j >> 8))
|
|
return (highbit_table[k] + 24);
|
|
else
|
|
return (highbit_table[j] + 16);
|
|
} else if (k = (i >> 8))
|
|
return (highbit_table[k] + 8);
|
|
return (highbit_table[i]);
|
|
}
|
|
|
|
int
|
|
_fsig(sigset_t *s)
|
|
{
|
|
int i, sig;
|
|
|
|
for (i = 0; i < 4; i++) {
|
|
if (sig = _hibit(s->__sigbits[i]))
|
|
return (i*32 + sig);
|
|
}
|
|
return (0);
|
|
}
|
|
|
|
/*
|
|
* mask s2's signals out of the set of signals in s1 and
|
|
* place the result in s3. Then, clear all the signals in s3
|
|
* from s1 and place the result in s1.
|
|
*/
|
|
void
|
|
_sigunblock(sigset_t *s1, sigset_t *s2, sigset_t *s3)
|
|
{
|
|
_sigmaskset(s1, s2, s3);
|
|
if (!sigisempty(s3)) {
|
|
s1->__sigbits[0] &= ~s3->__sigbits[0];
|
|
s1->__sigbits[1] &= ~s3->__sigbits[1];
|
|
s1->__sigbits[2] &= ~s3->__sigbits[2];
|
|
s1->__sigbits[3] &= ~s3->__sigbits[3];
|
|
}
|
|
}
|
|
|
|
/*
|
|
* mask s2's signals out of the set of signals in s1 and
|
|
* place the result in s3.
|
|
*/
|
|
void
|
|
_sigmaskset(sigset_t *s1, sigset_t *s2, sigset_t *s3)
|
|
{
|
|
s3->__sigbits[0] = (s1->__sigbits[0] & ~s2->__sigbits[0]);
|
|
s3->__sigbits[1] = (s1->__sigbits[1] & ~s2->__sigbits[1]);
|
|
s3->__sigbits[2] = (s1->__sigbits[2] & ~s2->__sigbits[2]);
|
|
s3->__sigbits[3] = (s1->__sigbits[3] & ~s2->__sigbits[3]);
|
|
}
|
|
|
|
int
|
|
_blocksent(sigset_t *sent, sigset_t *old, const sigset_t *new)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < 4; i++)
|
|
if (~old->__sigbits[i] & new->__sigbits[i] & sent->__sigbits[i])
|
|
return (1);
|
|
return (0);
|
|
}
|
|
|
|
int
|
|
_blocking(sigset_t *sent, sigset_t *old, const sigset_t *new, sigset_t *resend)
|
|
{
|
|
int i;
|
|
|
|
sigemptyset(resend);
|
|
for (i = 0; i < 4; i++)
|
|
resend->__sigbits[i] = ~old->__sigbits[i] & new->__sigbits[i]
|
|
& sent->__sigbits[i];
|
|
return (!sigisempty(resend));
|
|
}
|
|
|
|
|
|
void
|
|
_resume_ret(uthread_t *oldthread)
|
|
{
|
|
uthread_t *t = curthread;
|
|
|
|
ITRACE_0(UTR_FAC_TLIB_SWTCH, UTR_RESUME_END, "_resume end");
|
|
TRACE_0(UTR_FAC_TRACE, UTR_THR_LWP_MAP, "dummy for thr_lwp mapping");
|
|
|
|
/* preemption is disabled until _sigon() is called */
|
|
ASSERT(t->t_nosig > 0);
|
|
ASSERT(oldthread == NULL || (oldthread->t_state == TS_ZOMB ||
|
|
oldthread->t_flag & T_IDLETHREAD));
|
|
ASSERT(t->t_idle->t_sig == 0);
|
|
if (oldthread != NULL && oldthread->t_state == TS_ZOMB)
|
|
_reapq_add(oldthread);
|
|
_sched_lock_nosig();
|
|
t->t_state = TS_ONPROC;
|
|
if (PREEMPTED(t))
|
|
t->t_preempt = 1;
|
|
_sched_unlock_nosig();
|
|
/*
|
|
* preemption is enabled by calling _sigon(). if thread was
|
|
* preempted, _sigon() will notice it and call _dopreempt().
|
|
*/
|
|
_sigon();
|
|
}
|