patch-2.4.0-test8 linux/kernel/exit.c

Next file: linux/kernel/fork.c
Previous file: linux/ipc/shm.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.4.0-test7/linux/kernel/exit.c linux/kernel/exit.c
@@ -144,17 +144,29 @@
 	return retval;
 }
 
+/*
+ * When we die, we re-parent all our children.
+ * Try to give them to another thread in our process
+ * group, and if no such member exists, give it to
+ * the global child reaper process (ie "init")
+ */
 static inline void forget_original_parent(struct task_struct * father)
 {
-	struct task_struct * p;
+	struct task_struct * p, *reaper;
 
 	read_lock(&tasklist_lock);
+
+	/* Next in our thread group */
+	reaper = next_thread(father);
+	if (reaper == father)
+		reaper = child_reaper;
+
 	for_each_task(p) {
 		if (p->p_opptr == father) {
 			/* We dont want people slaying init */
 			p->exit_signal = SIGCHLD;
 			p->self_exec_id++;
-			p->p_opptr = child_reaper; /* init */
+			p->p_opptr = reaper;
 			if (p->pdeath_signal) send_sig(p->pdeath_signal, p, 0);
 		}
 	}
@@ -255,26 +267,6 @@
 	__exit_fs(tsk);
 }
 
-static inline void __exit_sighand(struct task_struct *tsk)
-{
-	struct signal_struct * sig = tsk->sig;
-
-	if (sig) {
-		spin_lock_irq(&tsk->sigmask_lock);
-		tsk->sig = NULL;
-		spin_unlock_irq(&tsk->sigmask_lock);
-		if (atomic_dec_and_test(&sig->count))
-			kmem_cache_free(sigact_cachep, sig);
-	}
-
-	flush_signals(tsk);
-}
-
-void exit_sighand(struct task_struct *tsk)
-{
-	__exit_sighand(tsk);
-}
-
 /*
  * We can use these to temporarily drop into
  * "lazy TLB" mode and back.
@@ -378,7 +370,6 @@
 	    && !capable(CAP_KILL))
 		current->exit_signal = SIGCHLD;
 
-	notify_parent(current, current->exit_signal);
 
 	/*
 	 * This loop does two things:
@@ -390,6 +381,7 @@
 	 */
 
 	write_lock_irq(&tasklist_lock);
+	do_notify_parent(current, current->exit_signal);
 	while (current->p_cptr != NULL) {
 		p = current->p_cptr;
 		current->p_cptr = p->p_osptr;
@@ -402,7 +394,7 @@
 			p->p_osptr->p_ysptr = p;
 		p->p_pptr->p_cptr = p;
 		if (p->state == TASK_ZOMBIE)
-			notify_parent(p, p->exit_signal);
+			do_notify_parent(p, p->exit_signal);
 		/*
 		 * process group orphan check
 		 * Case ii: Our child is in a different pgrp
@@ -449,7 +441,7 @@
 	__exit_mm(tsk);
 	__exit_files(tsk);
 	__exit_fs(tsk);
-	__exit_sighand(tsk);
+	exit_sighand(tsk);
 	exit_thread();
 	tsk->state = TASK_ZOMBIE;
 	tsk->exit_code = code;
@@ -483,9 +475,9 @@
 {
 	int flag, retval;
 	DECLARE_WAITQUEUE(wait, current);
-	struct task_struct *p;
+	struct task_struct *tsk;
 
-	if (options & ~(WNOHANG|WUNTRACED|__WCLONE|__WALL))
+	if (options & ~(WNOHANG|WUNTRACED|__WNOTHREAD|__WCLONE|__WALL))
 		return -EINVAL;
 
 	add_wait_queue(&current->wait_chldexit,&wait);
@@ -493,27 +485,30 @@
 	flag = 0;
 	current->state = TASK_INTERRUPTIBLE;
 	read_lock(&tasklist_lock);
- 	for (p = current->p_cptr ; p ; p = p->p_osptr) {
-		if (pid>0) {
-			if (p->pid != pid)
-				continue;
-		} else if (!pid) {
-			if (p->pgrp != current->pgrp)
-				continue;
-		} else if (pid != -1) {
-			if (p->pgrp != -pid)
+	tsk = current;
+	do {
+		struct task_struct *p;
+	 	for (p = tsk->p_cptr ; p ; p = p->p_osptr) {
+			if (pid>0) {
+				if (p->pid != pid)
+					continue;
+			} else if (!pid) {
+				if (p->pgrp != current->pgrp)
+					continue;
+			} else if (pid != -1) {
+				if (p->pgrp != -pid)
+					continue;
+			}
+			/* Wait for all children (clone and not) if __WALL is set;
+			 * otherwise, wait for clone children *only* if __WCLONE is
+			 * set; otherwise, wait for non-clone children *only*.  (Note:
+			 * A "clone" child here is one that reports to its parent
+			 * using a signal other than SIGCHLD.) */
+			if (((p->exit_signal != SIGCHLD) ^ ((options & __WCLONE) != 0))
+			    && !(options & __WALL))
 				continue;
-		}
-		/* Wait for all children (clone and not) if __WALL is set;
-		 * otherwise, wait for clone children *only* if __WCLONE is
-		 * set; otherwise, wait for non-clone children *only*.  (Note:
-		 * A "clone" child here is one that reports to its parent
-		 * using a signal other than SIGCHLD.) */
-		if (((p->exit_signal != SIGCHLD) ^ ((options & __WCLONE) != 0))
-		    && !(options & __WALL))
-			continue;
-		flag = 1;
-		switch (p->state) {
+			flag = 1;
+			switch (p->state) {
 			case TASK_STOPPED:
 				if (!p->exit_code)
 					continue;
@@ -543,15 +538,19 @@
 					REMOVE_LINKS(p);
 					p->p_pptr = p->p_opptr;
 					SET_LINKS(p);
+					do_notify_parent(p, SIGCHLD);
 					write_unlock_irq(&tasklist_lock);
-					notify_parent(p, SIGCHLD);
 				} else
 					release(p);
 				goto end_wait4;
 			default:
 				continue;
+			}
 		}
-	}
+		if (options & __WNOTHREAD)
+			break;
+		tsk = next_thread(tsk);
+	} while (tsk != current);
 	read_unlock(&tasklist_lock);
 	if (flag) {
 		retval = 0;

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