Cleanup some signal interfaces. Now the tdsignal function accepts

both proc pointer and thread pointer, if thread pointer is NULL,
tdsignal automatically finds a thread, otherwise it sends signal
to given thread.
Add utility function psignal_event to send a realtime sigevent
to a process according to the delivery requirement specified in
struct sigevent.
This commit is contained in:
David Xu 2005-11-03 04:49:16 +00:00
parent 165edba6a7
commit 6d7b314b14
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=151993
6 changed files with 67 additions and 86 deletions

View File

@ -670,7 +670,7 @@ do_execve(td, args, mac_p)
* single thread mode.
*/
if (p->p_flag & P_TRACED)
tdsignal(td, SIGTRAP, NULL, SIGTARGET_TD);
tdsignal(p, td, SIGTRAP, NULL);
/* clear "fork but no exec" flag, as we _are_ execing */
p->p_acflag &= ~AFORK;

View File

@ -210,7 +210,7 @@ kse_thr_interrupt(struct thread *td, struct kse_thr_interrupt_args *uap)
if (uap->data > 0) {
td2->td_flags &= ~TDF_INTERRUPT;
mtx_unlock_spin(&sched_lock);
tdsignal(td2, (int)uap->data, NULL, SIGTARGET_TD);
tdsignal(p, td2, (int)uap->data, NULL);
} else {
mtx_unlock_spin(&sched_lock);
}

View File

