diff options
author | jmallett <jmallett@FreeBSD.org> | 2002-09-30 20:20:22 +0000 |
---|---|---|
committer | jmallett <jmallett@FreeBSD.org> | 2002-09-30 20:20:22 +0000 |
commit | 0341f71df178fd346332ced28efb677a6ef39414 (patch) | |
tree | 44cc85d6d7a465b4410e0fa06f9f5a1b21bc40b6 | |
parent | e70c6b99c8b8b510eaef402242dd8cb86e300c6f (diff) | |
download | FreeBSD-src-0341f71df178fd346332ced28efb677a6ef39414.zip FreeBSD-src-0341f71df178fd346332ced28efb677a6ef39414.tar.gz |
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]
-rw-r--r-- | sys/alpha/osf1/osf1_signal.c | 3 | ||||
-rw-r--r-- | sys/compat/linprocfs/linprocfs.c | 2 | ||||
-rw-r--r-- | sys/compat/linux/linux_misc.c | 3 | ||||
-rw-r--r-- | sys/compat/linux/linux_signal.c | 3 | ||||
-rw-r--r-- | sys/compat/svr4/svr4_filio.c | 3 | ||||
-rw-r--r-- | sys/compat/svr4/svr4_signal.c | 2 | ||||
-rw-r--r-- | sys/conf/files | 1 | ||||
-rw-r--r-- | sys/fs/procfs/procfs_ctl.c | 3 | ||||
-rw-r--r-- | sys/kern/init_main.c | 2 | ||||
-rw-r--r-- | sys/kern/kern_exit.c | 9 | ||||
-rw-r--r-- | sys/kern/kern_fork.c | 1 | ||||
-rw-r--r-- | sys/kern/kern_kthread.c | 17 | ||||
-rw-r--r-- | sys/kern/kern_proc.c | 5 | ||||
-rw-r--r-- | sys/kern/kern_sig.c | 64 | ||||
-rw-r--r-- | sys/kern/subr_sigq.c | 301 | ||||
-rw-r--r-- | sys/kern/subr_trap.c | 4 | ||||
-rw-r--r-- | sys/kern/tty.c | 14 | ||||
-rw-r--r-- | sys/sys/ksiginfo.h | 78 | ||||
-rw-r--r-- | sys/sys/proc.h | 2 |
19 files changed, 465 insertions, 52 deletions
diff --git a/sys/alpha/osf1/osf1_signal.c b/sys/alpha/osf1/osf1_signal.c index 7ea80fd..4e42796 100644 --- a/sys/alpha/osf1/osf1_signal.c +++ b/sys/alpha/osf1/osf1_signal.c @@ -46,6 +46,7 @@ #include <sys/buf.h> #include <sys/bus.h> #include <sys/mbuf.h> +#include <sys/ksiginfo.h> #include <sys/vmmeter.h> #include <sys/msgbuf.h> #include <sys/exec.h> @@ -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 d0db293..af542b4 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 16c8677..d344548 100644 --- a/sys/compat/linux/linux_misc.c +++ b/sys/compat/linux/linux_misc.c @@ -36,6 +36,7 @@ #include <sys/imgact_aout.h> #include <sys/jail.h> #include <sys/kernel.h> +#include <sys/ksiginfo.h> #include <sys/lock.h> #include <sys/mac.h> #include <sys/malloc.h> @@ -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 532fb81..d264db5 100644 --- a/sys/compat/linux/linux_signal.c +++ b/sys/compat/linux/linux_signal.c @@ -34,6 +34,7 @@ #include <sys/mutex.h> #include <sys/proc.h> #include <sys/signalvar.h> +#include <sys/ksiginfo.h> #include <sys/syscallsubr.h> #include <sys/sysproto.h> @@ -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 c2bad1d..8dc1b4d 100644 --- a/sys/compat/svr4/svr4_filio.c +++ b/sys/compat/svr4/svr4_filio.c @@ -39,6 +39,7 @@ #include <sys/poll.h> #include <sys/malloc.h> #include <sys/mutex.h> +#include <sys/ksiginfo.h> #include <sys/sysproto.h> @@ -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 fea5317..1c78b53 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 73e62c0..eccc374 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 c9572b6..89f8de1 100644 --- a/sys/fs/procfs/procfs_ctl.c +++ b/sys/fs/procfs/procfs_ctl.c @@ -51,6 +51,7 @@ #include <sys/signalvar.h> #include <sys/sx.h> #include <sys/uio.h> +#include <sys/ksiginfo.h> #include <fs/pseudofs/pseudofs.h> #include <fs/procfs/procfs.h> @@ -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 49bb739..d58e7df 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 1725d54..572aab3 100644 --- a/sys/kern/kern_exit.c +++ b/sys/kern/kern_exit.c @@ -67,6 +67,7 @@ #ifdef KTRACE #include <sys/ktrace.h> #endif +#include <sys/ksiginfo.h> #include <vm/vm.h> #include <vm/vm_extern.h> @@ -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 da7ca7d..c8182f9 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 08ef71f..95e9a68 100644 --- a/sys/kern/kern_kthread.c +++ b/sys/kern/kern_kthread.c @@ -37,6 +37,7 @@ #include <sys/sx.h> #include <sys/unistd.h> #include <sys/wait.h> +#include <sys/ksiginfo.h> #include <machine/stdarg.h> @@ -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 633c66e..e7fce8a 100644 --- a/sys/kern/kern_proc.c +++ b/sys/kern/kern_proc.c @@ -58,6 +58,7 @@ #include <sys/uio.h> #include <sys/ktrace.h> #endif +#include <sys/ksiginfo.h> #include <vm/vm.h> #include <vm/vm_extern.h> @@ -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 f6fa38b..ada2016 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 <sys/sysctl.h> #include <sys/malloc.h> #include <sys/unistd.h> +#include <sys/ksiginfo.h> #include <machine/cpu.h> @@ -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 0000000..fa44fab --- /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 <jmallett@FreeBSD.org> 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 <sys/param.h> +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/signalvar.h> +#include <sys/proc.h> +#include <sys/errno.h> +#include <sys/lock.h> +#include <sys/malloc.h> +#include <sys/mutex.h> +#include <sys/signal.h> +#include <sys/ksiginfo.h> + +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 f120141..0a165e9 100644 --- a/sys/kern/subr_trap.c +++ b/sys/kern/subr_trap.c @@ -54,6 +54,8 @@ #include <sys/signalvar.h> #include <sys/systm.h> #include <sys/vmmeter.h> +#include <sys/malloc.h> +#include <sys/ksiginfo.h> #include <machine/cpu.h> #include <machine/pcb.h> @@ -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 c075a47..590e8de 100644 --- a/sys/kern/tty.c +++ b/sys/kern/tty.c @@ -102,6 +102,7 @@ #include <sys/malloc.h> #include <sys/filedesc.h> #include <sys/sysctl.h> +#include <sys/ksiginfo.h> #include <vm/vm.h> #include <vm/pmap.h> @@ -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 0000000..26b88d5 --- /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 <jmallett@FreeBSD.org> 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 <sys/malloc.h> + +/* + * 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 fe6a068..12ae34e 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. */ |