Sat Jan 21 22:09:57 2012 UTC ()
Complete rewrite of the signal and spl framework for NetBSD/usermode

Signals are now moved from the sigaltstack ASAP and stacked on a replacement
stack for each processes.

Preemption now works though could be enhanced a bit more


(reinoud)
diff -r1.25 -r1.26 src/sys/arch/usermode/dev/clock.c
diff -r1.68 -r1.69 src/sys/arch/usermode/dev/cpu.c
diff -r1.4 -r1.5 src/sys/arch/usermode/dev/if_veth.c
diff -r1.29 -r1.30 src/sys/arch/usermode/dev/ld_thunkbus.c
diff -r1.17 -r1.18 src/sys/arch/usermode/dev/ttycons.c
diff -r1.6 -r1.7 src/sys/arch/usermode/include/intr.h
diff -r1.14 -r1.15 src/sys/arch/usermode/usermode/intr.c
diff -r1.60 -r1.61 src/sys/arch/usermode/usermode/trap.c

cvs diff -r1.25 -r1.26 src/sys/arch/usermode/dev/clock.c (expand / switch to context diff)
--- src/sys/arch/usermode/dev/clock.c 2012/01/14 21:42:51 1.25
+++ src/sys/arch/usermode/dev/clock.c 2012/01/21 22:09:56 1.26
@@ -1,4 +1,4 @@
-/* $NetBSD: clock.c,v 1.25 2012/01/14 21:42:51 reinoud Exp $ */
+/* $NetBSD: clock.c,v 1.26 2012/01/21 22:09:56 reinoud Exp $ */
 
 /*-
  * Copyright (c) 2007 Jared D. McNeill <jmcneill@invisible.ca>
@@ -29,7 +29,7 @@
 #include "opt_hz.h"
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: clock.c,v 1.25 2012/01/14 21:42:51 reinoud Exp $");
+__KERNEL_RCSID(0, "$NetBSD: clock.c,v 1.26 2012/01/21 22:09:56 reinoud Exp $");
 
 #include <sys/param.h>
 #include <sys/proc.h>
@@ -50,11 +50,14 @@
 static int	clock_match(device_t, cfdata_t, void *);
 static void	clock_attach(device_t, device_t, void *);
 
-static void	clock_signal(int sig, siginfo_t *info, void *ctx);
 static unsigned int clock_getcounter(struct timecounter *);
 
 static int	clock_todr_gettime(struct todr_chip_handle *, struct timeval *);
 
+extern void setup_clock_intr(void);
+void clock_intr(void *priv);
+
+
 struct clock_softc {
 	device_t		sc_dev;
 	struct todr_chip_handle	sc_todr;
@@ -72,6 +75,7 @@
 };
 
 timer_t clock_timerid;
+int clock_running = 0;
 
 CFATTACH_DECL_NEW(clock, sizeof(struct clock_softc),
     clock_match, clock_attach, NULL, NULL);
@@ -90,7 +94,6 @@
 static void
 clock_attach(device_t parent, device_t self, void *opaque)
 {
-	static struct sigaction sa;
 	struct clock_softc *sc = device_private(self);
 
 	aprint_naive("\n");
@@ -101,21 +104,15 @@
 	sc->sc_todr.todr_gettime = clock_todr_gettime;
 	todr_attach(&sc->sc_todr);
 
-	memset(&sa, 0, sizeof(sa));
-	thunk_sigemptyset(&sa.sa_mask);
-	sa.sa_sigaction = clock_signal;
-	sa.sa_flags = SA_RESTART | SA_ONSTACK;
-	if (thunk_sigaction(SIGALRM, &sa, NULL) == -1)
-		panic("couldn't register SIGALRM handler : %d",
-		    thunk_geterrno());
-
 	clock_timerid = thunk_timer_attach();
-
 	clock_timecounter.tc_quality = 1000;
 	tc_init(&clock_timecounter);
+
+	setup_clock_intr();
+	clock_running = 1;
 }
 
-static void
+void
 clock_intr(void *priv)
 {
 	struct clockframe cf;
@@ -126,13 +123,6 @@
 	}
 }
 
-static void
-clock_signal(int sig, siginfo_t *info, void *ctx)
-{
-	curcpu()->ci_idepth++;
-	spl_intr(IPL_SOFTCLOCK, clock_intr, NULL);
-	curcpu()->ci_idepth--;
-}
 
 static unsigned int
 clock_getcounter(struct timecounter *tc)

cvs diff -r1.68 -r1.69 src/sys/arch/usermode/dev/cpu.c (expand / switch to context diff)
--- src/sys/arch/usermode/dev/cpu.c 2012/01/18 19:17:02 1.68
+++ src/sys/arch/usermode/dev/cpu.c 2012/01/21 22:09:56 1.69
@@ -1,4 +1,4 @@
-/* $NetBSD: cpu.c,v 1.68 2012/01/18 19:17:02 reinoud Exp $ */
+/* $NetBSD: cpu.c,v 1.69 2012/01/21 22:09:56 reinoud Exp $ */
 
 /*-
  * Copyright (c) 2007 Jared D. McNeill <jmcneill@invisible.ca>
@@ -30,7 +30,7 @@
 #include "opt_hz.h"
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: cpu.c,v 1.68 2012/01/18 19:17:02 reinoud Exp $");
+__KERNEL_RCSID(0, "$NetBSD: cpu.c,v 1.69 2012/01/21 22:09:56 reinoud Exp $");
 
 #include <sys/param.h>
 #include <sys/conf.h>
@@ -244,12 +244,13 @@
 	thunk_makecontext(&sc->sc_ucp, (void (*)(void)) cpu_switchto_atomic,
 			2, oldlwp, newlwp, NULL);
 
-	if (!oldpcb) {
-		thunk_setcontext(&sc->sc_ucp);
-		/* never returns */
-	} else {
+	KASSERT(sc);
+	if (oldpcb) {
 		thunk_swapcontext(&oldpcb->pcb_ucp, &sc->sc_ucp);
 		/* returns here */
+	} else {
+		thunk_setcontext(&sc->sc_ucp);
+		/* never returns */
 	}
 
 #ifdef CPU_DEBUG
@@ -374,8 +375,10 @@
 	/* get l2 its own stack */
 	pcb2->pcb_ucp.uc_stack.ss_sp = pcb2->sys_stack;
 	pcb2->pcb_ucp.uc_stack.ss_size = pcb2->sys_stack_top - pcb2->sys_stack;
-	pcb2->pcb_ucp.uc_flags = _UC_STACK | _UC_CPU | _UC_SIGMASK;
 	pcb2->pcb_ucp.uc_link = &pcb2->pcb_userret_ucp;
+
+	thunk_sigemptyset(&pcb2->pcb_ucp.uc_sigmask);
+	pcb2->pcb_ucp.uc_flags = _UC_STACK | _UC_CPU | _UC_SIGMASK;
 	thunk_makecontext(&pcb2->pcb_ucp,
 	    (void (*)(void)) cpu_lwp_trampoline,
 	    3, &pcb2->pcb_ucp, func, arg);
@@ -412,7 +415,9 @@
 	/* init lwp0 */
 	memset(&lwp0pcb, 0, sizeof(lwp0pcb));
 	thunk_getcontext(&lwp0pcb.pcb_ucp);
+	thunk_sigemptyset(&lwp0pcb.pcb_ucp.uc_sigmask);
 	lwp0pcb.pcb_ucp.uc_flags = _UC_STACK | _UC_CPU | _UC_SIGMASK;
+
 	uvm_lwp_setuarea(&lwp0, (vaddr_t) &lwp0pcb);
 	memcpy(&lwp0pcb.pcb_userret_ucp, &lwp0pcb.pcb_ucp, sizeof(ucontext_t));
 

cvs diff -r1.4 -r1.5 src/sys/arch/usermode/dev/if_veth.c (expand / switch to context diff)
--- src/sys/arch/usermode/dev/if_veth.c 2012/01/15 10:51:12 1.4
+++ src/sys/arch/usermode/dev/if_veth.c 2012/01/21 22:09:56 1.5
@@ -1,4 +1,4 @@
-/* $NetBSD: if_veth.c,v 1.4 2012/01/15 10:51:12 jmcneill Exp $ */
+/* $NetBSD: if_veth.c,v 1.5 2012/01/21 22:09:56 reinoud Exp $ */
 
 /*-
  * Copyright (c) 2011 Jared D. McNeill <jmcneill@invisible.ca>
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_veth.c,v 1.4 2012/01/15 10:51:12 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_veth.c,v 1.5 2012/01/21 22:09:56 reinoud Exp $");
 
 #include <sys/param.h>
 #include <sys/proc.h>
@@ -189,10 +189,7 @@
 {
 	struct veth_softc *sc = priv;
 
-	curcpu()->ci_idepth++;
-	spl_intr(IPL_NET, softint_schedule, sc->sc_rx_intr);
-	curcpu()->ci_idepth--;
-
+	softint_schedule(sc->sc_rx_intr);
 	return 0;
 }
 

cvs diff -r1.29 -r1.30 src/sys/arch/usermode/dev/ld_thunkbus.c (expand / switch to context diff)
--- src/sys/arch/usermode/dev/ld_thunkbus.c 2012/01/09 21:01:31 1.29
+++ src/sys/arch/usermode/dev/ld_thunkbus.c 2012/01/21 22:09:57 1.30
@@ -1,4 +1,4 @@
-/* $NetBSD: ld_thunkbus.c,v 1.29 2012/01/09 21:01:31 reinoud Exp $ */
+/* $NetBSD: ld_thunkbus.c,v 1.30 2012/01/21 22:09:57 reinoud Exp $ */
 
 /*-
  * Copyright (c) 2011 Jared D. McNeill <jmcneill@invisible.ca>
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ld_thunkbus.c,v 1.29 2012/01/09 21:01:31 reinoud Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ld_thunkbus.c,v 1.30 2012/01/21 22:09:57 reinoud Exp $");
 
 #include <sys/param.h>
 #include <sys/proc.h>
@@ -145,9 +145,7 @@
 	struct ld_softc *ld = arg;
 	struct ld_thunkbus_softc *sc = (struct ld_thunkbus_softc *)ld;
 
-	curcpu()->ci_idepth++;
-	spl_intr(IPL_BIO, softint_schedule, sc->sc_ih);
-	curcpu()->ci_idepth--;
+	softint_schedule(sc->sc_ih);
 
 	return 0;
 }
@@ -250,7 +248,7 @@
 
 	/* let the softint do the work */
 	sc->busy = true;
-	spl_intr(IPL_BIO, softint_schedule, sc->sc_ih);
+	softint_schedule(sc->sc_ih);
 
 	return 0;
 }

