Commit 10d6e374 authored by Roland McGrath's avatar Roland McGrath Committed by Linus Torvalds

[PATCH] move waitchld_exit from task_struct to signal_struct

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: default avatarRoland McGrath <roland@redhat.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 66519f54
...@@ -583,7 +583,7 @@ asmlinkage int irix_waitsys(int type, int pid, struct irix5_siginfo *info, ...@@ -583,7 +583,7 @@ asmlinkage int irix_waitsys(int type, int pid, struct irix5_siginfo *info,
retval = -EINVAL; retval = -EINVAL;
goto out; goto out;
} }
add_wait_queue(&current->wait_chldexit, &wait); add_wait_queue(&current->signal->wait_chldexit, &wait);
repeat: repeat:
flag = 0; flag = 0;
current->state = TASK_INTERRUPTIBLE; current->state = TASK_INTERRUPTIBLE;
...@@ -672,7 +672,7 @@ asmlinkage int irix_waitsys(int type, int pid, struct irix5_siginfo *info, ...@@ -672,7 +672,7 @@ asmlinkage int irix_waitsys(int type, int pid, struct irix5_siginfo *info,
retval = -ECHILD; retval = -ECHILD;
end_waitsys: end_waitsys:
current->state = TASK_RUNNING; current->state = TASK_RUNNING;
remove_wait_queue(&current->wait_chldexit, &wait); remove_wait_queue(&current->signal->wait_chldexit, &wait);
out: out:
return retval; return retval;
......
...@@ -46,6 +46,7 @@ ...@@ -46,6 +46,7 @@
#define INIT_SIGNALS(sig) { \ #define INIT_SIGNALS(sig) { \
.count = ATOMIC_INIT(1), \ .count = ATOMIC_INIT(1), \
.wait_chldexit = __WAIT_QUEUE_HEAD_INITIALIZER(sig.wait_chldexit),\
.shared_pending = { \ .shared_pending = { \
.list = LIST_HEAD_INIT(sig.shared_pending.list), \ .list = LIST_HEAD_INIT(sig.shared_pending.list), \
.signal = {{0}}}, \ .signal = {{0}}}, \
...@@ -88,7 +89,6 @@ extern struct group_info init_groups; ...@@ -88,7 +89,6 @@ extern struct group_info init_groups;
.children = LIST_HEAD_INIT(tsk.children), \ .children = LIST_HEAD_INIT(tsk.children), \
.sibling = LIST_HEAD_INIT(tsk.sibling), \ .sibling = LIST_HEAD_INIT(tsk.sibling), \
.group_leader = &tsk, \ .group_leader = &tsk, \
.wait_chldexit = __WAIT_QUEUE_HEAD_INITIALIZER(tsk.wait_chldexit),\
.real_timer = { \ .real_timer = { \
.function = it_real_fn \ .function = it_real_fn \
}, \ }, \
......
...@@ -274,6 +274,8 @@ struct signal_struct { ...@@ -274,6 +274,8 @@ struct signal_struct {
atomic_t count; atomic_t count;
atomic_t live; atomic_t live;
wait_queue_head_t wait_chldexit; /* for wait4() */
/* current thread group signal load-balancing target: */ /* current thread group signal load-balancing target: */
task_t *curr_target; task_t *curr_target;
...@@ -586,7 +588,6 @@ struct task_struct { ...@@ -586,7 +588,6 @@ struct task_struct {
/* PID/PID hash table linkage. */ /* PID/PID hash table linkage. */
struct pid pids[PIDTYPE_MAX]; struct pid pids[PIDTYPE_MAX];
wait_queue_head_t wait_chldexit; /* for wait4() */
struct completion *vfork_done; /* for vfork() */ struct completion *vfork_done; /* for vfork() */
int __user *set_child_tid; /* CLONE_CHILD_SETTID */ int __user *set_child_tid; /* CLONE_CHILD_SETTID */
int __user *clear_child_tid; /* CLONE_CHILD_CLEARTID */ int __user *clear_child_tid; /* CLONE_CHILD_CLEARTID */
......
...@@ -1319,7 +1319,7 @@ static long do_wait(pid_t pid, int options, struct siginfo __user *infop, ...@@ -1319,7 +1319,7 @@ static long do_wait(pid_t pid, int options, struct siginfo __user *infop,
struct task_struct *tsk; struct task_struct *tsk;
int flag, retval; int flag, retval;
add_wait_queue(&current->wait_chldexit,&wait); add_wait_queue(&current->signal->wait_chldexit,&wait);
repeat: repeat:
/* /*
* We will set this flag if we see any child that might later * We will set this flag if we see any child that might later
...@@ -1433,7 +1433,7 @@ static long do_wait(pid_t pid, int options, struct siginfo __user *infop, ...@@ -1433,7 +1433,7 @@ static long do_wait(pid_t pid, int options, struct siginfo __user *infop,
retval = -ECHILD; retval = -ECHILD;
end: end:
current->state = TASK_RUNNING; current->state = TASK_RUNNING;
remove_wait_queue(&current->wait_chldexit,&wait); remove_wait_queue(&current->signal->wait_chldexit,&wait);
if (infop) { if (infop) {
if (retval > 0) if (retval > 0)
retval = 0; retval = 0;
......
...@@ -733,6 +733,7 @@ static inline int copy_signal(unsigned long clone_flags, struct task_struct * ts ...@@ -733,6 +733,7 @@ static inline int copy_signal(unsigned long clone_flags, struct task_struct * ts
return -ENOMEM; return -ENOMEM;
atomic_set(&sig->count, 1); atomic_set(&sig->count, 1);
atomic_set(&sig->live, 1); atomic_set(&sig->live, 1);
init_waitqueue_head(&sig->wait_chldexit);
sig->flags = 0; sig->flags = 0;
sig->group_exit_code = 0; sig->group_exit_code = 0;
sig->group_exit_task = NULL; sig->group_exit_task = NULL;
...@@ -860,7 +861,6 @@ static task_t *copy_process(unsigned long clone_flags, ...@@ -860,7 +861,6 @@ static task_t *copy_process(unsigned long clone_flags,
INIT_LIST_HEAD(&p->children); INIT_LIST_HEAD(&p->children);
INIT_LIST_HEAD(&p->sibling); INIT_LIST_HEAD(&p->sibling);
init_waitqueue_head(&p->wait_chldexit);
p->vfork_done = NULL; p->vfork_done = NULL;
spin_lock_init(&p->alloc_lock); spin_lock_init(&p->alloc_lock);
spin_lock_init(&p->proc_lock); spin_lock_init(&p->proc_lock);
......
...@@ -1437,28 +1437,12 @@ send_group_sigqueue(int sig, struct sigqueue *q, struct task_struct *p) ...@@ -1437,28 +1437,12 @@ send_group_sigqueue(int sig, struct sigqueue *q, struct task_struct *p)
} }
/* /*
* Joy. Or not. Pthread wants us to wake up every thread * Wake up any threads in the parent blocked in wait* syscalls.
* in our parent group.
*/ */
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 *parent)
{ {
struct task_struct *tsk = parent; wake_up_interruptible_sync(&parent->signal->wait_chldexit);
/*
* 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);
} }
/* /*
......
...@@ -1908,7 +1908,7 @@ static void selinux_bprm_apply_creds(struct linux_binprm *bprm, int unsafe) ...@@ -1908,7 +1908,7 @@ static void selinux_bprm_apply_creds(struct linux_binprm *bprm, int unsafe)
/* Wake up the parent if it is waiting so that it can /* Wake up the parent if it is waiting so that it can
recheck wait permission to the new task SID. */ recheck wait permission to the new task SID. */
wake_up_interruptible(&current->parent->wait_chldexit); wake_up_interruptible(&current->parent->signal->wait_chldexit);
lock_out: lock_out:
task_lock(current); task_lock(current);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment