diff options
author | davidxu <davidxu@FreeBSD.org> | 2005-10-14 12:43:47 +0000 |
---|---|---|
committer | davidxu <davidxu@FreeBSD.org> | 2005-10-14 12:43:47 +0000 |
commit | 3fbdb3c21524d9d95278ada1d61b4d1e6bee654b (patch) | |
tree | 95d82b1a11b0c187223f8ac12f020b19901fa750 /sys/amd64/ia32 | |
parent | 6b2407fb7677ef2b8cef5c0925b3fe88a6ec7ca4 (diff) | |
download | FreeBSD-src-3fbdb3c21524d9d95278ada1d61b4d1e6bee654b.zip FreeBSD-src-3fbdb3c21524d9d95278ada1d61b4d1e6bee654b.tar.gz |
1. Change prototype of trapsignal and sendsig to use ksiginfo_t *, most
changes in MD code are trivial, before this change, trapsignal and
sendsig use discrete parameters, now they uses member fields of
ksiginfo_t structure. For sendsig, this change allows us to pass
POSIX realtime signal value to user code.
2. Remove cpu_thread_siginfo, it is no longer needed because we now always
generate ksiginfo_t data and feed it to libpthread.
3. Add p_sigqueue to proc structure to hold shared signals which were
blocked by all threads in the proc.
4. Add td_sigqueue to thread structure to hold all signals delivered to
thread.
5. i386 and amd64 now return POSIX standard si_code, other arches will
be fixed.
6. In this sigqueue implementation, pending signal set is kept as before,
an extra siginfo list holds additional siginfo_t data for signals.
kernel code uses psignal() still behavior as before, it won't be failed
even under memory pressure, only exception is when deleting a signal,
we should call sigqueue_delete to remove signal from sigqueue but
not SIGDELSET. Current there is no kernel code will deliver a signal
with additional data, so kernel should be as stable as before,
a ksiginfo can carry more information, for example, allow signal to
be delivered but throw away siginfo data if memory is not enough.
SIGKILL and SIGSTOP have fast path in sigqueue_add, because they can
not be caught or masked.
The sigqueue() syscall allows user code to queue a signal to target
process, if resource is unavailable, EAGAIN will be returned as
specification said.
Just before thread exits, signal queue memory will be freed by
sigqueue_flush.
Current, all signals are allowed to be queued, not only realtime signals.
Earlier patch reviewed by: jhb, deischen
Tested on: i386, amd64
Diffstat (limited to 'sys/amd64/ia32')
-rw-r--r-- | sys/amd64/ia32/ia32_signal.c | 62 | ||||
-rw-r--r-- | sys/amd64/ia32/ia32_syscall.c | 7 |
2 files changed, 54 insertions, 15 deletions
diff --git a/sys/amd64/ia32/ia32_signal.c b/sys/amd64/ia32/ia32_signal.c index b5533b5..116361a 100644 --- a/sys/amd64/ia32/ia32_signal.c +++ b/sys/amd64/ia32/ia32_signal.c @@ -79,7 +79,7 @@ __FBSDID("$FreeBSD$"); #include <machine/cpufunc.h> #ifdef COMPAT_FREEBSD4 -static void freebsd4_ia32_sendsig(sig_t, int, sigset_t *, u_long); +static void freebsd4_ia32_sendsig(sig_t, ksiginfo_t *, sigset_t *); #endif static void ia32_get_fpcontext(struct thread *td, struct ia32_mcontext *mcp); static int ia32_set_fpcontext(struct thread *td, const struct ia32_mcontext *mcp); @@ -295,18 +295,23 @@ freebsd32_swapcontext(struct thread *td, struct freebsd32_swapcontext_args *uap) */ #ifdef COMPAT_FREEBSD4 static void -freebsd4_ia32_sendsig(sig_t catcher, int sig, sigset_t *mask, u_long code) +freebsd4_ia32_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask) { struct ia32_sigframe4 sf, *sfp; + struct ia32_siginfo siginfo; struct proc *p; struct thread *td; struct sigacts *psp; struct trapframe *regs; int oonstack; + int sig; td = curthread; p = td->td_proc; + siginfo_to_ia32siginfo(&ksi->ksi_info, &siginfo); + PROC_LOCK_ASSERT(p, MA_OWNED); + sig = siginfo.si_signo; psp = p->p_sigacts; mtx_assert(&psp->ps_mtx, MA_OWNED); regs = td->td_frame; @@ -362,13 +367,12 @@ freebsd4_ia32_sendsig(sig_t catcher, int sig, sigset_t *mask, u_long code) sf.sf_ah = (u_int32_t)(uintptr_t)catcher; /* Fill in POSIX parts */ + sf.sf_si = siginfo; sf.sf_si.si_signo = sig; - sf.sf_si.si_code = code; - sf.sf_si.si_addr = regs->tf_addr; } else { /* Old FreeBSD-style arguments. */ - sf.sf_siginfo = code; - sf.sf_addr = regs->tf_addr; + sf.sf_siginfo = siginfo.si_code; + sf.sf_addr = (u_int32_t)siginfo.si_addr; sf.sf_ah = (u_int32_t)(uintptr_t)catcher; } mtx_unlock(&psp->ps_mtx); @@ -400,23 +404,27 @@ freebsd4_ia32_sendsig(sig_t catcher, int sig, sigset_t *mask, u_long code) #endif /* COMPAT_FREEBSD4 */ void -ia32_sendsig(sig_t catcher, int sig, sigset_t *mask, u_long code) +ia32_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask) { struct ia32_sigframe sf, *sfp; + struct ia32_siginfo siginfo; struct proc *p; struct thread *td; struct sigacts *psp; char *sp; struct trapframe *regs; int oonstack; + int sig; + siginfo_to_ia32siginfo(&ksi->ksi_info, &siginfo); td = curthread; p = td->td_proc; PROC_LOCK_ASSERT(p, MA_OWNED); + sig = siginfo.si_signo; psp = p->p_sigacts; #ifdef COMPAT_FREEBSD4 if (SIGISMEMBER(psp->ps_freebsd4, sig)) { - freebsd4_ia32_sendsig(catcher, sig, mask, code); + freebsd4_ia32_sendsig(catcher, ksi, mask); return; } #endif @@ -479,13 +487,12 @@ ia32_sendsig(sig_t catcher, int sig, sigset_t *mask, u_long code) sf.sf_ah = (u_int32_t)(uintptr_t)catcher; /* Fill in POSIX parts */ + sf.sf_si = siginfo; sf.sf_si.si_signo = sig; - sf.sf_si.si_code = code; - sf.sf_si.si_addr = regs->tf_addr; } else { /* Old FreeBSD-style arguments. */ - sf.sf_siginfo = code; - sf.sf_addr = regs->tf_addr; + sf.sf_siginfo = siginfo.si_code; + sf.sf_addr = (u_int32_t)siginfo.si_addr; sf.sf_ah = (u_int32_t)(uintptr_t)catcher; } mtx_unlock(&psp->ps_mtx); @@ -540,6 +547,7 @@ freebsd4_freebsd32_sigreturn(td, uap) struct trapframe *regs; const struct ia32_ucontext4 *ucp; int cs, eflags, error; + ksiginfo_t ksi; error = copyin(uap->sigcntxp, &uc, sizeof(uc)); if (error != 0) @@ -573,7 +581,12 @@ freebsd4_freebsd32_sigreturn(td, uap) cs = ucp->uc_mcontext.mc_cs; if (!CS_SECURE(cs)) { printf("freebsd4_sigreturn: cs = 0x%x\n", cs); - trapsignal(td, SIGBUS, T_PROTFLT); + ksiginfo_init_trap(&ksi); + ksi.ksi_signo = SIGBUS; + ksi.ksi_code = BUS_OBJERR; + ksi.ksi_trapno = T_PROTFLT; + ksi.ksi_addr = (void *)regs->tf_rip; + trapsignal(td, &ksi); return (EINVAL); } @@ -617,6 +630,7 @@ freebsd32_sigreturn(td, uap) struct trapframe *regs; const struct ia32_ucontext *ucp; int cs, eflags, error, ret; + ksiginfo_t ksi; error = copyin(uap->sigcntxp, &uc, sizeof(uc)); if (error != 0) @@ -650,7 +664,12 @@ freebsd32_sigreturn(td, uap) cs = ucp->uc_mcontext.mc_cs; if (!CS_SECURE(cs)) { printf("sigreturn: cs = 0x%x\n", cs); - trapsignal(td, SIGBUS, T_PROTFLT); + ksiginfo_init_trap(&ksi); + ksi.ksi_signo = SIGBUS; + ksi.ksi_code = BUS_OBJERR; + ksi.ksi_trapno = T_PROTFLT; + ksi.ksi_addr = (void *)regs->tf_rip; + trapsignal(td, &ksi); return (EINVAL); } @@ -722,3 +741,18 @@ ia32_setregs(td, entry, stack, ps_strings) pcb->pcb_flags |= PCB_FULLCTX; td->td_retval[1] = 0; } + +void +siginfo_to_ia32siginfo(siginfo_t *src, struct ia32_siginfo *dst) +{ + dst->si_signo = src->si_signo; + dst->si_errno = src->si_errno; + dst->si_code = src->si_code; + dst->si_pid = src->si_pid; + dst->si_uid = src->si_uid; + dst->si_status = src->si_status; + dst->si_addr = dst->si_addr; + dst->si_value.sigval_int = src->si_value.sigval_int; + dst->si_band = src->si_band; + dst->__spare__[0] = src->si_trapno; +} diff --git a/sys/amd64/ia32/ia32_syscall.c b/sys/amd64/ia32/ia32_syscall.c index f159cfb..93d4e16 100644 --- a/sys/amd64/ia32/ia32_syscall.c +++ b/sys/amd64/ia32/ia32_syscall.c @@ -101,6 +101,7 @@ ia32_syscall(struct trapframe frame) u_int32_t args[8]; u_int64_t args64[8]; u_int code; + ksiginfo_t ksi; /* * note: PCPU_LAZY_INC() can only be used if we can afford @@ -227,7 +228,11 @@ ia32_syscall(struct trapframe frame) */ if (orig_tf_rflags & PSL_T) { frame.tf_rflags &= ~PSL_T; - trapsignal(td, SIGTRAP, 0); + ksiginfo_init_trap(&ksi); + ksi.ksi_signo = SIGTRAP; + ksi.ksi_code = TRAP_TRACE; + ksi.ksi_addr = (void *)frame.tf_rip; + trapsignal(td, &ksi); } /* |