cvs diff -r1.17 -r1.18 src/sys/arch/usermode/dev/ttycons.c (expand / switch to context diff)
--- src/sys/arch/usermode/dev/ttycons.c 2011/12/27 20:59:45 1.17
+++ src/sys/arch/usermode/dev/ttycons.c 2012/01/21 22:09:57 1.18
@@ -1,4 +1,4 @@
-/* $NetBSD: ttycons.c,v 1.17 2011/12/27 20:59:45 jmcneill Exp $ */
+/* $NetBSD: ttycons.c,v 1.18 2012/01/21 22:09:57 reinoud Exp $ */
 
 /*-
  * Copyright (c) 2007 Jared D. McNeill <jmcneill@invisible.ca>
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ttycons.c,v 1.17 2011/12/27 20:59:45 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ttycons.c,v 1.18 2012/01/21 22:09:57 reinoud Exp $");
 
 #include <sys/param.h>
 #include <sys/conf.h>
@@ -103,9 +103,9 @@
 static int	ttycons_intr(void *);
 static void	ttycons_softintr(void *);
 
-static void	ttycons_ctrlc(int);
+static sigfunc_t  ttycons_ctrlc;
 static void	ttycons_softctrlc(void *);
-static void	ttycons_ctrlz(int);
+static sigfunc_t  ttycons_ctrlz;
 static void	ttycons_softctrlz(void *);
 
 static int
@@ -154,8 +154,9 @@
 		panic("couldn't establish ttycons ctrlz handler\n");
 
 	sigio_intr_establish(ttycons_intr, sc);
-	thunk_signal(SIGINT, ttycons_ctrlc);
-	thunk_signal(SIGTSTP, ttycons_ctrlz);
+	signal_intr_establish(SIGINT,  ttycons_ctrlc);
+	signal_intr_establish(SIGTSTP, ttycons_ctrlz);
+
 	if (thunk_set_stdin_sigio(true) != 0)
 		panic("couldn't enable stdin async mode");
 }
@@ -361,9 +362,7 @@
 {
 	struct ttycons_softc *sc = priv;
 
-	curcpu()->ci_idepth++;
-	spl_intr(IPL_SERIAL, softint_schedule, sc->sc_rd_sih);
-	curcpu()->ci_idepth--;
+	softint_schedule(sc->sc_rd_sih);
 
 	return 0;
 }
@@ -383,17 +382,20 @@
 	}
 }
 
+
+/*
+ * handle SIGINT signal from trap.c
+ *
+ * argument 'pc' and 'va' are not used.
+ */
 static void
