patch-2.1.101 linux/arch/mips/kernel/signal.c

Next file: linux/arch/mips/kernel/syscall.c
Previous file: linux/arch/mips/kernel/setup.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.1.100/linux/arch/mips/kernel/signal.c linux/arch/mips/kernel/signal.c
@@ -4,7 +4,9 @@
  *  Copyright (C) 1991, 1992  Linus Torvalds
  *  Copyright (C) 1994, 1995, 1996  Ralf Baechle
  *
- * $Id: signal.c,v 1.8 1997/12/01 16:26:34 ralf Exp $
+ * $Id: signal.c,v 1.12 1998/05/01 01:34:28 ralf Exp $
+ *
+ * XXX Handle lazy fp context switches correctly.
  */
 #include <linux/config.h>
 #include <linux/sched.h>
@@ -23,82 +25,189 @@
 #include <asm/pgtable.h>
 #include <asm/uaccess.h>
 
-#define _S(nr) (1<<((nr)-1))
+#define DEBUG_SIG 0
 
-#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))
+#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
 
 asmlinkage int sys_wait4(pid_t pid, unsigned long *stat_addr,
                          int options, unsigned long *ru);
-asmlinkage int do_signal(unsigned long oldmask, struct pt_regs *regs);
+asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs);
 extern asmlinkage void (*save_fp_context)(struct sigcontext *sc);
 extern asmlinkage void (*restore_fp_context)(struct sigcontext *sc);
 
 /*
  * Atomically swap in the new signal mask, and wait for a signal.
- * Unlike on Intel we pass a sigset_t *, not sigset_t.
  */
-asmlinkage int sys_sigsuspend(struct pt_regs *regs)
+asmlinkage inline int
+sys_sigsuspend(struct pt_regs regs)
 {
-	unsigned long mask;
-	sigset_t *uset, set;
+	sigset_t *uset, saveset, newset;
 
-	uset = (sigset_t *) regs->regs[4];
-	if (get_user(set, uset))
+	uset = (sigset_t *) regs.regs[4];
+	if (copy_from_user(&newset, uset, sizeof(sigset_t)))
 		return -EFAULT;
+	sigdelsetmask(&newset, ~_BLOCKABLE);
 
 	spin_lock_irq(&current->sigmask_lock);
-	mask = current->blocked;
-	current->blocked = set & _BLOCKABLE;
+	saveset = current->blocked;
+	current->blocked = newset;
 	spin_unlock_irq(&current->sigmask_lock);
 
-	regs->regs[2] = -EINTR;
+	regs.regs[2] = -EINTR;
 	while (1) {
 		current->state = TASK_INTERRUPTIBLE;
 		schedule();
-		if (do_signal(mask, regs))
+		if (do_signal(&saveset, &regs))
 			return -EINTR;
 	}
-	return -EINTR;
 }
 
-asmlinkage int sys_sigreturn(struct pt_regs *regs)
+asmlinkage int
+sys_rt_sigsuspend(struct pt_regs regs)
 {
-	struct sigcontext *context;
-	unsigned long blocked;
-	long long reg;
-	int i;
+	sigset_t *uset, saveset, newset;
 
-	context = (struct sigcontext *)(long) regs->regs[29];
-	if (!access_ok(VERIFY_READ, context, sizeof(struct sigcontext)) ||
-	    (regs->regs[29] & (SZREG - 1)))
-		goto badframe;
+	uset = (sigset_t *) regs.regs[4];
+	if (copy_from_user(&newset, uset, sizeof(sigset_t)))
+		return -EFAULT;
+	sigdelsetmask(&newset, ~_BLOCKABLE);
 
-	__get_user(blocked, &context->sc_sigset);
-	current->blocked = blocked & _BLOCKABLE;
-	__get_user(regs->cp0_epc, &context->sc_pc);
+	spin_lock_irq(&current->sigmask_lock);
+	saveset = current->blocked;
+	current->blocked = newset;
+	spin_unlock_irq(&current->sigmask_lock);
 
-	/*
-	 * Restore all integer registers.
-	 */
-	for(i = 31;i >= 0;i--) {
-		__get_user(reg, &context->sc_regs[i]);
-		regs->regs[i] = (int) reg;
+	regs.regs[2] = -EINTR;
+	while (1) {
+		current->state = TASK_INTERRUPTIBLE;
+		schedule();
+		if (do_signal(&saveset, &regs))
+			return -EINTR;
 	}
+}
+
+asmlinkage int 
+sys_sigaction(int sig, const struct sigaction *act,
+	      struct sigaction *oact)
+{
+	struct k_sigaction new_ka, old_ka;
+	int ret;
+
+	if (act) {
+		sigset_t mask;
+		if (verify_area(VERIFY_READ, act, sizeof(*act)) ||
+		    __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
+		    __get_user(new_ka.sa.sa_flags, &act->sa_flags))
+			return -EFAULT;
+
+		__copy_from_user(&mask, &act->sa_mask, sizeof(sigset_t));
+		new_ka.ka_restorer = NULL;
+	}
+
+	ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
+
+	if (!ret && oact) {
+		if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) ||
+		    __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
+		    __put_user(old_ka.sa.sa_flags, &oact->sa_flags))
+			return -EFAULT;
+		__copy_to_user(&old_ka.sa.sa_mask, &oact->sa_mask,
+		               sizeof(sigset_t));
+	}
+
+	return ret;
+}
+
+/*
+ * To do: this entire function should be accessed over a function pointer
+ * such that we can handle stack frames for different ABIs.
+ */
+
+asmlinkage void
+restore_sigcontext(struct pt_regs *regs, struct sigcontext *context)
+{
+	long long reg;
+	int owned_fp;
+
+	__get_user(regs->cp0_epc, &context->sc_pc);
+
 	__get_user(reg, &context->sc_mdhi);
 	regs->hi = (int) reg;
 	__get_user(reg, &context->sc_mdlo);
 	regs->lo = (int) reg;
 
-	/*
-	 * FP depends on what FPU in what mode we have.  Best done in
-	 * Assembler ...
-	 */
-	restore_fp_context(context);
+#define restore_gp_reg(i) __get_user(reg, &context->sc_regs[i]); \
+			  regs->regs[i] = (int) reg;
+	restore_gp_reg( 1); restore_gp_reg( 2); restore_gp_reg( 3);
+	restore_gp_reg( 4); restore_gp_reg( 5); restore_gp_reg( 6);
+	restore_gp_reg( 7); restore_gp_reg( 8); restore_gp_reg( 9);
+	restore_gp_reg(10); restore_gp_reg(11); restore_gp_reg(12);
+	restore_gp_reg(13); restore_gp_reg(14); restore_gp_reg(15);
+	restore_gp_reg(16); restore_gp_reg(17); restore_gp_reg(18);
+	restore_gp_reg(19); restore_gp_reg(20); restore_gp_reg(21);
+	restore_gp_reg(22); restore_gp_reg(23); restore_gp_reg(24);
+	restore_gp_reg(25); restore_gp_reg(26); restore_gp_reg(27);
+	restore_gp_reg(28); restore_gp_reg(29); restore_gp_reg(30);
+	restore_gp_reg(31);
+#undef restore_gp_reg
+
+	/* FP depends on what FPU in what mode we have.  */
+	__get_user(owned_fp, &context->sc_ownedfp);
+#if 0
+	if (owned_fp) {
+		restore_fp_context(context);
+		last_task_used_math = current;
+	}
+#endif
+restore_fp_context(context);
+}
 
