patch-2.0.1 linux/arch/alpha/kernel/signal.c

Next file: linux/arch/i386/kernel/ksyms.c
Previous file: linux/arch/alpha/kernel/process.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.0.0/linux/arch/alpha/kernel/signal.c linux/arch/alpha/kernel/signal.c
@@ -130,24 +130,28 @@
 /*
  * Set up a signal frame...
  */
-static void setup_frame(struct sigaction * sa, struct sigcontext_struct ** fp,
-			unsigned long pc, struct pt_regs * regs,
+static void setup_frame(struct sigaction * sa,
+			struct pt_regs * regs,
 			struct switch_stack * sw, int signr,
 			unsigned long oldmask)
 {
 	int i;
+	unsigned long oldsp;
 	struct sigcontext_struct * sc;
 
-	sc = *fp;
+	oldsp = rdusp();
+	sc = ((struct sigcontext_struct *) oldsp) - 1;
+
 	/* check here if we would need to switch stacks.. */
-	sc--;
 	if (verify_area(VERIFY_WRITE, sc, sizeof(*sc)))
 		do_exit(SIGSEGV);
 
+	wrusp((unsigned long) sc);
+
 	put_fs_quad(oldmask, &sc->sc_mask);
 	put_fs_quad(8, &sc->sc_ps);
-	put_fs_quad(pc, &sc->sc_pc);
-	put_fs_quad((unsigned long)*fp, sc->sc_regs+30);
+	put_fs_quad(regs->pc, &sc->sc_pc);
+	put_fs_quad(oldsp, sc->sc_regs+30);
 
 	put_fs_quad(regs->r0 , sc->sc_regs+0);
 	put_fs_quad(regs->r1 , sc->sc_regs+1);
@@ -193,14 +197,51 @@
 	 */
 	put_fs_quad(0x43ecf40047de0410, sc->sc_retcode+0);
 	put_fs_quad(0x0000000000000083, sc->sc_retcode+1);
+	imb();
+
+	/* "return" to the handler */
+	regs->r27 = regs->pc = (unsigned long) sa->sa_handler;
 	regs->r26 = (unsigned long) sc->sc_retcode;
 	regs->r16 = signr;		/* a0: signal number */
 	regs->r17 = 0;			/* a1: exception code; see gentrap.h */
 	regs->r18 = (unsigned long) sc;	/* a2: sigcontext pointer */
-	*fp = sc;
 }
 
 /*
+ * OK, we're invoking a handler
+ */
+static inline void handle_signal(unsigned long signr, struct sigaction *sa,
+	unsigned long oldmask, struct pt_regs * regs, struct switch_stack *sw)
+{
+	setup_frame(sa,regs,sw,signr,oldmask);
+
+	if (sa->sa_flags & SA_ONESHOT)
+		sa->sa_handler = NULL;
+	if (!(sa->sa_flags & SA_NOMASK))
+		current->blocked |= (sa->sa_mask | _S(signr)) & _BLOCKABLE;
+}
+
+static inline void syscall_restart(unsigned long r0, unsigned long r19,
+	struct pt_regs * regs, struct sigaction * sa)
+{
+	switch (regs->r0) {
+		case ERESTARTNOHAND:
+		no_system_call_restart:
+			regs->r0 = EINTR;
+			break;
+		case ERESTARTSYS:
+			if (!(sa->sa_flags & SA_RESTART))
+				goto no_system_call_restart;
+		/* fallthrough */
+		case ERESTARTNOINTR:
+			regs->r0 = r0;	/* reset v0 and a3 and replay syscall */
+			regs->r19 = r19;
+			regs->pc -= 4;
+	}
+}
+
+
+/*
  * 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.
@@ -219,9 +260,6 @@
 	unsigned long r0, unsigned long r19)
 {
 	unsigned long mask = ~current->blocked;
-	unsigned long handler_signal = 0;
-	struct sigcontext_struct *frame = NULL;
-	unsigned long pc = 0;
 	unsigned long signr, single_stepping;
 	struct sigaction * sa;
 
@@ -264,7 +302,10 @@
 			case SIGCONT: case SIGCHLD: case SIGWINCH:
 				continue;
 
-			case SIGSTOP: case SIGTSTP: case SIGTTIN: case SIGTTOU:
+			case SIGTSTP: case SIGTTIN: case SIGTTOU:
+				if (is_orphaned_pgrp(current->pgrp))
+					continue;
+			case SIGSTOP:
 				if (current->flags & PF_PTRACED)
 					continue;
 				current->state = TASK_STOPPED;
@@ -289,16 +330,13 @@
 				do_exit(signr);
 			}
 		}
-		/*
-		 * OK, we're invoking a handler
-		 */
-		if (r0) {
-			if (regs->r0 == ERESTARTNOHAND ||
-			   (regs->r0 == ERESTARTSYS && !(sa->sa_flags & SA_RESTART)))
-				regs->r0 = EINTR;
+		if (r0)
+			syscall_restart(r0, r19, regs, sa);
+		handle_signal(signr, sa, oldmask, regs, sw);
+		if (single_stepping) {
+			ptrace_set_bpt(current);	/* re-set breakpoint */
 		}
-		handler_signal |= 1 << (signr-1);
-		mask &= ~sa->sa_mask;
+		return 1;
 	}
 	if (r0 &&
 	    (regs->r0 == ERESTARTNOHAND ||
@@ -308,34 +346,8 @@
 		regs->r19 = r19;
 		regs->pc -= 4;
 	}
-	if (!handler_signal) {	/* no handler will be called - return 0 */
-		if (single_stepping) {
-			ptrace_set_bpt(current);	/* re-set breakpoint */
-		}
-		return 0;
-	}
-	pc = regs->pc;
-	frame = (struct sigcontext_struct *) rdusp();
-	signr = 1;
-	sa = current->sig->action;
-	for (mask = 1 ; mask ; sa++,signr++,mask += mask) {
-		if (mask > handler_signal)
-			break;
-		if (!(mask & handler_signal))
-			continue;
-		setup_frame(sa,&frame,pc,regs,sw,signr,oldmask);
-		pc = (unsigned long) sa->sa_handler;
-		regs->r27 = pc;
-		if (sa->sa_flags & SA_ONESHOT)
-			sa->sa_handler = NULL;
-		current->blocked |= sa->sa_mask;
-		oldmask |= sa->sa_mask;
-	}
-	imb();
-	wrusp((unsigned long) frame);
-	regs->pc = pc;			/* "return" to the first handler */
 	if (single_stepping) {
 		ptrace_set_bpt(current);	/* re-set breakpoint */
 	}
-	return 1;
+	return 0;
 }

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