-ttycons_ctrlc(int sig)
+ttycons_ctrlc(vaddr_t from_userland, vaddr_t pc, vaddr_t va)
 {
 	struct ttycons_softc *sc;
 
-	curcpu()->ci_idepth++;
 	sc = device_lookup_private(&ttycons_cd, minor(cn_tab->cn_dev));
-	if (sc) {
-		spl_intr(IPL_SERIAL, softint_schedule, sc->sc_ctrlc_sih);
-	}
-	curcpu()->ci_idepth--;
+	if (sc)
+		softint_schedule(sc->sc_ctrlc_sih);
 
 }
 
@@ -408,18 +410,19 @@
 	t->t_linesw->l_rint(ch, t);
 }
 
+/*
+ * handle SIGTSTP signal from trap.c
+ *
+ * argument 'pc' and 'va' are not used.
+ */
 static void
-ttycons_ctrlz(int sig)
+ttycons_ctrlz(vaddr_t from_userland, vaddr_t pc, vaddr_t va)
 {
 	struct ttycons_softc *sc;
 
-	curcpu()->ci_idepth++;
 	sc = device_lookup_private(&ttycons_cd, minor(cn_tab->cn_dev));
-	if (sc) {
-		spl_intr(IPL_SERIAL, softint_schedule, sc->sc_ctrlz_sih);
-	}
-	curcpu()->ci_idepth--;
-
+	if (sc)
+		softint_schedule(sc->sc_ctrlz_sih);
 }
 
 static void

cvs diff -r1.6 -r1.7 src/sys/arch/usermode/include/intr.h (expand / switch to context diff)
--- src/sys/arch/usermode/include/intr.h 2011/12/26 22:04:35 1.6
+++ src/sys/arch/usermode/include/intr.h 2012/01/21 22:09:57 1.7
@@ -1,4 +1,4 @@
-/* $NetBSD: intr.h,v 1.6 2011/12/26 22:04:35 jmcneill Exp $ */
+/* $NetBSD: intr.h,v 1.7 2012/01/21 22:09:57 reinoud Exp $ */
 
 /*-
  * Copyright (c) 2007 Jared D. McNeill <jmcneill@invisible.ca>
@@ -32,9 +32,7 @@
 #include <machine/intrdefs.h>
 #include <sys/siginfo.h>
 
-void	sigio_signal_handler(int, siginfo_t *, void *);
-void *	sigio_intr_establish(int (*)(void *), void *);
-
+/* spl */
 void	splinit(void);
 int	splraise(int);
 void	spllower(int);
@@ -43,6 +41,13 @@
 #define	spl0()		spllower(IPL_NONE)
 #define splx(x)		spllower(x)
 
+/* traps */
+typedef void (sigfunc_t)(vaddr_t from_userland, vaddr_t pc, vaddr_t va);
+extern void setup_signal_handlers(void);
+extern void  signal_intr_establish(int sig, sigfunc_t f);
+extern void *sigio_intr_establish(int (*)(void *), void *);
+
+/* spl implementation */
 typedef uint8_t ipl_t;
 typedef struct {
 	ipl_t _ipl;
@@ -61,5 +66,7 @@
 }
 
 #include <sys/spl.h>
+
+/* for trap.c */
 
 #endif /* !_ARCH_USERMODE_INCLUDE_INTR_H */

cvs diff -r1.14 -r1.15 src/sys/arch/usermode/usermode/intr.c (expand / switch to context diff)
--- src/sys/arch/usermode/usermode/intr.c 2012/01/09 22:20:53 1.14
+++ src/sys/arch/usermode/usermode/intr.c 2012/01/21 22:09:57 1.15
@@ -1,4 +1,4 @@
-/* $NetBSD: intr.c,v 1.14 2012/01/09 22:20:53 reinoud Exp $ */
+/* $NetBSD: intr.c,v 1.15 2012/01/21 22:09:57 reinoud Exp $ */
 
 /*-
  * Copyright (c) 2011 Jared D. McNeill <jmcneill@invisible.ca>
@@ -27,152 +27,36 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: intr.c,v 1.14 2012/01/09 22:20:53 reinoud Exp $");
+__KERNEL_RCSID(0, "$NetBSD: intr.c,v 1.15 2012/01/21 22:09:57 reinoud Exp $");
 
 #include <sys/types.h>
 
 #include <machine/intr.h>
 #include <machine/thunk.h>
 
-struct intr_handler {
-	int (*func)(void *);
-	void *arg;
-};
+int usermode_x = IPL_NONE;
 
-#define SIGIO_MAX_HANDLERS	8
-
-static struct intr_handler sigio_intr_handler[SIGIO_MAX_HANDLERS];
-
-//#define INTR_USE_SIGPROCMASK
-
-#define MAX_QUEUED_EVENTS 128
-
-static int usermode_x = IPL_NONE;
-
-#ifdef INTR_USE_SIGPROCMASK
-static bool block_sigalrm = false;
-#endif
-
-
-struct spl_intr_event {
-	void (*func)(void *);
-	void *arg;
-};
-
-struct spl_intr_event spl_intrs[IPL_HIGH+1][MAX_QUEUED_EVENTS];
-int spl_intr_wr[IPL_HIGH+1];
-int spl_intr_rd[IPL_HIGH+1];
-
 void
 splinit(void)
 {
-	int i;
-	for (i = 0; i <= IPL_HIGH; i++) {
-		spl_intr_rd[i] = 1;
-		spl_intr_wr[i] = 1;
-	}
+	/* nothing */
 }
 
-void
-spl_intr(int x, void (*func)(void *), void *arg)
-{
-	struct spl_intr_event *spli;
-
-	if (x >= usermode_x) {
-		func(arg);
-		return;
-	}
-
-//	dprintf_debug("spl_intr: queue %d when %d\n", x, usermode_x);
-	spli = &spl_intrs[x][spl_intr_wr[x]];
-	spli->func = func;
-	spli->arg = arg;
-
-	spl_intr_wr[x] = (spl_intr_wr[x] + 1) % MAX_QUEUED_EVENTS;
-	if (spl_intr_wr[x] == spl_intr_rd[x]) {
-		thunk_printf("%s: spl list %d full!\n", __func__, x);
-		panic("%s: spl list %d full!\n", __func__, x);
-	}
-}
-
 int
 splraise(int x)
 {
 	int oldx = usermode_x;
 
-	if (x > usermode_x) {
+	if (x > usermode_x)
 		usermode_x = x;
-	}
 
-#ifdef INTR_USE_SIGPROCMASK
-	if (x >= IPL_SCHED && !block_sigalrm) {
-		thunk_sigblock(SIGALRM);
-		block_sigalrm = true;
-	}
-#endif
-
 	return oldx;
 }
 
 void
 spllower(int x)
 {
-	struct spl_intr_event *spli;
-	int y;
-
-	/* `eat' interrupts that came by until we got back to x */
-	if (usermode_x > x) {
-//restart:
-		for (y = usermode_x; y >= x; y--) {
-			while (spl_intr_rd[y] != spl_intr_wr[y]) {
-//				dprintf_debug("spl y %d firing\n", y);
-				spli = &spl_intrs[y][spl_intr_rd[y]];
-				if (!spli->func)
-					panic("%s: spli->func is NULL for ipl %d, rd %d, wr %d\n",
-						__func__, y, spl_intr_rd[y], spl_intr_wr[y]);
-				spli->func(spli->arg);
-				spl_intr_rd[y] = (spl_intr_rd[y] + 1) % MAX_QUEUED_EVENTS;
-//				goto restart;
-			}
-		}
+	if (usermode_x > x)
 		usermode_x = x;
-	}
-
-#ifdef INTR_USE_SIGPROCMASK
-	if (x < IPL_SCHED && block_sigalrm) {
-		thunk_sigunblock(SIGALRM);
-		block_sigalrm = false;
-	}
-#endif
 }
 
-void
-sigio_signal_handler(int sig, siginfo_t *info, void *ctx)
-{
-	struct intr_handler *sih;
-	unsigned int n;
-
-	for (n = 0; n < SIGIO_MAX_HANDLERS; n++) {
-		sih = &sigio_intr_handler[n];
-		if (sih->func)
-			sih->func(sih->arg);
-	}
-}
-
-void *
-sigio_intr_establish(int (*func)(void *), void *arg)
-{
-	struct intr_handler *sih;
-	unsigned int n;
-
-	for (n = 0; n < SIGIO_MAX_HANDLERS; n++) {
-		sih = &sigio_intr_handler[n];
-		if (sih->func == NULL) {
-			sih->func = func;
-			sih->arg = arg;
-			return sih;
-		}
-	}
-
-	panic("increase SIGIO_MAX_HANDLERS");
-}