@ -96,9 +96,8 @@ static int filt_signal(struct knote *kn, long hint);
static struct thread *sigtd(struct proc *p, int sig, int prop);
static int kern_sigtimedwait(struct thread *, sigset_t,
ksiginfo_t *, struct timespec *);
static int do_tdsignal(struct thread *, int, ksiginfo_t *, sigtarget_t);
static int do_tdsignal(struct proc *, struct thread *, int, ksiginfo_t *);
static void sigqueue_start(void);
static int psignal_common(struct proc *p, int sig, ksiginfo_t *ksi);
static uma_zone_t ksiginfo_zone = NULL;
struct filterops sig_filtops =
@ -1787,7 +1786,7 @@ sigqueue(struct thread *td, struct sigqueue_args *uap)
ksi.ksi_pid = td->td_proc->p_pid;
ksi.ksi_uid = td->td_ucred->cr_ruid;
ksi.ksi_value.sigval_ptr = uap->value;
error = psignal_info(p, &ksi);
error = tdsignal(p, NULL, ksi.ksi_signo, &ksi);
}
PROC_UNLOCK(p);
return (error);
@ -1922,7 +1921,7 @@ trapsignal(struct thread *td, ksiginfo_t *ksi)
mtx_unlock(&ps->ps_mtx);
p->p_code = code; /* XXX for core dump/debugger */
p->p_sig = sig; /* XXX to verify code */
tdsignal(td, sig, ksi, SIGTARGET_TD);
tdsignal(p, td, sig, ksi);
}
PROC_UNLOCK(p);
}
@ -1972,53 +1971,44 @@ sigtd(struct proc *p, int sig, int prop)
void
psignal(struct proc *p, int sig)
{
(void) psignal_common(p, sig, NULL);
(void) tdsignal(p, NULL, sig, NULL);
}
int
psignal_info(struct proc *p, ksiginfo_t *ksi)
psignal_event(struct proc *p, struct sigevent *sigev, ksiginfo_t *ksi)
{
return (psignal_common(p, ksi->ksi_signo, ksi));
}
static int
psignal_common(struct proc *p, int sig, ksiginfo_t *ksi)
{
struct thread *td;
int prop;
if (!_SIG_VALID(sig))
panic("psignal(): invalid signal");
struct thread *td = NULL;
PROC_LOCK_ASSERT(p, MA_OWNED);
/*
* IEEE Std 1003.1-2001: return success when killing a zombie.
*/
if (p->p_state == PRS_ZOMBIE)
return (0);
prop = sigprop(sig);
KASSERT(!KSI_ONQ(ksi), ("psignal_event: ksi on queue"));
/*
* Find a thread to deliver the signal to.
* ksi_code and other fields should be set before
* calling this function.
*/
td = sigtd(p, sig, prop);
return (tdsignal(td, sig, ksi, SIGTARGET_P));
ksi->ksi_signo = sigev->sigev_signo;
ksi->ksi_value = sigev->sigev_value;
if (sigev->sigev_notify == SIGEV_THREAD_ID) {
td = thread_find(p, sigev->sigev_notify_thread_id);
if (td == NULL)
return (ESRCH);
}
return (tdsignal(p, td, ksi->ksi_signo, ksi));
}
/*
* MPSAFE
*/
int
tdsignal(struct thread *td, int sig, ksiginfo_t *ksi, sigtarget_t target)
tdsignal(struct proc *p, struct thread *td, int sig, ksiginfo_t *ksi)
{
sigset_t saved;
struct proc *p = td->td_proc;
int ret;
if (p->p_flag & P_SA)
saved = p->p_sigqueue.sq_signals;
ret = do_tdsignal(td, sig, ksi, target);
ret = do_tdsignal(p, td, sig, ksi);
if ((p->p_flag & P_SA) && !(p->p_flag & P_SIGEVENT)) {
if (!SIGSETEQ(saved, p->p_sigqueue.sq_signals)) {
/* pending set changed */
@ -2030,9 +2020,8 @@ tdsignal(struct thread *td, int sig, ksiginfo_t *ksi, sigtarget_t target)
}
static int
do_tdsignal(struct thread *td, int sig, ksiginfo_t *ksi, sigtarget_t target)
do_tdsignal(struct proc *p, struct thread *td, int sig, ksiginfo_t *ksi)
{
struct proc *p;
sig_t action;
sigqueue_t *sigqueue;
struct thread *td0;
@ -2040,15 +2029,24 @@ do_tdsignal(struct thread *td, int sig, ksiginfo_t *ksi, sigtarget_t target)
struct sigacts *ps;
int ret = 0;
PROC_LOCK_ASSERT(p, MA_OWNED);
if (!_SIG_VALID(sig))
panic("do_tdsignal(): invalid signal");
p = td->td_proc;
KASSERT(ksi == NULL || !KSI_ONQ(ksi), ("do_tdsignal: ksi on queue"));
/*
* IEEE Std 1003.1-2001: return success when killing a zombie.
*/
if (p->p_state == PRS_ZOMBIE) {
if (ksi && (ksi->ksi_flags & KSI_INS))
ksiginfo_tryfree(ksi);
return (ret);
}
ps = p->p_sigacts;
PROC_LOCK_ASSERT(p, MA_OWNED);
KNOTE_LOCKED(&p->p_klist, NOTE_SIGNAL | sig);
prop = sigprop(sig);
/*
@ -2056,13 +2054,15 @@ do_tdsignal(struct thread *td, int sig, ksiginfo_t *ksi, sigtarget_t target)
* assign it to the process so that we can find it later in the first
* thread that unblocks it. Otherwise, assign it to this thread now.
*/
if (target == SIGTARGET_TD) {
sigqueue = &td->td_sigqueue;
} else {
if (!SIGISMEMBER(td->td_sigmask, sig))
sigqueue = &td->td_sigqueue;
else
if (td == NULL) {
td = sigtd(p, sig, prop);
if (SIGISMEMBER(td->td_sigmask, sig))
sigqueue = &p->p_sigqueue;
else
sigqueue = &td->td_sigqueue;
} else {
KASSERT(td->td_proc == p, ("invalid thread"));
sigqueue = &td->td_sigqueue;
}
/*
@ -2077,6 +2077,8 @@ do_tdsignal(struct thread *td, int sig, ksiginfo_t *ksi, sigtarget_t target)
if (SIGISMEMBER(ps->ps_sigignore, sig) ||
(p->p_flag & P_WEXIT)) {
mtx_unlock(&ps->ps_mtx);
if (ksi && (ksi->ksi_flags & KSI_INS))
ksiginfo_tryfree(ksi);
return (ret);
}
if (SIGISMEMBER(td->td_sigmask, sig))
@ -2098,8 +2100,11 @@ do_tdsignal(struct thread *td, int sig, ksiginfo_t *ksi, sigtarget_t target)
*/
if ((prop & SA_TTYSTOP) &&
(p->p_pgrp->pg_jobc == 0) &&
(action == SIG_DFL))
return (ret);
(action == SIG_DFL)) {
if (ksi && (ksi->ksi_flags & KSI_INS))
ksiginfo_tryfree(ksi);
return (ret);
}
sigqueue_delete_proc(p, SIGCONT);
p->p_flag &= ~P_CONTINUED;
}
@ -2107,7 +2112,7 @@ do_tdsignal(struct thread *td, int sig, ksiginfo_t *ksi, sigtarget_t target)
ret = sigqueue_add(sigqueue, sig, ksi);
if (ret != 0)
return (ret);
signotify(td); /* uses schedlock */
signotify(td);
/*
* Defer further processing for signals which are held,
* except that stopped processes must be continued by SIGCONT.

View File

@ -321,7 +321,7 @@ thr_kill(struct thread *td, struct thr_kill_args *uap)
error = EINVAL;
goto out;
}
tdsignal(ttd, uap->sig, NULL, SIGTARGET_TD);
tdsignal(p, ttd, uap->sig, NULL);
out:
PROC_UNLOCK(p);
return (error);

View File

@ -1413,46 +1413,29 @@ void
itimer_fire(struct itimer *it)
{
struct proc *p = it->it_proc;
struct thread *td;
int ret;
if (it->it_sigev.sigev_notify == SIGEV_SIGNAL ||
it->it_sigev.sigev_notify == SIGEV_THREAD_ID) {
PROC_LOCK(p);
if (KSI_ONQ(&it->it_ksi)) {
it->it_overrun++;
} else {
if (it->it_sigev.sigev_notify == SIGEV_THREAD_ID) {
/* XXX
* This is too slow if there are many threads,
* why the world don't have a thread hash table,
* sigh.
if (!KSI_ONQ(&it->it_ksi)) {
ret = psignal_event(p, &it->it_sigev, &it->it_ksi);
if (__predict_false(ret != 0)) {
it->it_overrun++;
/*
* Broken userland code, thread went
* away, disarm the timer.
*/
FOREACH_THREAD_IN_PROC(p, td) {
if (td->td_tid ==
it->it_sigev.sigev_notify_thread_id)
break;
}
if (td != NULL)
tdsignal(td, it->it_ksi.ksi_signo,
&it->it_ksi, SIGTARGET_TD);
else {
/*
* Broken userland code, thread went
* away, disarm the timer.
*/
#if 0
it->it_overrun++;
#else
if (ret == ESRCH) {
ITIMER_LOCK(it);
timespecclear(&it->it_time.it_value);
timespecclear(&it->it_time.it_interval);
callout_stop(&it->it_callout);
ITIMER_UNLOCK(it);
#endif
}
} else {
psignal_info(p, &it->it_ksi);
}
} else {
it->it_overrun++;
}
PROC_UNLOCK(p);
}