-	/*
-	 * Disable syscall checks
-	 */
-	regs->orig_reg2 = -1;
+/*
+ * The structure sc describes the stackframe on the userstack.  The frames
+ * are identical for normal and realtime signal stackframes with the
+ * exception of the additional struct ucontext for rt frames.
+ */
+struct sigframe {
+	unsigned long	ass[4];		/* argument save space for o32 */
+	unsigned int	code[4];	/* signal trampoline */
+	struct sigcontext scc;
+};
+
+struct rt_sigframe {
+	unsigned long	ass[4];
+	unsigned int	code[4];
+	struct sigcontext scc;
+	// struct ucontext uc;
+};
+
+asmlinkage int sys_sigreturn(struct pt_regs regs)
+{
+	struct sigcontext *context;
+	sigset_t blocked;
+
+	context = (struct sigcontext *)(long) regs.regs[29];
+	if (!access_ok(VERIFY_READ, context, sizeof(struct sigcontext)) ||
+	    (regs.regs[29] & (SZREG - 1)))
+		goto badframe;
+
+#if 1
+	if (__get_user(blocked.sig[0], &context->sc_sigset[0]) ||
+	    __get_user(blocked.sig[1], &context->sc_sigset[1]) ||
+	    __get_user(blocked.sig[2], &context->sc_sigset[2]) ||
+	    __get_user(blocked.sig[3], &context->sc_sigset[3]))
+		goto badframe;
+#else
+	if (__copy_from_user(&blocked, &context->sc_sigset, sizeof(blocked)))
+		goto badframe;
+#endif
+
+	sigdelsetmask(&blocked, ~_BLOCKABLE);
+	spin_lock_irq(&current->sigmask_lock);
+	current->blocked = blocked;
+	recalc_sigpending(current);
+	spin_unlock_irq(&current->sigmask_lock);
+
+	restore_sigcontext(&regs, context);
 
 	/*
 	 * Don't let your children do this ...
@@ -107,7 +216,7 @@
 		"move\t$29,%0\n\t"
 		"j\tret_from_sys_call"
 		:/* no outputs */
-		:"r" (regs));
+		:"r" (&regs));
 	/* Unreached */
 
 badframe:
@@ -116,103 +225,113 @@
 	unlock_kernel();
 }
 
+/* same as sys_sigreturn for now */
+asmlinkage int sys_rt_sigreturn(struct pt_regs regs)
+{
+	return -ENOSYS;
+}
+
+#define scc_offset ((size_t)&((struct sigframe *)0)->scc)
+
 /*
- * Set up a signal frame...
- *
- * This routine is somewhat complicated by the fact that if the kernel may be
- * entered by an exception other than a system call; e.g. a bus error or other
- * "bad" exception.  If this is the case, then *all* the context on the kernel
- * stack frame must be saved.
- *
- * For a large number of exceptions, the stack frame format is the same
- * as that which will be created when the process traps back to the kernel
- * when finished executing the signal handler.	In this case, nothing
- * must be done. This information is saved on the user stack and restored
- * when the signal handler is returned.
- *
- * The signal handler will be called with ra pointing to code1 (see below) and
- * one parameters in a0 (signum).
+ * Set up the return code ...
  *
- *     usp ->  [unused]                         ; first free word on stack
- *             arg save space                   ; 16/32 bytes arg. save space
- *	       code1   (addiu sp,#1-offset)	; pop stackframe
- *	       code2   (li v0,__NR_sigreturn)	; syscall number
- *	       code3   (syscall)		; do sigreturn(2)
- *     #1|     $0, at, v0, v1, a0, a1, a2, a3   ; All integer registers
- *       |     t0, t1, t2, t3, t4, t5, t6, t7   ; $0, k0 and k1 are placeholders
- *       |     s0, s1, s2, s3, s4, s5, s6, s7
- *       |     k0, k1, t8, t9, gp, sp, fp, ra;
- *       |     epc                              ; old program counter
- *       |     cause                            ; CP0 cause register
- *       |     oldmask
+ *         .set    noreorder
+ *         addiu   sp,0x20
+ *         li      v0,__NR_sigreturn
+ *         syscall
+ *         .set    reorder
  */
