patch-2.2.14 linux/kernel/exit.c

Next file: linux/kernel/kmod.c
Previous file: linux/kernel/dma.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.2.13/linux/kernel/exit.c linux/kernel/exit.c
@@ -232,18 +232,17 @@
 static inline void __exit_sighand(struct task_struct *tsk)
 {
 	struct signal_struct * sig = tsk->sig;
+	unsigned long flags;
 
+	spin_lock_irqsave(&tsk->sigmask_lock, flags);
 	if (sig) {
-		unsigned long flags;
-
-		spin_lock_irqsave(&tsk->sigmask_lock, flags);
 		tsk->sig = NULL;
-		spin_unlock_irqrestore(&tsk->sigmask_lock, flags);
 		if (atomic_dec_and_test(&sig->count))
 			kfree(sig);
 	}
 
 	flush_signals(tsk);
+	spin_unlock_irqrestore(&tsk->sigmask_lock, flags);
 }
 
 void exit_sighand(struct task_struct *tsk)
@@ -444,6 +443,13 @@
 	add_wait_queue(&current->wait_chldexit,&wait);
 repeat:
 	flag = 0;
+
+	/* The interruptible state must be set before looking at the
+	   children. This because we want to catch any racy exit from
+	   the children as do_exit() may run under us. The following
+	   read_lock will enforce SMP ordering at the CPU level. */
+	current->state = TASK_INTERRUPTIBLE;
+
 	read_lock(&tasklist_lock);
  	for (p = current->p_cptr ; p ; p = p->p_osptr) {
 		if (pid>0) {
@@ -510,13 +516,13 @@
 		retval = -ERESTARTSYS;
 		if (signal_pending(current))
 			goto end_wait4;
-		current->state=TASK_INTERRUPTIBLE;
 		schedule();
 		goto repeat;
 	}
 	retval = -ECHILD;
 end_wait4:
 	remove_wait_queue(&current->wait_chldexit,&wait);
+	current->state = TASK_RUNNING;
 	return retval;
 }
 

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)