summaryrefslogtreecommitdiffstats
path: root/sys/amd64/ia32/ia32_signal.c
diff options
context:
space:
mode:
authordavidxu <davidxu@FreeBSD.org>2005-10-14 12:43:47 +0000
committerdavidxu <davidxu@FreeBSD.org>2005-10-14 12:43:47 +0000
commit3fbdb3c21524d9d95278ada1d61b4d1e6bee654b (patch)
tree95d82b1a11b0c187223f8ac12f020b19901fa750 /sys/amd64/ia32/ia32_signal.c
parent6b2407fb7677ef2b8cef5c0925b3fe88a6ec7ca4 (diff)
downloadFreeBSD-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/ia32_signal.c')
-rw-r--r--sys/amd64/ia32/ia32_signal.c62
1 files changed, 48 insertions, 14 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;
+}
OpenPOWER on IntegriCloud