From: Roland McGrath There is really no point in each task_struct having its own waitchld_exit. In the only use of it, the waitchld_exit of each thread in a group gets woken up at the same time. So, there might as well just be one wait queue for the whole thread group. This patch does that by moving the field from task_struct to signal_struct. It should have no effect on the behavior, but saves a little work and a little storage in the multithreaded case. Signed-off-by: Roland McGrath Signed-off-by: Andrew Morton --- 25-akpm/arch/mips/kernel/irixsig.c | 4 ++-- 25-akpm/include/linux/init_task.h | 2 +- 25-akpm/include/linux/sched.h | 3 ++- 25-akpm/kernel/exit.c | 4 ++-- 25-akpm/kernel/fork.c | 2 +- 25-akpm/kernel/signal.c | 22 +++------------------- 25-akpm/security/selinux/hooks.c | 2 +- 7 files changed, 12 insertions(+), 27 deletions(-) diff -puN arch/mips/kernel/irixsig.c~move-waitchld_exit-from-task_struct-to-signal_struct arch/mips/kernel/irixsig.c --- 25/arch/mips/kernel/irixsig.c~move-waitchld_exit-from-task_struct-to-signal_struct 2004-12-06 13:55:37.494774344 -0800 +++ 25-akpm/arch/mips/kernel/irixsig.c 2004-12-06 13:55:37.537767808 -0800 @@ -583,7 +583,7 @@ asmlinkage int irix_waitsys(int type, in retval = -EINVAL; goto out; } - add_wait_queue(¤t->wait_chldexit, &wait); + add_wait_queue(¤t->signal->wait_chldexit, &wait); repeat: flag = 0; current->state = TASK_INTERRUPTIBLE; @@ -672,7 +672,7 @@ repeat: retval = -ECHILD; end_waitsys: current->state = TASK_RUNNING; - remove_wait_queue(¤t->wait_chldexit, &wait); + remove_wait_queue(¤t->signal->wait_chldexit, &wait); out: return retval; diff -puN include/linux/init_task.h~move-waitchld_exit-from-task_struct-to-signal_struct include/linux/init_task.h --- 25/include/linux/init_task.h~move-waitchld_exit-from-task_struct-to-signal_struct 2004-12-06 13:55:37.495774192 -0800 +++ 25-akpm/include/linux/init_task.h 2004-12-06 13:55:37.536767960 -0800 @@ -46,6 +46,7 @@ #define INIT_SIGNALS(sig) { \ .count = ATOMIC_INIT(1), \ + .wait_chldexit = __WAIT_QUEUE_HEAD_INITIALIZER(sig.wait_chldexit),\ .shared_pending = { \ .list = LIST_HEAD_INIT(sig.shared_pending.list), \ .signal = {{0}}}, \ @@ -88,7 +89,6 @@ extern struct group_info init_groups; .children = LIST_HEAD_INIT(tsk.children), \ .sibling = LIST_HEAD_INIT(tsk.sibling), \ .group_leader = &tsk, \ - .wait_chldexit = __WAIT_QUEUE_HEAD_INITIALIZER(tsk.wait_chldexit),\ .real_timer = { \ .function = it_real_fn \ }, \ diff -puN include/linux/sched.h~move-waitchld_exit-from-task_struct-to-signal_struct include/linux/sched.h --- 25/include/linux/sched.h~move-waitchld_exit-from-task_struct-to-signal_struct 2004-12-06 13:55:37.497773888 -0800 +++ 25-akpm/include/linux/sched.h 2004-12-06 13:55:37.536767960 -0800 @@ -275,6 +275,8 @@ struct signal_struct { atomic_t count; atomic_t live; + wait_queue_head_t wait_chldexit; /* for wait4() */ + /* current thread group signal load-balancing target: */ task_t *curr_target; @@ -587,7 +589,6 @@ struct task_struct { /* PID/PID hash table linkage. */ struct pid pids[PIDTYPE_MAX]; - wait_queue_head_t wait_chldexit; /* for wait4() */ struct completion *vfork_done; /* for vfork() */ int __user *set_child_tid; /* CLONE_CHILD_SETTID */ int __user *clear_child_tid; /* CLONE_CHILD_CLEARTID */ diff -puN kernel/exit.c~move-waitchld_exit-from-task_struct-to-signal_struct kernel/exit.c --- 25/kernel/exit.c~move-waitchld_exit-from-task_struct-to-signal_struct 2004-12-06 13:55:37.499773584 -0800 +++ 25-akpm/kernel/exit.c 2004-12-06 13:55:37.530768872 -0800 @@ -1320,7 +1320,7 @@ static long do_wait(pid_t pid, int optio struct task_struct *tsk; int flag, retval; - add_wait_queue(¤t->wait_chldexit,&wait); + add_wait_queue(¤t->signal->wait_chldexit,&wait); repeat: /* * We will set this flag if we see any child that might later @@ -1434,7 +1434,7 @@ check_continued: retval = -ECHILD; end: current->state = TASK_RUNNING; - remove_wait_queue(¤t->wait_chldexit,&wait); + remove_wait_queue(¤t->signal->wait_chldexit,&wait); if (infop) { if (retval > 0) retval = 0; diff -puN kernel/fork.c~move-waitchld_exit-from-task_struct-to-signal_struct kernel/fork.c --- 25/kernel/fork.c~move-waitchld_exit-from-task_struct-to-signal_struct 2004-12-06 13:55:37.501773280 -0800 +++ 25-akpm/kernel/fork.c 2004-12-06 13:56:06.328390968 -0800 @@ -733,6 +733,7 @@ static inline int copy_signal(unsigned l return -ENOMEM; atomic_set(&sig->count, 1); atomic_set(&sig->live, 1); + init_waitqueue_head(&sig->wait_chldexit); sig->flags = 0; sig->group_exit_code = 0; sig->group_exit_task = NULL; @@ -860,7 +861,6 @@ static task_t *copy_process(unsigned lon INIT_LIST_HEAD(&p->children); INIT_LIST_HEAD(&p->sibling); - init_waitqueue_head(&p->wait_chldexit); p->vfork_done = NULL; spin_lock_init(&p->alloc_lock); spin_lock_init(&p->proc_lock); diff -puN kernel/signal.c~move-waitchld_exit-from-task_struct-to-signal_struct kernel/signal.c --- 25/kernel/signal.c~move-waitchld_exit-from-task_struct-to-signal_struct 2004-12-06 13:55:37.503772976 -0800 +++ 25-akpm/kernel/signal.c 2004-12-06 13:55:37.532768568 -0800 @@ -1437,28 +1437,12 @@ out: } /* - * Joy. Or not. Pthread wants us to wake up every thread - * in our parent group. + * Wake up any threads in the parent blocked in wait* syscalls. */ -static void __wake_up_parent(struct task_struct *p, +static inline void __wake_up_parent(struct task_struct *p, struct task_struct *parent) { - struct task_struct *tsk = parent; - - /* - * Fortunately this is not necessary for thread groups: - */ - if (p->tgid == tsk->tgid) { - wake_up_interruptible_sync(&tsk->wait_chldexit); - return; - } - - do { - wake_up_interruptible_sync(&tsk->wait_chldexit); - tsk = next_thread(tsk); - if (tsk->signal != parent->signal) - BUG(); - } while (tsk != parent); + wake_up_interruptible_sync(&parent->signal->wait_chldexit); } /* diff -puN security/selinux/hooks.c~move-waitchld_exit-from-task_struct-to-signal_struct security/selinux/hooks.c --- 25/security/selinux/hooks.c~move-waitchld_exit-from-task_struct-to-signal_struct 2004-12-06 13:55:37.522770088 -0800 +++ 25-akpm/security/selinux/hooks.c 2004-12-06 13:55:37.528769176 -0800 @@ -1914,7 +1914,7 @@ static void selinux_bprm_apply_creds(str /* Wake up the parent if it is waiting so that it can recheck wait permission to the new task SID. */ - wake_up_interruptible(¤t->parent->wait_chldexit); + wake_up_interruptible(¤t->parent->signal->wait_chldexit); lock_out: task_lock(current); _