From 1226f694e66c1af1593fa0fc5f30e72932266b3b Mon Sep 17 00:00:00 2001 From: Juli Mallett Date: Mon, 30 Sep 2002 20:20:22 +0000 Subject: [PATCH] First half of implementation of ksiginfo, signal queues, and such. This gets signals operating based on a TailQ, and is good enough to run X11, GNOME, and do job control. There are some intricate parts which could be more refined to match the sigset_t versions, but those require further evaluation of directions in which our signal system can expand and contract to fit our needs. After this has been in the tree for a while, I will make in kernel API changes, most notably to trapsignal(9) and sendsig(9), to use ksiginfo more robustly, such that we can actually pass information with our (queued) signals to the userland. That will also result in using a struct ksiginfo pointer, rather than a signal number, in a lot of kern_sig.c, to refer to an individual pending signal queue member, but right now there is no defined behaviour for such. CODAFS is unfinished in this regard because the logic is unclear in some places. Sponsored by: New Gold Technology Reviewed by: bde, tjr, jake [an older version, logic similar] --- sys/alpha/osf1/osf1_signal.c | 3 +- sys/compat/linprocfs/linprocfs.c | 2 +- sys/compat/linux/linux_misc.c | 3 +- sys/compat/linux/linux_signal.c | 3 +- sys/compat/svr4/svr4_filio.c | 3 + sys/compat/svr4/svr4_signal.c | 2 +- sys/conf/files | 1 + sys/fs/procfs/procfs_ctl.c | 3 +- sys/kern/init_main.c | 2 + sys/kern/kern_exit.c | 9 +- sys/kern/kern_fork.c | 1 + sys/kern/kern_kthread.c | 17 +- sys/kern/kern_proc.c | 5 +- sys/kern/kern_sig.c | 64 ++++--- sys/kern/subr_sigq.c | 301 +++++++++++++++++++++++++++++++ sys/kern/subr_trap.c | 4 +- sys/kern/tty.c | 14 +- sys/sys/ksiginfo.h | 78 ++++++++ sys/sys/proc.h | 2 +- 19 files changed, 465 insertions(+), 52 deletions(-) create mode 100644 sys/kern/subr_sigq.c create mode 100644 sys/sys/ksiginfo.h diff --git a/sys/alpha/osf1/osf1_signal.c b/sys/alpha/osf1/osf1_signal.c index 7ea80fd8a2b6..4e42796d49d5 100644 --- a/sys/alpha/osf1/osf1_signal.c +++ b/sys/alpha/osf1/osf1_signal.c @@ -46,6 +46,7 @@ #include #include #include +#include #include #include #include @@ -523,7 +524,7 @@ osf1_sigpending(td, uap) p = td->td_proc; PROC_LOCK(p); - bss = p->p_siglist; + ksiginfo_to_sigset_t(p, &bss); SIGSETAND(bss, p->p_sigmask); PROC_UNLOCK(p); bsd_to_osf1_sigset(&bss, &oss); diff --git a/sys/compat/linprocfs/linprocfs.c b/sys/compat/linprocfs/linprocfs.c index d0db2936b56e..af542b43c5c7 100644 --- a/sys/compat/linprocfs/linprocfs.c +++ b/sys/compat/linprocfs/linprocfs.c @@ -651,7 +651,7 @@ linprocfs_doprocstatus(PFS_FILL_ARGS) * running on anything but i386, so ignore that for now. */ PROC_LOCK(p); - sbuf_printf(sb, "SigPnd:\t%08x\n", p->p_siglist.__bits[0]); + sbuf_printf(sb, "SigPnd:\t%08x\n", 0); /* XXX */ /* * I can't seem to find out where the signal mask is in * relation to struct proc, so SigBlk is left unimplemented. diff --git a/sys/compat/linux/linux_misc.c b/sys/compat/linux/linux_misc.c index 16c8677e0f44..d344548de97b 100644 --- a/sys/compat/linux/linux_misc.c +++ b/sys/compat/linux/linux_misc.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -832,7 +833,7 @@ linux_wait4(struct thread *td, struct linux_wait4_args *args) if ((error = wait4(td, &tmp)) != 0) return error; - SIGDELSET(td->td_proc->p_siglist, SIGCHLD); + signal_delete(td->td_proc, NULL, SIGCHLD); if (args->status) { if ((error = copyin((caddr_t)args->status, &tmpstat, diff --git a/sys/compat/linux/linux_signal.c b/sys/compat/linux/linux_signal.c index 532fb81a678a..d264db56cf85 100644 --- a/sys/compat/linux/linux_signal.c +++ b/sys/compat/linux/linux_signal.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include @@ -390,7 +391,7 @@ linux_sigpending(struct thread *td, struct linux_sigpending_args *args) #endif PROC_LOCK(p); - bset = p->p_siglist; + ksiginfo_to_sigset_t(p, &bset); SIGSETAND(bset, p->p_sigmask); bsd_to_linux_sigset(&bset, &lset); PROC_UNLOCK(p); diff --git a/sys/compat/svr4/svr4_filio.c b/sys/compat/svr4/svr4_filio.c index c2bad1d41b14..8dc1b4d0911c 100644 --- a/sys/compat/svr4/svr4_filio.c +++ b/sys/compat/svr4/svr4_filio.c @@ -39,6 +39,7 @@ #include #include #include +#include #include @@ -135,7 +136,9 @@ svr4_sys_read(td, uap) DPRINTF(("sigmask = 0x%x\n", td->td_proc->p_sigmask)); DPRINTF(("sigignore = 0x%x\n", td->td_proc->p_sigignore)); DPRINTF(("sigcaught = 0x%x\n", td->td_proc->p_sigcatch)); +#if 0 /* XXX - use ksiginfo_to_sigset_t ? */ DPRINTF(("siglist = 0x%x\n", td->td_proc->p_siglist)); +#endif } #if defined(GROTTY_READ_HACK) diff --git a/sys/compat/svr4/svr4_signal.c b/sys/compat/svr4/svr4_signal.c index fea531771410..1c78b5393510 100644 --- a/sys/compat/svr4/svr4_signal.c +++ b/sys/compat/svr4/svr4_signal.c @@ -565,7 +565,7 @@ svr4_sys_sigpending(td, uap) if (SCARG(uap, mask) == NULL) return 0; PROC_LOCK(td->td_proc); - bss = td->td_proc->p_siglist; + ksiginfo_to_sigset_t(td->td_proc, &bss); SIGSETAND(bss, td->td_proc->p_sigmask); PROC_UNLOCK(td->td_proc); bsd_to_svr4_sigset(&bss, &sss); diff --git a/sys/conf/files b/sys/conf/files index 73e62c0fa1c5..eccc3741d296 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -963,6 +963,7 @@ kern/subr_prof.c standard kern/subr_rman.c standard kern/subr_sbuf.c standard kern/subr_scanf.c standard +kern/subr_sigq.c standard kern/subr_smp.c optional smp kern/subr_taskqueue.c standard kern/subr_trap.c standard diff --git a/sys/fs/procfs/procfs_ctl.c b/sys/fs/procfs/procfs_ctl.c index c9572b6e904e..89f8de191d21 100644 --- a/sys/fs/procfs/procfs_ctl.c +++ b/sys/fs/procfs/procfs_ctl.c @@ -51,6 +51,7 @@ #include #include #include +#include #include #include @@ -221,7 +222,7 @@ out: p->p_flag &= ~P_TRACED; /* remove pending SIGTRAP, else the process will die */ - SIGDELSET(p->p_siglist, SIGTRAP); + signal_delete(p, NULL, SIGTRAP); PROC_UNLOCK(p); /* give process back to original parent */ diff --git a/sys/kern/init_main.c b/sys/kern/init_main.c index 49bb73980ef1..d58e7df18735 100644 --- a/sys/kern/init_main.c +++ b/sys/kern/init_main.c @@ -348,6 +348,8 @@ proc0_init(void *dummy __unused) LIST_INIT(&pgrp0.pg_members); LIST_INSERT_HEAD(&pgrp0.pg_members, p, p_pglist); + TAILQ_INIT(&p->p_sigq); + pgrp0.pg_session = &session0; mtx_init(&session0.s_mtx, "session", NULL, MTX_DEF); session0.s_count = 1; diff --git a/sys/kern/kern_exit.c b/sys/kern/kern_exit.c index 1725d5477e96..572aab31a4ac 100644 --- a/sys/kern/kern_exit.c +++ b/sys/kern/kern_exit.c @@ -67,6 +67,7 @@ #ifdef KTRACE #include #endif +#include #include #include @@ -244,7 +245,7 @@ exit1(td, rv) */ PROC_LOCK(p); p->p_flag &= ~(P_TRACED | P_PPWAIT); - SIGEMPTYSET(p->p_siglist); + signal_delete(p, NULL, 0); PROC_UNLOCK(p); if (timevalisset(&p->p_realtimer.it_value)) callout_stop(&p->p_itcallout); @@ -473,6 +474,12 @@ exit1(td, rv) */ if (p->p_flag & P_KTHREAD) wakeup(p); + + /* + * And now, kill off its signals... + */ + signal_delete(p, NULL, 0); + PROC_UNLOCK(p); /* diff --git a/sys/kern/kern_fork.c b/sys/kern/kern_fork.c index da7ca7dad1a8..c8182f984a62 100644 --- a/sys/kern/kern_fork.c +++ b/sys/kern/kern_fork.c @@ -605,6 +605,7 @@ again: LIST_INSERT_AFTER(p1, p2, p_pglist); PGRP_UNLOCK(p1->p_pgrp); LIST_INIT(&p2->p_children); + TAILQ_INIT(&p2->p_sigq); callout_init(&p2->p_itcallout, 0); diff --git a/sys/kern/kern_kthread.c b/sys/kern/kern_kthread.c index 08ef71f8b31c..95e9a68f3ff9 100644 --- a/sys/kern/kern_kthread.c +++ b/sys/kern/kern_kthread.c @@ -37,6 +37,7 @@ #include #include #include +#include #include @@ -144,16 +145,16 @@ kthread_suspend(struct proc *p, int timo) { /* * Make sure this is indeed a system process and we can safely - * use the p_siglist field. + * use the signal queue. */ PROC_LOCK(p); if ((p->p_flag & P_KTHREAD) == 0) { PROC_UNLOCK(p); return (EINVAL); } - SIGADDSET(p->p_siglist, SIGSTOP); + signal_add(p, NULL, SIGSTOP); wakeup(p); - return msleep(&p->p_siglist, &p->p_mtx, PPAUSE | PDROP, "suspkt", timo); + return msleep(&p->p_sigq, &p->p_mtx, PPAUSE | PDROP, "suspkt", timo); } int @@ -168,9 +169,9 @@ kthread_resume(struct proc *p) PROC_UNLOCK(p); return (EINVAL); } - SIGDELSET(p->p_siglist, SIGSTOP); + signal_delete(p, NULL, SIGSTOP); PROC_UNLOCK(p); - wakeup(&p->p_siglist); + wakeup(&p->p_sigq); return (0); } @@ -178,9 +179,9 @@ void kthread_suspend_check(struct proc *p) { PROC_LOCK(p); - while (SIGISMEMBER(p->p_siglist, SIGSTOP)) { - wakeup(&p->p_siglist); - msleep(&p->p_siglist, &p->p_mtx, PPAUSE, "ktsusp", 0); + while (signal_queued(p, SIGSTOP)) { + wakeup(&p->p_sigq); + msleep(&p->p_sigq, &p->p_mtx, PPAUSE, "ktsusp", 0); } PROC_UNLOCK(p); } diff --git a/sys/kern/kern_proc.c b/sys/kern/kern_proc.c index 633c66e5c922..e7fce8a2dfea 100644 --- a/sys/kern/kern_proc.c +++ b/sys/kern/kern_proc.c @@ -58,6 +58,7 @@ #include #include #endif +#include #include #include @@ -408,7 +409,7 @@ kse_create(struct thread *td, struct kse_create_args *uap) RANGEOF(struct kse, ke_startcopy, ke_endcopy)); #endif PROC_LOCK(p); - if (SIGPENDING(p)) + if (signal_pending(p)) newke->ke_flags |= KEF_ASTPENDING; PROC_UNLOCK(p); mtx_lock_spin(&sched_lock); @@ -1014,7 +1015,7 @@ fill_kinfo_proc(p, kp) strncpy(kp->ki_comm, p->p_comm, sizeof(kp->ki_comm) - 1); strncpy(kp->ki_ocomm, p->p_comm, sizeof(kp->ki_ocomm) - 1); } - kp->ki_siglist = p->p_siglist; + ksiginfo_to_sigset_t(p, &kp->ki_siglist); kp->ki_sigmask = p->p_sigmask; kp->ki_xstat = p->p_xstat; kp->ki_acflag = p->p_acflag; diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c index f6fa38b720c7..ada2016af2ae 100644 --- a/sys/kern/kern_sig.c +++ b/sys/kern/kern_sig.c @@ -1,4 +1,6 @@ /* + * Copyright (c) 2002 New Gold Technoloy. All rights reserved. + * Copyright (c) 2002 Juli Mallett. All rights reserved. * Copyright (c) 1982, 1986, 1989, 1991, 1993 * The Regents of the University of California. All rights reserved. * (c) UNIX System Laboratories, Inc. @@ -70,6 +72,7 @@ #include #include #include +#include #include @@ -116,6 +119,9 @@ static int do_coredump = 1; SYSCTL_INT(_kern, OID_AUTO, coredump, CTLFLAG_RW, &do_coredump, 0, "Enable/Disable coredumps"); +static int stopmask = + sigmask(SIGSTOP) | sigmask(SIGTSTP) | sigmask(SIGTTIN) | sigmask(SIGTTOU); + /* * Signal properties and actions. * The array below categorizes the signals and their default actions @@ -178,12 +184,12 @@ cursig(struct thread *td) PROC_LOCK_ASSERT(p, MA_OWNED); mtx_assert(&sched_lock, MA_NOTOWNED); - return (SIGPENDING(p) ? issignal(td) : 0); + return (signal_pending(p) ? issignal(td) : 0); } /* * Arrange for ast() to handle unmasked pending signals on return to user - * mode. This must be called whenever a signal is added to p_siglist or + * mode. This must be called whenever a signal is added to p_sigq or * unmasked in p_sigmask. */ void @@ -194,7 +200,7 @@ signotify(struct proc *p) PROC_LOCK_ASSERT(p, MA_OWNED); mtx_lock_spin(&sched_lock); - if (SIGPENDING(p)) { + if (signal_pending(p)) { p->p_sflag |= PS_NEEDSIGCHK; /* XXXKSE for now punish all KSEs */ FOREACH_KSEGRP_IN_PROC(p, kg) { @@ -341,7 +347,7 @@ kern_sigaction(td, sig, act, oact, old) (sigprop(sig) & SA_IGNORE && ps->ps_sigact[_SIG_IDX(sig)] == SIG_DFL)) { /* never to be seen again */ - SIGDELSET(p->p_siglist, sig); + signal_delete(p, NULL, sig); if (sig != SIGCONT) /* easier in psignal */ SIGADDSET(p->p_sigignore, sig); @@ -494,7 +500,7 @@ execsigs(p) if (sigprop(sig) & SA_IGNORE) { if (sig != SIGCONT) SIGADDSET(p->p_sigignore, sig); - SIGDELSET(p->p_siglist, sig); + signal_delete(p, NULL, sig); } ps->ps_sigact[_SIG_IDX(sig)] = SIG_DFL; } @@ -641,7 +647,7 @@ sigpending(td, uap) mtx_lock(&Giant); PROC_LOCK(p); - siglist = p->p_siglist; + ksiginfo_to_sigset_t(p, &siglist); PROC_UNLOCK(p); mtx_unlock(&Giant); error = copyout(&siglist, uap->set, sizeof(sigset_t)); @@ -664,10 +670,12 @@ osigpending(td, uap) struct osigpending_args *uap; { struct proc *p = td->td_proc; + sigset_t siglist; mtx_lock(&Giant); PROC_LOCK(p); - SIG2OSIG(p->p_siglist, td->td_retval[0]); + ksiginfo_to_sigset_t(p, &siglist); + SIG2OSIG(siglist, td->td_retval[0]); PROC_UNLOCK(p); mtx_unlock(&Giant); return (0); @@ -1308,7 +1316,7 @@ psignal(p, sig) } if (prop & SA_CONT) - SIG_STOPSIGMASK(p->p_siglist); + signal_delete_mask(p, stopmask); if (prop & SA_STOP) { /* @@ -1321,10 +1329,10 @@ psignal(p, sig) (p->p_pgrp->pg_jobc == 0) && (action == SIG_DFL)) return; - SIG_CONTSIGMASK(p->p_siglist); + signal_delete_mask(p, sigmask(SIGCONT)); p->p_flag &= ~P_CONTINUED; } - SIGADDSET(p->p_siglist, sig); + signal_add(p, NULL, sig); signotify(p); /* uses schedlock */ /* @@ -1362,10 +1370,10 @@ psignal(p, sig) if (prop & SA_CONT) { /* * If SIGCONT is default (or ignored), we continue the - * process but don't leave the signal in p_siglist as - * it has no further action. If SIGCONT is held, we + * process but don't leave the signal in p_sigq as it + * has no further action. If SIGCONT is held, we * continue the process and leave the signal in - * p_siglist. If the process catches SIGCONT, let it + * p_sigq. If the process catches SIGCONT, let it * handle the signal itself. If it isn't waiting on * an event, it goes back to run state. * Otherwise, process goes back to sleep state. @@ -1373,7 +1381,7 @@ psignal(p, sig) p->p_flag &= ~P_STOPPED_SIG; p->p_flag |= P_CONTINUED; if (action == SIG_DFL) { - SIGDELSET(p->p_siglist, sig); + signal_delete(p, NULL, sig); } else if (action == SIG_CATCH) { /* * The process wants to catch it so it needs @@ -1403,7 +1411,7 @@ psignal(p, sig) * Just make sure the signal STOP bit set. */ p->p_flag |= P_STOPPED_SIG; - SIGDELSET(p->p_siglist, sig); + signal_delete(p, NULL, sig); goto out; } @@ -1437,7 +1445,7 @@ psignal(p, sig) /* * Already active, don't need to start again. */ - SIGDELSET(p->p_siglist, sig); + signal_delete(p, NULL, sig); goto out; } if ((p->p_flag & P_TRACED) || (action != SIG_DFL) || @@ -1461,7 +1469,7 @@ psignal(p, sig) mtx_unlock_spin(&sched_lock); stop(p); p->p_xstat = sig; - SIGDELSET(p->p_siglist, sig); + signal_delete(p, NULL, sig); PROC_LOCK(p->p_pptr); if ((p->p_pptr->p_procsig->ps_flag & PS_NOCLDSTOP) == 0) { @@ -1478,7 +1486,7 @@ psignal(p, sig) /* NOTREACHED */ } else { /* Not in "NORMAL" state. discard the signal. */ - SIGDELSET(p->p_siglist, sig); + signal_delete(p, NULL, sig); goto out; } @@ -1553,7 +1561,7 @@ tdsignal(struct thread *td, int sig, sig_t action) * be awakened. */ if ((prop & SA_CONT) && action == SIG_DFL) { - SIGDELSET(p->p_siglist, sig); + signal_delete(p, NULL, sig); return; } @@ -1609,13 +1617,13 @@ issignal(td) for (;;) { int traced = (p->p_flag & P_TRACED) || (p->p_stops & S_SIG); - mask = p->p_siglist; + ksiginfo_to_sigset_t(p, &mask); SIGSETNAND(mask, p->p_sigmask); if (p->p_flag & P_PPWAIT) SIG_STOPSIGMASK(mask); if (SIGISEMPTY(mask)) /* no signal to send */ return (0); - sig = sig_ffs(&mask); + sig = signal_queued_mask(p, mask); prop = sigprop(sig); _STOPEVENT(p, S_SIG, sig); @@ -1625,7 +1633,7 @@ issignal(td) * only if P_TRACED was on when they were posted. */ if (SIGISMEMBER(p->p_sigignore, sig) && (traced == 0)) { - SIGDELSET(p->p_siglist, sig); + signal_delete(p, NULL, sig); continue; } if (p->p_flag & P_TRACED && (p->p_flag & P_PPWAIT) == 0) { @@ -1660,16 +1668,16 @@ issignal(td) * then it will leave it in p->p_xstat; * otherwise we just look for signals again. */ - SIGDELSET(p->p_siglist, sig); /* clear old signal */ + signal_delete(p, NULL, sig); /* clear old signal */ sig = p->p_xstat; if (sig == 0) continue; /* - * Put the new signal into p_siglist. If the - * signal is being masked, look for other signals. + * Put the new signal into p_sigq. If the signal + * is being masked, look for other signals. */ - SIGADDSET(p->p_siglist, sig); + psignal(p, sig); if (SIGISMEMBER(p->p_sigmask, sig)) continue; signotify(p); @@ -1759,7 +1767,7 @@ issignal(td) */ return (sig); } - SIGDELSET(p->p_siglist, sig); /* take the signal! */ + signal_delete(p, NULL, sig); /* take the signal! */ } /* NOTREACHED */ } @@ -1800,7 +1808,7 @@ postsig(sig) PROC_LOCK_ASSERT(p, MA_OWNED); ps = p->p_sigacts; - SIGDELSET(p->p_siglist, sig); + signal_delete(p, NULL, sig); action = ps->ps_sigact[_SIG_IDX(sig)]; #ifdef KTRACE if (KTRPOINT(td, KTR_PSIG)) diff --git a/sys/kern/subr_sigq.c b/sys/kern/subr_sigq.c new file mode 100644 index 000000000000..fa44fabd2e28 --- /dev/null +++ b/sys/kern/subr_sigq.c @@ -0,0 +1,301 @@ +/*- + * Copyright (c) 2002 New Gold Technology. All rights reserved. + * Copyright (c) 2002 Juli Mallett. All rights reserved. + * + * This software was written by Juli Mallett for the + * FreeBSD project. Redistribution and use in source and binary forms, with + * or without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +MALLOC_DEFINE(M_KSIGINFO, "ksiginfos", "Kernel signal info structures"); + +int +ksiginfo_alloc(struct ksiginfo **ksip, int signo) +{ + int error; + struct ksiginfo *ksi; + + error = 0; + + ksi = malloc(sizeof *ksi, M_KSIGINFO, M_ZERO | M_WAITOK); + KASSERT(ksi != NULL, ("ksiginfo_alloc(%d): allocation failed.", signo)); + if (ksi == NULL) { + error = ENOMEM; + goto out; + } + ksi->ksi_signo = signo; + if (curproc != NULL) { + ksi->ksi_pid = curproc->p_pid; + ksi->ksi_ruid = curproc->p_ucred->cr_uid; + } +out: + *ksip = ksi; + return (error); +} + +int +ksiginfo_dequeue(struct ksiginfo **ksip, struct proc *p, int signo) +{ + int error; + struct ksiginfo *ksi; + + error = 0; + ksi = NULL; + + PROC_LOCK_ASSERT(p, MA_OWNED); + if (TAILQ_EMPTY(&p->p_sigq)) { + error = EDOOFUS; + goto out; + } + if (!signo) { + ksi = TAILQ_FIRST(&p->p_sigq); + goto out; + } + TAILQ_FOREACH(ksi, &p->p_sigq, ksi_queue) { + if (ksi->ksi_signo == signo) + goto out; + } + error = ESRCH; + ksi = NULL; +out: + if (ksi != NULL) + TAILQ_REMOVE(&p->p_sigq, ksi, ksi_queue); + *ksip = ksi; + return (error); +} + +int +ksiginfo_destroy(struct ksiginfo **ksip) +{ + int error; + struct ksiginfo *ksi; + + error = 0; + + ksi = *ksip; + if (ksi == NULL) { + error = EDOOFUS; + goto out; + } + free(ksi, M_KSIGINFO); + ksi = NULL; +out: + *ksip = ksi; + return (error); +} + +int +ksiginfo_to_sigset_t(struct proc *p, sigset_t *setp) +{ + int error; + sigset_t set; + struct ksiginfo *ksi; + + error = 0; + SIGEMPTYSET(set); + + PROC_LOCK_ASSERT(p, MA_OWNED); + /* + * We could set EDOOFUS here, however if there are no queued + * signals, then an empty signal set _is_ valid. + */ + if (TAILQ_EMPTY(&p->p_sigq)) + goto out; + TAILQ_FOREACH(ksi, &p->p_sigq, ksi_queue) + SIGADDSET(set, ksi->ksi_signo); +out: + *setp = set; + return (error); +} + +int +signal_add(struct proc *p, struct ksiginfo *ksi, int signo) +{ + int error; + + error = 0; + + PROC_LOCK_ASSERT(p, MA_OWNED); + if (ksi == NULL) { + PROC_UNLOCK(p); + error = ksiginfo_alloc(&ksi, signo); + PROC_LOCK(p); + if (error) + goto out; + } + TAILQ_INSERT_HEAD(&p->p_sigq, ksi, ksi_queue); +out: + return (error); +} + +int +signal_delete(struct proc *p, struct ksiginfo *ksi, int signo) +{ + int error; + + error = 0; + + PROC_LOCK_ASSERT(p, MA_OWNED); + if (ksi == NULL) { + while (signal_queued(p, signo)) { + error = ksiginfo_dequeue(&ksi, p, signo); + if (error) + goto out; + error = ksiginfo_destroy(&ksi); + if (error) + goto out; + } + } +out: + if (ksi != NULL) { + TAILQ_REMOVE(&p->p_sigq, ksi, ksi_queue); + ksiginfo_destroy(&ksi); + } + return (error); +} + +int +signal_delete_mask(struct proc *p, int mask) +{ + int error; + struct ksiginfo *ksi, *prev; + + error = 0; + ksi = prev = NULL; + + PROC_LOCK_ASSERT(p, MA_OWNED); + if (TAILQ_EMPTY(&p->p_sigq)) + goto out; + TAILQ_FOREACH(ksi, &p->p_sigq, ksi_queue) { + if (prev != NULL) { + TAILQ_REMOVE(&p->p_sigq, prev, ksi_queue); + error = ksiginfo_destroy(&prev); + if (error) + goto out; + } + if (sigmask(ksi->ksi_signo) & mask) + prev = ksi; + } + if (prev != NULL) { + TAILQ_REMOVE(&p->p_sigq, prev, ksi_queue); + error = ksiginfo_destroy(&prev); + /* + * XXX - Could just fall off the bottom... + */ + if (error) + goto out; + } +out: + return (error); +} + +int +signal_pending(struct proc *p) +{ + int error, pending; + sigset_t set; + + error = 0; + pending = 0; + + PROC_LOCK_ASSERT(p, MA_OWNED); + if (TAILQ_EMPTY(&p->p_sigq)) + goto out; + if (p->p_flag & P_TRACED) { + pending = 1; + goto out; + } + error = ksiginfo_to_sigset_t(p, &set); + if (error) + goto out; + pending = !sigsetmasked(&set, &p->p_sigmask); + if (pending) + goto out; +out: + return (pending); +} + +int +signal_queued(struct proc *p, int signo) +{ + int error, pending; + struct ksiginfo *ksi; + + error = 0; + pending = 0; + ksi = NULL; + + PROC_LOCK_ASSERT(p, MA_OWNED); + if (TAILQ_EMPTY(&p->p_sigq)) + goto out; + /* + * Since we know the queue is not empty, we can just do + * pending = TAILQ_FIRST(&p->p_sigq)->ksi_signo, if the + * signo is 0, however since we have to use at least one + * more TailQ manipulation macro either way, might as well + * just do it like this, as I think it optimises better, + * even if the failure case is more expensive. + */ + TAILQ_FOREACH(ksi, &p->p_sigq, ksi_queue) { + pending = !signo || ksi->ksi_signo == signo; + if (pending) + goto out; + } +out: + return (pending); +} + +int +signal_queued_mask(struct proc *p, sigset_t mask) +{ + int pending; + struct ksiginfo *ksi; + + pending = 0; + ksi = NULL; + + PROC_LOCK_ASSERT(p, MA_OWNED); + if (TAILQ_EMPTY(&p->p_sigq)) + goto out; + TAILQ_FOREACH(ksi, &p->p_sigq, ksi_queue) { + if (SIGISMEMBER(mask, ksi->ksi_signo)) { + pending = ksi->ksi_signo; + goto out; + } + } +out: + return (pending); +} diff --git a/sys/kern/subr_trap.c b/sys/kern/subr_trap.c index f12014163b53..0a165e9ee1bb 100644 --- a/sys/kern/subr_trap.c +++ b/sys/kern/subr_trap.c @@ -54,6 +54,8 @@ #include #include #include +#include +#include #include #include @@ -80,7 +82,7 @@ userret(td, frame, oticks) mtx_lock(&Giant); PROC_LOCK(p); mtx_lock_spin(&sched_lock); - if (SIGPENDING(p) && ((p->p_sflag & PS_NEEDSIGCHK) == 0 || + if (signal_pending(p) && ((p->p_sflag & PS_NEEDSIGCHK) == 0 || (td->td_kse->ke_flags & KEF_ASTPENDING) == 0)) printf("failed to set signal flags properly for ast()\n"); mtx_unlock_spin(&sched_lock); diff --git a/sys/kern/tty.c b/sys/kern/tty.c index c075a4738ff5..590e8de26402 100644 --- a/sys/kern/tty.c +++ b/sys/kern/tty.c @@ -102,6 +102,7 @@ #include #include #include +#include #include #include @@ -1841,21 +1842,24 @@ int ttycheckoutq(struct tty *tp, int wait) { int hiwat, s; - sigset_t oldmask; + sigset_t oldmask, newmask; hiwat = tp->t_ohiwat; SIGEMPTYSET(oldmask); s = spltty(); if (wait) - oldmask = curproc->p_siglist; + ksiginfo_to_sigset_t(curproc, &oldmask); if (tp->t_outq.c_cc > hiwat + OBUFSIZ + 100) while (tp->t_outq.c_cc > hiwat) { ttstart(tp); if (tp->t_outq.c_cc <= hiwat) break; - if (!(wait && SIGSETEQ(curproc->p_siglist, oldmask))) { - splx(s); - return (0); + if (!wait) { + ksiginfo_to_sigset_t(curproc, &newmask); + if (SIGSETEQ(newmask, oldmask)) { + splx(s); + return (0); + } } SET(tp->t_state, TS_SO_OLOWAT); tsleep(TSA_OLOWAT(tp), PZERO - 1, "ttoutq", hz); diff --git a/sys/sys/ksiginfo.h b/sys/sys/ksiginfo.h new file mode 100644 index 000000000000..26b88d574414 --- /dev/null +++ b/sys/sys/ksiginfo.h @@ -0,0 +1,78 @@ +/*- + * Copyright (c) 2002 New Gold Technology. All rights reserved. + * Copyright (c) 2002 Juli Mallett. All rights reserved. + * + * This software was written by Juli Mallett for the + * FreeBSD project. Redistribution and use in source and binary forms, with + * or without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _SYS_KSIGINFO_H_ +#define _SYS_KSIGINFO_H_ + +#ifndef _KERNEL +#error "no user-serviceable parts inside" +#endif + +#include + +/* + * Structures and prototypes for working with the in-kernel representation + * of pending signals, and all the information we have about them. + */ + +MALLOC_DECLARE(M_KSIGINFO); + +/* + * This is pushed to userland in the form of a siginfo_t, which is POSIX + * defined. This is for in-kernel representations only, and has no ABI + * consumers. + */ +struct ksiginfo { + TAILQ_ENTRY(ksiginfo) ksi_queue; /* Entry in the signal queue. */ + void *ksi_addr; /* [Fault] address. */ + int ksi_code; /* [Trap] code. */ + int ksi_errno; /* Error number. */ + int ksi_signo; /* Signal number. */ + int ksi_status; /* Exit status (SIGCHLD). */ + uid_t ksi_ruid; /* Real UID of sender. */ + pid_t ksi_pid; /* PID of sender. */ +}; + +struct proc; + +__BEGIN_DECLS; +int ksiginfo_alloc(struct ksiginfo **, int); +int ksiginfo_dequeue(struct ksiginfo **, struct proc *, int); +int ksiginfo_destroy(struct ksiginfo **); +int ksiginfo_to_sigset_t(struct proc *, sigset_t *); +int signal_add(struct proc *, struct ksiginfo *, int); +int signal_delete(struct proc *, struct ksiginfo *, int); +int signal_delete_mask(struct proc *, int); +int signal_pending(struct proc *); +int signal_queued(struct proc *, int); +int signal_queued_mask(struct proc *, sigset_t); +__END_DECLS; + +#endif /* !_SYS_KSIGINFO_H_ */ diff --git a/sys/sys/proc.h b/sys/sys/proc.h index fe6a0684d28c..12ae34e05ac4 100644 --- a/sys/sys/proc.h +++ b/sys/sys/proc.h @@ -497,6 +497,7 @@ struct proc { TAILQ_HEAD(, ksegrp) p_ksegrps; /* (kg_ksegrp) All KSEGs. */ TAILQ_HEAD(, thread) p_threads; /* (td_plist) Threads. (shortcut) */ TAILQ_HEAD(, thread) p_suspended; /* (td_runq) suspended threads */ + TAILQ_HEAD(, ksiginfo) p_sigq; /* (c) Queued signals. */ struct ucred *p_ucred; /* (c) Process owner's identity. */ struct filedesc *p_fd; /* (b) Ptr to open files structure. */ /* Accumulated stats for all KSEs? */ @@ -537,7 +538,6 @@ struct proc { struct bintime p_runtime; /* (j) Real time. */ int p_traceflag; /* (o) Kernel trace points. */ struct vnode *p_tracep; /* (c + o) Trace to vnode. */ - sigset_t p_siglist; /* (c) Sigs arrived, not delivered. */ struct vnode *p_textvp; /* (b) Vnode of executable. */ char p_lock; /* (c) Proclock (prevent swap) count. */ struct klist p_klist; /* (c) Knotes attached to this proc. */