+static void inline
+setup_trampoline(unsigned int *code)
+{
+	__put_user(0x27bd0000 + scc_offset    , code + 0);
+	__put_user(0x24020000 + __NR_sigreturn, code + 1);
+	__put_user(0x0000000c                 , code + 2);
 
-struct sc {
-	unsigned long	ass[4];
-	unsigned int	code[4];
-	struct sigcontext scc;
-};
-#define scc_offset ((size_t)&((struct sc *)0)->scc)
+	/*
+	 * Flush caches so that the instructions will be correctly executed.
+	 */
+	flush_cache_sigtramp((unsigned long) code);
+}
+
+static void inline
+setup_sigcontext(struct pt_regs *regs, struct sigcontext *sc, sigset_t *set)
+{
+	int owned_fp;
+
+	__put_user(regs->cp0_epc, &sc->sc_pc);
+	__put_user(regs->cp0_status, &sc->sc_status);	/* Status register */
+
+#define save_gp_reg(i) __put_user(regs->regs[(i)], &sc->sc_regs[(i)])
+	__put_user(0, &sc->sc_regs[0]); save_gp_reg(1); save_gp_reg(2);
+	save_gp_reg(3); save_gp_reg(4); save_gp_reg(5); save_gp_reg(6);
+	save_gp_reg(7); save_gp_reg(8); save_gp_reg(9); save_gp_reg(10);
+	save_gp_reg(11); save_gp_reg(12); save_gp_reg(13); save_gp_reg(14);
+	save_gp_reg(15); save_gp_reg(16); save_gp_reg(17); save_gp_reg(18);
+	save_gp_reg(19); save_gp_reg(20); save_gp_reg(21); save_gp_reg(22);
+	save_gp_reg(23); save_gp_reg(24); save_gp_reg(25); save_gp_reg(26);
+	save_gp_reg(27); save_gp_reg(28); save_gp_reg(29); save_gp_reg(30);
+	save_gp_reg(31);
+#undef save_gp_reg
+
+	__put_user(regs->hi, &sc->sc_mdhi);
+	__put_user(regs->lo, &sc->sc_mdlo);
+	__put_user(regs->cp0_cause, &sc->sc_cause);
+
+	owned_fp = (current == last_task_used_math);
+	__put_user(owned_fp, &sc->sc_ownedfp);
+
+#if 0
+	if (current->used_math) {	/* fp is active.  */
+		set_cp0_status(ST0_CU1, ST0_CU1);
+		save_fp_context(sc);		/* cpu dependant */
+		last_task_used_math = NULL;
+		regs->cp0_status &= ~ST0_CU1;
+		current->used_math = 0;
+	}
+#endif
+set_cp0_status(ST0_CU1, ST0_CU1);
+save_fp_context(sc);		/* cpu dependant */
 
-static void setup_frame(struct sigaction * sa, struct pt_regs *regs,
-                        int signr, unsigned long oldmask)
+	__put_user(set->sig[0], &sc->sc_sigset[0]);
+	__put_user(set->sig[1], &sc->sc_sigset[1]);
+	__put_user(set->sig[2], &sc->sc_sigset[2]);
+	__put_user(set->sig[3], &sc->sc_sigset[3]);
+}
+
+static void inline
+setup_frame(struct k_sigaction * ka, struct pt_regs *regs,
+            int signr, sigset_t *oldmask)
 {
-	struct sc *frame;
+	struct sigframe *frame;
 	struct sigcontext *sc;
-	int i;
 
 	/* Align the stackframe to an adequate boundary for the architecture. */
-	frame = (struct sc *) (long) regs->regs[29];
+	frame = (struct sigframe *) (long) regs->regs[29];
 	frame--;
-	frame = (struct sc *)((unsigned long)frame & ALMASK);
+	frame = (struct sigframe *)((unsigned long)frame & ALMASK);
 
 	if (verify_area(VERIFY_WRITE, frame, sizeof (*frame)))
 		goto segv_and_exit;
 	sc = &frame->scc;
 
-	/*
-	 * Set up the return code ...
-	 *
-	 *         .set    noreorder
-	 *         addiu   sp,0x20
-	 *         li      v0,__NR_sigreturn
-	 *         syscall
-	 *         .set    reorder
-	 */
-	__put_user(0x27bd0000 + scc_offset, &frame->code[0]);
-	__put_user(0x24020000 + __NR_sigreturn, &frame->code[1]);
-	__put_user(0x0000000c, &frame->code[2]);
-
-	/*
-	 * Flush caches so that the instructions will be correctly executed.
-	 */
-	flush_cache_sigtramp((unsigned long) frame->code);
+	setup_trampoline(frame->code);
+	setup_sigcontext(regs, &frame->scc, oldmask);
 
-	/*
-	 * Set up the "normal" sigcontext
-	 */
-	__put_user(regs->cp0_epc, &sc->sc_pc);
-	__put_user(regs->cp0_status, &sc->sc_status);	/* Status register */
-	for(i = 31;i >= 0;i--)
-		__put_user(regs->regs[i], &sc->sc_regs[i]);
-	save_fp_context(sc);
-	__put_user(regs->hi, &sc->sc_mdhi);
-	__put_user(regs->lo, &sc->sc_mdlo);
-	__put_user(regs->cp0_cause, &sc->sc_cause);
-	__put_user((regs->cp0_status & ST0_CU1) != 0, &sc->sc_ownedfp);
-	__put_user(oldmask, &sc->sc_sigset);
-	__put_user(0, &sc->__pad0[0]);
-	__put_user(0, &sc->__pad0[1]);
-	__put_user(0, &sc->__pad0[2]);
-
-	regs->regs[4] = signr;				/* Arguments for handler */
-	regs->regs[5] = 0;				/* For now. */
-	regs->regs[6] = (long) frame;			/* Pointer to sigcontext */
-	regs->regs[29] = (unsigned long) frame;		/* Stack pointer */
-	regs->regs[31] = (unsigned long) frame->code;	/* Return address */
-	regs->cp0_epc = (unsigned long) sa->sa_handler;	/* "return" to the first handler */
-	regs->regs[25] = regs->cp0_epc;			/* PIC shit... */
-	return;
+	regs->regs[4] = signr;				/* arguments */
+        regs->regs[5] = 0;                              /* should be cause  */
+        regs->regs[6] = (long) frame;                   /* ptr to sigcontext */
+        regs->regs[29] = (unsigned long) frame;         /* Stack pointer */
+        regs->regs[31] = (unsigned long) frame->code;   /* Return address */
+        regs->cp0_epc = (unsigned long) ka->sa.sa_handler; /* handler address */
+        regs->regs[25] = regs->cp0_epc;                 /* PIC shit... */
+
+#if DEBUG_SIG
+	printk("SIG deliver (%s:%d): sp=0x%p pc=0x%p ra=0x%p\n",
+	       current->comm, current->pid, frame, regs->cp0_epc, frame->code);
+#endif
+        return;
 
 segv_and_exit:
 	lock_kernel();
@@ -220,96 +339,127 @@
 	unlock_kernel();
 }
 