cvs diff -r1.60 -r1.61 src/sys/arch/usermode/usermode/trap.c (expand / switch to context diff)
--- src/sys/arch/usermode/usermode/trap.c 2012/01/18 12:39:45 1.60
+++ src/sys/arch/usermode/usermode/trap.c 2012/01/21 22:09:57 1.61
@@ -1,4 +1,4 @@
-/* $NetBSD: trap.c,v 1.60 2012/01/18 12:39:45 reinoud Exp $ */
+/* $NetBSD: trap.c,v 1.61 2012/01/21 22:09:57 reinoud Exp $ */
 
 /*-
  * Copyright (c) 2011 Reinoud Zandijk <reinoud@netbsd.org>
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.60 2012/01/18 12:39:45 reinoud Exp $");
+__KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.61 2012/01/21 22:09:57 reinoud Exp $");
 
 #include <sys/types.h>
 #include <sys/param.h>
@@ -46,24 +46,49 @@
 #include <machine/intr.h>
 #include <machine/thunk.h>
 
+/* define maximum signal number */
+#ifndef NSIG
+#define NSIG 64
+#endif
 
 /* forwards and externals */
 void setup_signal_handlers(void);
 void stop_all_signal_handlers(void);
 
-static void mem_access_handler(int sig, siginfo_t *info, void *ctx);
-static void illegal_instruction_handler(int sig, siginfo_t *info, void *ctx);
-extern int errno;
+static sigfunc_t pagefault;
+static sigfunc_t illegal_instruction;
+static sigfunc_t alarm;
+static sigfunc_t sigio;
 
-static void pagefault(vaddr_t from_userland, vaddr_t pc, vaddr_t va);
-static void illegal_instruction(vaddr_t from_userland);
+/* raw signal handlers */
+static stack_t sigstk;
+ucontext_t jump_ucp;
 
-bool pmap_fault(pmap_t pmap, vaddr_t va, vm_prot_t *atype);
+sigfunc_t *sig_funcs[NSIG];
 
-static stack_t sigstk;
+/* segv, bus */
+extern bool pmap_fault(pmap_t pmap, vaddr_t va, vm_prot_t *atype);
 
+/* alarm */
+void setup_clock_intr(void);
+extern void clock_intr(void *priv);
+
+extern int clock_running;
+void *alrm_ih;
+
+/* sigio handlers */
+struct intr_handler {
+	int (*func)(void *);
+	void *arg;
+};
+#define SIGIO_MAX_HANDLERS	8
+static struct intr_handler sigio_intr_handler[SIGIO_MAX_HANDLERS];
+
+/* misc */
 int astpending = 0;
 
+
+/* XXX why is it here ? */
 void
 startlwp(void *arg)
 {
@@ -74,8 +99,14 @@
 void
 setup_signal_handlers(void)
 {
-	static struct sigaction sa;
+	int i;
 
+	/*
+	 * Set up the alternative signal stack. This prevents signals to be
+	 * pushed on the NetBSD/usermode userland's stack with all desastrous
+	 * effects. Especially ld.so and friends have such tiny stacks that
+	 * its not feasable.
+	 */
 	if ((sigstk.ss_sp = thunk_malloc(SIGSTKSZ)) == NULL)
 		panic("can't allocate signal stack space\n");
 	sigstk.ss_size  = SIGSTKSZ;
@@ -84,68 +115,106 @@
 		panic("can't set alternate stacksize: %d",
 		    thunk_geterrno());
 
-	/* SIGBUS and SIGSEGV need to be reentrant hence the SA_NODEFER */
-	sa.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK | SA_NODEFER;
-	sa.sa_sigaction = mem_access_handler;
-	thunk_sigemptyset(&sa.sa_mask);
-	if (thunk_sigaction(SIGSEGV, &sa, NULL) == -1)
-		panic("couldn't register SIGSEGV handler: %d",
-		    thunk_geterrno());
-	if (thunk_sigaction(SIGBUS, &sa, NULL) == -1)
-		panic("couldn't register SIGBUS handler: %d", thunk_geterrno());
+	for (i = 0; i < NSIG; i++)
+		sig_funcs[i] = NULL;
 
-	sa.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK;
-	sa.sa_sigaction = illegal_instruction_handler;
-	thunk_sigemptyset(&sa.sa_mask);
-	if (thunk_sigaction(SIGILL, &sa, NULL) == -1)
-		panic("couldn't register SIGILL handler: %d", thunk_geterrno());
-
-	sa.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK;
-	sa.sa_sigaction = sigio_signal_handler;
-	thunk_sigemptyset(&sa.sa_mask);
-	if (thunk_sigaction(SIGIO, &sa, NULL) == -1)
-		panic("couldn't register SIGIO handler: %d", thunk_geterrno());
+	/* HUP */
+	/* INT */	/* ttycons ^C */
+	/* QUIT */
+	signal_intr_establish(SIGILL, illegal_instruction);
+	/* TRAP */
+	/* ABRT */
+	/* SIGEMT */
+	/* SIGFPE XXX! */
+	/* KILL */
+	signal_intr_establish(SIGBUS,  pagefault);
+	signal_intr_establish(SIGSEGV, pagefault);
+	/* SYS */
+	/* PIPE */
+	signal_intr_establish(SIGALRM, alarm);
+	/* TERM */
+	/* URG */
+	/* STOP */
+	/* TSTP */	/* ttycons ^Z */
+	/* CONT */
+	/* CHLD */
+	/* GTTIN */
+	/* TTOU */
+	signal_intr_establish(SIGIO,   sigio);
+	/* XCPU */
+	/* XFSZ */
+	/* VTALRM */
+	/* PROF */
+	/* WINCH */
+	/* INFO */
+	/* USR1 */
+	/* USR2 */
+	/* PWR */
 }
 
 
+/* XXX yes this is blunt */
 void
 stop_all_signal_handlers(void)
 {
-	thunk_sigblock(SIGALRM);
-	thunk_sigblock(SIGIO);
-	thunk_sigblock(SIGILL);
-	thunk_sigblock(SIGSEGV);
-	thunk_sigblock(SIGBUS);
+	int i;
+	for (i = 0; i < NSIG; i++)
+		if (sig_funcs[i])
+			thunk_sigblock(i);
 }
 
 
-/* ast and userret */
 void
-userret(struct lwp *l)
+setup_clock_intr(void)
 {
-	/* invoke MI userret code */
-	mi_userret(l);
+	/* setup soft interrupt handler */
+	alrm_ih = softint_establish(SOFTINT_CLOCK,
+		clock_intr, NULL);
+}
 
-	while (astpending) {
-		astpending = 0;
 
-		curcpu()->ci_data.cpu_ntrap++;
+/* ast and userret */
+static void
+ast(struct lwp *l)
+{
+	struct pcb *pcb;
+
+	if (!astpending)
+		return;
+
+	astpending = 0;
+	curcpu()->ci_data.cpu_ntrap++;
+
 #if 0
-		/* profiling */
-		if (l->l_pflag & LP_OWEUPC) {
-			l->l_pflag &= ~LP_OWEUPC;
-			ADDUPROF(l);
-		}
+	/* profiling */
+	if (l->l_pflag & LP_OWEUPC) {
+		l->l_pflag &= ~LP_OWEUPC;
+		ADDUPROF(l);
+	}
 #endif
-		/* allow a forced task switch */
-		if (l->l_cpu->ci_want_resched)
-			preempt();
 
-		mi_userret(l);
+	/* allow a forced task switch */
+	if (curcpu()->ci_want_resched) {
+		curcpu()->ci_want_resched = 0;
+		preempt();
+		/* returns here! */
 	}
+	KASSERT(l == curlwp); KASSERT(l);
+	pcb = lwp_getpcb(l); KASSERT(pcb);
+	mi_userret(l);
 }
 
 
+void
+userret(struct lwp *l)
+{
+	/* invoke MI userret code */
+	mi_userret(l);
+
+	ast(l);
+}
+
+
 #ifdef DEBUG
 /*
  * Uncomment the following if you want to receive information about what
@@ -175,11 +244,8 @@
 #endif
 
 #if 0
-	printf("memaccess error, pc %p, va %p, "
-		"sys_stack %p, sp %p, stack top %p\n",
-		(void *) pc, (void *) va,
-		(void *) pcb->sys_stack, (void *) sp,
-		(void *) pcb->sys_stack_top);
+	thunk_printf("memaccess error, pc %p, va %p, sp %p\n",
+		(void *) pc, (void *) va, (void *) sp);
 #endif
 }
 
@@ -220,6 +286,10 @@
 		thunk_printf("%02x ", *((uint8_t *) info->si_addr + i));
 	thunk_printf("\n");
 #endif
+
+#if 0
+	thunk_printf("sigill\n");
+#endif
 }
 #else /* DEBUG */
 #define print_mem_access_siginfo(s, i, c, p, v, sp)
@@ -227,40 +297,47 @@
 #endif /* DEBUG */
 
 
-/* signal handler switching to a pagefault context */
 static void
-mem_access_handler(int sig, siginfo_t *info, void *ctx)
+handle_signal(int sig, siginfo_t *info, void *ctx)
 {
+	sigfunc_t *f;
 	ucontext_t *ucp = ctx;
 	struct lwp *l;
 	struct pcb *pcb;
 	vaddr_t va, sp, pc, fp;
 	int from_userland;
 
-	assert((info->si_signo == SIGSEGV) || (info->si_signo == SIGBUS));
+	if (sig == SIGBUS || sig == SIGSEGV || sig == SIGILL) {
+		if (info->si_code == SI_NOINFO)
+			panic("received signal %d with no info",
+			    info->si_signo);
+	}
 
-	if (info->si_code == SI_NOINFO)
-		panic("received signal %d with no info",
-		    info->si_signo);
+	f = sig_funcs[sig];
+	KASSERT(f);
 
-	l = curlwp;
-	pcb = lwp_getpcb(l);
+	l = curlwp; KASSERT(l);
+	pcb = lwp_getpcb(l); KASSERT(pcb);
 
-	/* get address of faulted memory access and make it page aligned */
+	/* get address of possible faulted memory access and page aligne it */
 	va = (vaddr_t) info->si_addr;
 	va = trunc_page(va);
 
-	/* get PC address of faulted memory instruction */
+	/* get PC address of possibly faulted instruction */
 	pc = md_get_pc(ctx);
 
-	/* setup for pagefault context */
+	/* nest it on the stack */
 	sp = md_get_sp(ctx);
 
-	print_mem_access_siginfo(sig, info, ctx, pc, va, sp);
+	if (sig == SIGBUS || sig == SIGSEGV)
+		print_mem_access_siginfo(sig, info, ctx, pc, va, sp);
+	if (sig == SIGILL)
+		print_illegal_instruction_siginfo(sig, info, ctx, pc, va, sp);
 
 	/* if we're running on a stack of our own, use the system stack */
 	from_userland = 0;
-	if ((sp < (vaddr_t) pcb->sys_stack) || (sp > (vaddr_t) pcb->sys_stack_top)) {
+	if ((sp < (vaddr_t) pcb->sys_stack) ||
+	    (sp > (vaddr_t) pcb->sys_stack_top)) {
 		sp = (vaddr_t) pcb->sys_stack_top - sizeof(register_t);
 		fp = (vaddr_t) &pcb->pcb_userret_ucp;
 		if (pc < kmem_user_end)
@@ -276,79 +353,38 @@
 	}
 
 	memcpy((void *) fp, ucp, sizeof(ucontext_t));
+	memcpy(&jump_ucp, ucp, sizeof(ucontext_t));
 
-	/* create context for pagefault */
-	pcb->pcb_ucp.uc_stack.ss_sp = (void *) pcb->sys_stack;
-	pcb->pcb_ucp.uc_stack.ss_size = sp - (vaddr_t) pcb->sys_stack;
-	pcb->pcb_ucp.uc_link = (void *) fp;	/* link to old frame on stack */
+	/* create context */
+	jump_ucp.uc_stack.ss_sp = (void *) pcb->sys_stack;
+	jump_ucp.uc_stack.ss_size = sp - (vaddr_t) pcb->sys_stack;
+	jump_ucp.uc_link = (void *) fp;	/* link to old frame on stack */
 
-	pcb->pcb_ucp.uc_flags = _UC_STACK | _UC_CPU;
-	thunk_makecontext(&pcb->pcb_ucp, (void (*)(void)) pagefault,
+	thunk_sigemptyset(&jump_ucp.uc_sigmask);
+	jump_ucp.uc_flags = _UC_STACK | _UC_CPU | _UC_SIGMASK;
+	thunk_makecontext(&jump_ucp,
+			(void (*)(void)) f,
 		3, (void *) from_userland, (void *) pc, (void *) va);
 
-	/* switch to the new pagefault entry on return from signal */
-	memcpy(ctx, &pcb->pcb_ucp, sizeof(ucontext_t));
+	/* switch to the new context on return from signal */
+	thunk_setcontext(&jump_ucp);
+//	memcpy(ctx, &pcb->pcb_ucp, sizeof(ucontext_t));
 }
 
 
-/* signal handler switching to a illegal instruction context */
-static void
-illegal_instruction_handler(int sig, siginfo_t *info, void *ctx)
+void
+signal_intr_establish(int sig, sigfunc_t f)
 {
-	ucontext_t *ucp = ctx;
-	struct lwp *l;
-	struct pcb *pcb;
-	vaddr_t sp, pc, fp;
-	int from_userland;
+	static struct sigaction sa;
 
-	assert(info->si_signo == SIGILL);
+	sig_funcs[sig] = f;
 
-	l = curlwp;
-	pcb = lwp_getpcb(l);
-
-	/* get PC address of faulted instruction */
-	pc = md_get_pc(ctx);
-
-	/* setup for illegal_instruction context */
-	sp = md_get_sp(ctx);
-
-	print_illegal_instruction_siginfo(sig, info, ctx, pc, 0, sp);
-
-	/* if we're running on a stack of our own, use the system stack */
-	from_userland = 0;
-	if ((sp < (vaddr_t) pcb->sys_stack) ||
-			(sp > (vaddr_t) pcb->sys_stack_top)) {
-		sp = (vaddr_t) pcb->sys_stack_top - sizeof(register_t);
-		fp = (vaddr_t) &pcb->pcb_userret_ucp;
-
-		KASSERT(pc < kmem_user_end);
-		from_userland = 1;
-	} else {
-		panic("illegal instruction inside kernel?");
-#if 0
-		/* stack grows down */
-		fp = sp - sizeof(ucontext_t) - sizeof(register_t); /* slack */
-		sp = fp - sizeof(register_t);	/* slack */
-
-		/* sanity check before copying */
-		if (fp - 2*PAGE_SIZE < (vaddr_t) pcb->sys_stack)
-			panic("%s: out of system stack", __func__);
-#endif
-	}
-
-	memcpy((void *) fp, ucp, sizeof(ucontext_t));
-
-	/* create context for illegal instruction */
-	pcb->pcb_ucp.uc_stack.ss_sp = (void *) pcb->sys_stack;
-	pcb->pcb_ucp.uc_stack.ss_size = sp - (vaddr_t) pcb->sys_stack;
-	pcb->pcb_ucp.uc_link = (void *) fp;	/* link to old frame on stack */
-
-	pcb->pcb_ucp.uc_flags = _UC_STACK | _UC_CPU;
-	thunk_makecontext(&pcb->pcb_ucp, (void (*)(void)) illegal_instruction,
-		1, (void *) from_userland, NULL, NULL);
-
-	/* switch to the new illegal instruction entry on return from signal */
-	memcpy(ctx, &pcb->pcb_ucp, sizeof(ucontext_t));
+	sa.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK;
+	sa.sa_sigaction = (void *) handle_signal;
+	thunk_sigfillset(&sa.sa_mask);
+	if (thunk_sigaction(sig, &sa, NULL) == -1)
+		panic("couldn't register SIG%d handler: %d", sig,
+		    thunk_geterrno());
 }
 
 
@@ -377,18 +413,17 @@
 	lwp_errno = thunk_geterrno();
 
 	vm_map = &vm->vm_map;
-	from_kernel = (pc >= kmem_k_start);
+	from_kernel = (pc >= kmem_k_start) && (!from_userland);
 	if (from_kernel && (va >= VM_MIN_KERNEL_ADDRESS))
 		vm_map = kernel_map;
 
 #if 0
-	thunk_printf("pagefault : pc %p, va %p\n",
-		(void *) pc, (void *) va);
+	thunk_printf("%s: l %p, pcb %p\n", __func__, l, pcb);
+	thunk_printf("\tpc %p, va %p\n", (void *) pc, (void *) va);
 #endif
 
 	/* can pmap handle it? on its own? (r/m) emulation */
 	if (pmap_fault(vm_map->pmap, va, &atype)) {
-//		thunk_printf("pagefault leave (pmap)\n");
 		/* no use doing anything else here */
 		goto out_quick;
 	}
@@ -416,8 +451,8 @@
 	}
 
 	/* something got wrong */
-	thunk_printf("%s: uvm fault %d, pc %p, from_kernel %d\n",
-		__func__, error, (void *) pc, from_kernel);
+	thunk_printf("%s: uvm fault %d, pc %p, va %p, from_kernel %d\n",
+		__func__, error, (void *) pc, (void *) va, from_kernel);
 
 	/* check if its from copyin/copyout */
 	if (onfault) {
@@ -437,6 +472,7 @@
 	/* send signal */
 	thunk_printf("giving signal to userland\n");
 
+	KASSERT(from_userland);
 	KSI_INIT_TRAP(&ksi);
 	ksi.ksi_signo = SIGSEGV;
 	ksi.ksi_trap = 0;	/* XXX */
@@ -468,28 +504,32 @@
 
 
 /*
- * Context for handing illegal instruction from the sigill handler
+ * handle an illegal instruction.
+ *
+ * arguments 'pc' and 'va' are ignored here
  */
 static void
-illegal_instruction(vaddr_t from_userland)
+illegal_instruction(vaddr_t from_userland, vaddr_t pc, vaddr_t va)
 {
 	struct lwp *l = curlwp;
 	struct pcb *pcb = lwp_getpcb(l);
 	ucontext_t *ucp = &pcb->pcb_userret_ucp;
 	ksiginfo_t ksi;
 
-//	thunk_printf("illegal instruction\n");
+//	thunk_printf("%s: l %p, pcb %p\n", __func__, l, pcb);
+
+	KASSERT(from_userland);
+
 	/* if its a syscall ... */
 	if (md_syscall_check_opcode(ucp)) {
 		syscall();
-//		thunk_printf("illegal instruction leave\n");
-		KASSERT(from_userland);
 		userret(l);
 		return;
 	}
 
 	thunk_printf("%s: giving SIGILL (TRAP)\n", __func__);
 
+	KASSERT(from_userland);
 	KSI_INIT_TRAP(&ksi);
 	ksi.ksi_signo = SIGILL;
 	ksi.ksi_trap  = 0;	/* XXX */
@@ -502,7 +542,75 @@
 #else
 	trapsignal(l, &ksi);
 #endif
-	KASSERT(from_userland);
 	userret(l);
+}
+
+
+/*
+ * handle alarm, a clock ticker.
+ *
+ * arguments 'pc' and 'va' are ignored here
+ */
+static void
+alarm(vaddr_t from_userland, vaddr_t pc, vaddr_t va)
+{
+	struct lwp *l = curlwp;
+	struct pcb *pcb = lwp_getpcb(l); KASSERT(pcb);
+
+	if (!clock_running)
+		return;
+//	thunk_printf("%s: l %p, pcb %p\n", __func__, l, pcb);
+
+	softint_schedule(alrm_ih);
+
+	KASSERT(l == curlwp);
+	if (from_userland)
+		userret(l);
+}
+
+
+/*
+ * handle sigio, a mux for all io operations.
+ *
+ * arguments 'pc' and 'va' are ignored here
+ */
+static void
+sigio(vaddr_t from_userland, vaddr_t pc, vaddr_t va)
+{
+	struct lwp *l = curlwp;
+	struct pcb *pcb = lwp_getpcb(l); KASSERT(pcb);
+	struct intr_handler *sih;
+	unsigned int n;
+
+//	thunk_printf("%s: l %p, pcb %p\n", __func__, l, pcb);
+	for (n = 0; n < SIGIO_MAX_HANDLERS; n++) {
+		sih = &sigio_intr_handler[n];
+		if (sih->func)
+			sih->func(sih->arg);
+	}
+
+	KASSERT(l == curlwp);
+	if (from_userland)
+		userret(l);		/* or ast? */
+}
+
+
+/* sigio register function */
+void *
+sigio_intr_establish(int (*func)(void *), void *arg)
+{
+	struct intr_handler *sih;
+	unsigned int n;
+
+	for (n = 0; n < SIGIO_MAX_HANDLERS; n++) {
+		sih = &sigio_intr_handler[n];
+		if (sih->func == NULL) {
+			sih->func = func;
+			sih->arg = arg;
+			return sih;
+		}
+	}
+
+	panic("increase SIGIO_MAX_HANDLERS");
 }