View File

@ -248,13 +248,6 @@ typedef struct sigqueue {
#ifdef _KERNEL
/*
* Specifies the target of a signal.
* P - Doesn't matter which thread it gets delivered to.
* TD - Must be delivered to a specific thread.
*/
typedef enum sigtarget_enum { SIGTARGET_P, SIGTARGET_TD } sigtarget_t;
/* Return nonzero if process p has an unmasked pending signal. */
#define SIGPENDING(td) \
(!SIGISEMPTY((td)->td_siglist) && \
@ -326,7 +319,7 @@ void pgsigio(struct sigio **, int signum, int checkctty);
void pgsignal(struct pgrp *pgrp, int sig, int checkctty);
void postsig(int sig);
void psignal(struct proc *p, int sig);
int psignal_info(struct proc *p, ksiginfo_t *ksi);
int psignal_event(struct proc *p, struct sigevent *, ksiginfo_t *);
struct sigacts *sigacts_alloc(void);
void sigacts_copy(struct sigacts *dest, struct sigacts *src);
void sigacts_free(struct sigacts *ps);
@ -336,8 +329,8 @@ void sigexit(struct thread *td, int signum) __dead2;
int sig_ffs(sigset_t *set);
void siginit(struct proc *p);
void signotify(struct thread *td);
int tdsignal(struct thread *td, int sig, ksiginfo_t *ksi,
sigtarget_t target);
int tdsignal(struct proc *p, struct thread *td, int sig,
ksiginfo_t *ksi);
void trapsignal(struct thread *td, ksiginfo_t *);
int ptracestop(struct thread *td, int sig);
ksiginfo_t * ksiginfo_alloc(void);