-static inline void handle_signal(unsigned long signr, struct sigaction *sa,
-	unsigned long oldmask, struct pt_regs * regs)
+static void inline
+setup_rt_frame(struct k_sigaction * ka, struct pt_regs *regs,
+               int signr, sigset_t *oldmask, siginfo_t *info)
 {
-	setup_frame(sa, regs, signr, oldmask);
+	printk("Aiee: setup_tr_frame wants to be written");
+}
 
-	if (sa->sa_flags & SA_ONESHOT)
-		sa->sa_handler = NULL;
-	if (!(sa->sa_flags & SA_NOMASK)) {
+/* ------------------------------------------------------------------------- */
+
+static inline void handle_signal(unsigned long sig, struct k_sigaction *ka,
+	siginfo_t *info, sigset_t *oldset, struct pt_regs * regs)
+{
+	if (ka->sa.sa_flags & SA_SIGINFO)
+		setup_rt_frame(ka, regs, sig, oldset, info);
+	else
+		setup_frame(ka, regs, sig, oldset);
+
+	if (ka->sa.sa_flags & SA_ONESHOT)
+		ka->sa.sa_handler = SIG_DFL;
+	if (!(ka->sa.sa_flags & SA_NODEFER)) {
 		spin_lock_irq(&current->sigmask_lock);
-		current->blocked |= (sa->sa_mask | _S(signr)) & _BLOCKABLE;
+		sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+		sigaddset(&current->blocked,sig);
+		recalc_sigpending(current);
 		spin_unlock_irq(&current->sigmask_lock);
 	}
 }
 
-static inline void syscall_restart(unsigned long r0, unsigned long or2,
-				   unsigned long or7, struct pt_regs *regs,
-				   struct sigaction *sa)
+static inline void syscall_restart(struct pt_regs *regs, struct k_sigaction *ka)
 {
-	switch(r0) {
+	switch(regs->regs[0]) {
 	case ERESTARTNOHAND:
-	no_system_call_restart:
-		regs->regs[0] = regs->regs[2] = EINTR;
+		regs->regs[2] = EINTR;
 		break;
 	case ERESTARTSYS:
-		if(!(sa->sa_flags & SA_RESTART))
-			goto no_system_call_restart;
+		if(!(ka->sa.sa_flags & SA_RESTART)) {
+			regs->regs[2] = EINTR;
+			break;
+		}
 	/* fallthrough */
-	case ERESTARTNOINTR:
-		regs->regs[0] = regs->regs[2] = or2;
-		regs->regs[7] = or7;
+	case ERESTARTNOINTR:		/* Userland will reload $v0.  */
 		regs->cp0_epc -= 8;
 	}
+
+	regs->regs[0] = 0;		/* Don't deal with this again.  */
 }
 
-extern int do_irix_signal(unsigned long oldmask, struct pt_regs *regs);
+extern int do_irix_signal(sigset_t *oldset, struct pt_regs *regs);
 
-/*
- * Note that 'init' is a special process: it doesn't get signals it doesn't
- * want to handle. Thus you cannot kill init even with a SIGKILL even by
- * mistake.
- *
- * Note that we go through the signals twice: once to check the signals that
- * the kernel can handle, and then we build all the user-level signal handling
- * stack-frames in one go after that.
- */
-asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs)
+asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs)
 {
-	unsigned long mask = ~current->blocked;
-	unsigned long signr, r0 = regs->regs[0];
-	unsigned long r7 = regs->orig_reg7;
-	struct sigaction * sa;
+	struct k_sigaction *ka;
+	siginfo_t info;
 
 #ifdef CONFIG_BINFMT_IRIX
-	if(current->personality != PER_LINUX)
-		return do_irix_signal(oldmask, regs);
+	if (current->personality != PER_LINUX)           /* XXX */
+		return do_irix_signal(oldset, regs);
 #endif
-	while ((signr = current->signal & mask)) {
-		signr = ffz(~signr);
-		clear_bit(signr, &current->signal);
-		sa = current->sig->action + signr;
-		signr++;
+
+	if (!oldset)
+		oldset = &current->blocked;
+
+	for (;;) {
+		unsigned long signr;
+
+		spin_lock_irq(&current->sigmask_lock);
+		signr = dequeue_signal(&current->blocked, &info);
+		spin_unlock_irq(&current->sigmask_lock);
+
+		if (!signr)
+			break;
+
 		if ((current->flags & PF_PTRACED) && signr != SIGKILL) {
+			/* Let the debugger run.  */
 			current->exit_code = signr;
 			current->state = TASK_STOPPED;
 			notify_parent(current, SIGCHLD);
 			schedule();
+
+			/* We're back.  Did the debugger cancel the sig?  */
 			if (!(signr = current->exit_code))
 				continue;
 			current->exit_code = 0;
+
+			/* The debugger continued.  Ignore SIGSTOP.  */
 			if (signr == SIGSTOP)
 				continue;
-			if (_S(signr) & current->blocked) {
-				spin_lock_irq(&current->sigmask_lock);
-				current->signal |= _S(signr);
-				spin_unlock_irq(&current->sigmask_lock);
+
+			/* Update the siginfo structure.  Is this good?  */
+			if (signr != info.si_signo) {
+				info.si_signo = signr;
+				info.si_errno = 0;
+				info.si_code = SI_USER;
+				info.si_pid = current->p_pptr->pid;
+				info.si_uid = current->p_pptr->uid;
+			}
+
+			/* If the (new) signal is now blocked, requeue it.  */
+			if (sigismember(&current->blocked, signr)) {
+				send_sig_info(signr, &info, current);
 				continue;
 			}
-			sa = current->sig->action + signr - 1;
 		}
-		if (sa->sa_handler == SIG_IGN) {
+
+		ka = &current->sig->action[signr-1];
+		if (ka->sa.sa_handler == SIG_IGN) {
 			if (signr != SIGCHLD)
 				continue;
-			/* check for SIGCHLD: it's special */
-			while (sys_wait4(-1,NULL,WNOHANG, NULL) > 0)
+			/* Check for SIGCHLD: it's special.  */
+			while (sys_wait4(-1, NULL, WNOHANG, NULL) > 0)
 				/* nothing */;
 			continue;
 		}
-		if (sa->sa_handler == SIG_DFL) {
+
+		if (ka->sa.sa_handler == SIG_DFL) {
+			int exit_code = signr;
+
+			/* Init gets no signals it doesn't want.  */
 			if (current->pid == 1)
 				continue;
+
 			switch (signr) {
 			case SIGCONT: case SIGCHLD: case SIGWINCH:
 				continue;
@@ -317,72 +467,55 @@
 			case SIGTSTP: case SIGTTIN: case SIGTTOU:
 				if (is_orphaned_pgrp(current->pgrp))
 					continue;
+				/* FALLTHRU */
+
 			case SIGSTOP:
-				if (current->flags & PF_PTRACED)
-					continue;
 				current->state = TASK_STOPPED;
 				current->exit_code = signr;
-				if (!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags & 
-						SA_NOCLDSTOP))
+				if (!(current->p_pptr->sig->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDSTOP))
 					notify_parent(current, SIGCHLD);
 				schedule();
 				continue;
 
 			case SIGQUIT: case SIGILL: case SIGTRAP:
 			case SIGABRT: case SIGFPE: case SIGSEGV:
-			case SIGBUS:
 				lock_kernel();
-				if (current->binfmt && current->binfmt->core_dump) {
-					if (current->binfmt->core_dump(signr, regs))
-						signr |= 0x80;
-				}
+				if (current->binfmt
+				    && current->binfmt->core_dump
+				    && current->binfmt->core_dump(signr, regs))
+					exit_code |= 0x80;
 				unlock_kernel();
-				/* fall through */
-			default:
-				spin_lock_irq(&current->sigmask_lock);
-				current->signal |= _S(signr & 0x7f);
-				spin_unlock_irq(&current->sigmask_lock);
+				/* FALLTHRU */
 
+			default:
+				lock_kernel();
+				sigaddset(&current->signal, signr);
 				current->flags |= PF_SIGNALED;
-
-				lock_kernel(); /* 8-( */
-				do_exit(signr);
-				unlock_kernel();
+				do_exit(exit_code);
+				/* NOTREACHED */
 			}
 		}
-		/*
-		 * OK, we're invoking a handler
-		 */
-		if(r0)
-			syscall_restart(r0, regs->orig_reg2,
-					r7, regs, sa);
-		handle_signal(signr, sa, oldmask, regs);
+
+		if (regs->regs[0])
+			syscall_restart(regs, ka);
+		/* Whee!  Actually deliver the signal.  */
+		handle_signal(signr, ka, &info, oldset, regs);
 		return 1;
 	}
+
 	/*
 	 * Who's code doesn't conform to the restartable syscall convention
 	 * dies here!!!  The li instruction, a single machine instruction,
 	 * must directly be followed by the syscall instruction.
 	 */
-	if (r0 &&
-	    (regs->regs[2] == ERESTARTNOHAND ||
-	     regs->regs[2] == ERESTARTSYS ||
-	     regs->regs[2] == ERESTARTNOINTR)) {
-		regs->regs[0] = regs->regs[2] = regs->orig_reg2;
-		regs->regs[7] = r7;
-		regs->cp0_epc -= 8;
+	if (regs->regs[0]) {
+		if (regs->regs[2] == ERESTARTNOHAND ||
+		    regs->regs[2] == ERESTARTSYS ||
+		    regs->regs[2] == ERESTARTNOINTR) {
+			regs->cp0_epc -= 8;
+		}
 	}
 	return 0;
-}
-
-/*
- * The signal(2) syscall is no longer available in the kernel
- * because GNU libc doesn't use it.  Maybe I'll add it back to the
- * kernel for the binary compatibility stuff.
- */
-asmlinkage unsigned long sys_signal(int signum, __sighandler_t handler)
-{
-	return -ENOSYS;
 }
 
 /*

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov