patch-2.1.36 linux/arch/i386/kernel/signal.c

Next file: linux/arch/i386/kernel/smp.c
Previous file: linux/arch/i386/kernel/ptrace.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.1.35/linux/arch/i386/kernel/signal.c linux/arch/i386/kernel/signal.c
@@ -23,7 +23,9 @@
 
 #define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))
 
-asmlinkage int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options);
+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);
 
 /*
@@ -31,24 +33,21 @@
  */
 asmlinkage int sys_sigsuspend(int restart, unsigned long oldmask, unsigned long set)
 {
+	struct pt_regs * regs = (struct pt_regs *) &restart;
 	unsigned long mask;
-	struct pt_regs * regs;
-	int res = -EINTR;
 
-	lock_kernel();
-	regs = (struct pt_regs *) &restart;
+	spin_lock_irq(&current->sigmask_lock);
 	mask = current->blocked;
 	current->blocked = set & _BLOCKABLE;
+	spin_unlock_irq(&current->sigmask_lock);
+
 	regs->eax = -EINTR;
 	while (1) {
 		current->state = TASK_INTERRUPTIBLE;
 		schedule();
-		if (do_signal(mask,regs))
-			goto out;
+		if (do_signal(mask, regs))
+			return -EINTR;
 	}
-out:
-	unlock_kernel();
-	return res;
 }
 
 static inline void restore_i387_hard(struct _fpstate *buf)
@@ -108,9 +107,7 @@
 __asm__("mov %w0,%%" #seg: :"r" (tmp)); }
 	struct sigcontext * context;
 	struct pt_regs * regs;
-	int res;
 
-	lock_kernel();
 	regs = (struct pt_regs *) &__unused;
 	context = (struct sigcontext *) regs->esp;
 	if (verify_area(VERIFY_READ, context, sizeof(*context)))
@@ -136,11 +133,12 @@
 			goto badframe;
 		restore_i387(buf);
 	}
-	res = context->eax;
-	unlock_kernel();
-	return res;
+	return context->eax;
+
 badframe:
+	lock_kernel();
 	do_exit(SIGSEGV);
+	unlock_kernel();
 }
 
 static inline struct _fpstate * save_i387_hard(struct _fpstate * buf)
@@ -194,7 +192,7 @@
 		frame = (unsigned long *) sa->sa_restorer;
 	frame -= 64;
 	if (!access_ok(VERIFY_WRITE,frame,64*4))
-		do_exit(SIGSEGV);
+		goto segv_and_exit;
 
 /* set up the "normal" stack seen by the signal handler (iBCS2) */
 #define __CODE ((unsigned long)(frame+24))
@@ -206,7 +204,7 @@
        We use __put_user() here because the access_ok() call was already
        done earlier. */  
 	if (__put_user(__CODE,frame))
-		do_exit(SIGSEGV);
+		goto segv_and_exit;
 	if (current->exec_domain && current->exec_domain->signal_invmap)
 		__put_user(current->exec_domain->signal_invmap[signr], frame+1);
 	else
@@ -259,6 +257,12 @@
 		regs->xcs = USER_CS;
 	}
 	regs->eflags &= ~TF_MASK;
+	return;
+
+segv_and_exit:
+	lock_kernel();
+	do_exit(SIGSEGV);
+	unlock_kernel();
 }
 
 /*
@@ -292,8 +296,11 @@
 
 	if (sa->sa_flags & SA_ONESHOT)
 		sa->sa_handler = NULL;
-	if (!(sa->sa_flags & SA_NOMASK))
+	if (!(sa->sa_flags & SA_NOMASK)) {
+		spin_lock_irq(&current->sigmask_lock);
 		current->blocked |= (sa->sa_mask | _S(signr)) & _BLOCKABLE;
+		spin_unlock_irq(&current->sigmask_lock);
+	}
 }
 
 /*
@@ -310,9 +317,7 @@
 	unsigned long mask;
 	unsigned long signr;
 	struct sigaction * sa;
-	int res;
 
-	lock_kernel();
 	mask = ~current->blocked;
 	while ((signr = current->signal & mask)) {
 		/*
@@ -322,6 +327,9 @@
 		 */
 		struct task_struct *t=current;
 		__asm__("bsf %3,%1\n\t"
+#ifdef __SMP__
+			"lock ; "
+#endif
 			"btrl %1,%0"
 			:"=m" (t->signal),"=r" (signr)
 			:"0" (t->signal), "1" (signr));
@@ -338,7 +346,9 @@
 			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);
 				continue;
 			}
 			sa = current->sig->action + signr - 1;
@@ -347,7 +357,7 @@
 			if (signr != SIGCHLD)
 				continue;
 			/* check for SIGCHLD: it's special */
-			while (sys_waitpid(-1,NULL,WNOHANG) > 0)
+			while (sys_wait4(-1,NULL,WNOHANG, NULL) > 0)
 				/* nothing */;
 			continue;
 		}
@@ -380,14 +390,19 @@
 				}
 				/* fall through */
 			default:
+				spin_lock_irq(&current->sigmask_lock);
 				current->signal |= _S(signr & 0x7f);
+				spin_unlock_irq(&current->sigmask_lock);
+
 				current->flags |= PF_SIGNALED;
+
+				lock_kernel(); /* 8-( */
 				do_exit(signr);
+				unlock_kernel();
 			}
 		}
 		handle_signal(signr, sa, oldmask, regs);
-		res = 1;
-		goto out;
+		return 1;
 	}
 
 	/* Did we come from a system call? */
@@ -400,8 +415,5 @@
 			regs->eip -= 2;
 		}
 	}
-	res = 0;
-out:
-	unlock_kernel();
-	return res;
+	return 0;
 }

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