diff options
Diffstat (limited to 'kernel/exit.c')
| -rw-r--r-- | kernel/exit.c | 66 |
1 files changed, 36 insertions, 30 deletions
diff --git a/kernel/exit.c b/kernel/exit.c index 115a7cd7b807..8ab794864afd 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -49,16 +49,14 @@ static struct dentry * __unhash_process(struct task_struct *p) return proc_dentry; } -static void release_task(struct task_struct * p) +void release_task(struct task_struct * p) { struct dentry *proc_dentry; if (p->state != TASK_ZOMBIE) BUG(); -#ifdef CONFIG_SMP if (p != current) wait_task_inactive(p); -#endif atomic_dec(&p->user->processes); security_ops->task_free_security(p); free_uid(p->user); @@ -71,19 +69,19 @@ static void release_task(struct task_struct * p) write_lock_irq(&tasklist_lock); __exit_sighand(p); proc_dentry = __unhash_process(p); + p->parent->cutime += p->utime + p->cutime; + p->parent->cstime += p->stime + p->cstime; + p->parent->cmin_flt += p->min_flt + p->cmin_flt; + p->parent->cmaj_flt += p->maj_flt + p->cmaj_flt; + p->parent->cnswap += p->nswap + p->cnswap; + sched_exit(p); write_unlock_irq(&tasklist_lock); + if (unlikely(proc_dentry != NULL)) { shrink_dcache_parent(proc_dentry); dput(proc_dentry); } - release_thread(p); - if (p != current) { - current->cmin_flt += p->min_flt + p->cmin_flt; - current->cmaj_flt += p->maj_flt + p->cmaj_flt; - current->cnswap += p->nswap + p->cnswap; - sched_exit(p); - } put_task_struct(p); } @@ -447,11 +445,7 @@ static inline void forget_original_parent(struct task_struct * father) struct task_struct *p, *reaper = father; struct list_head *_p; - if (father->exit_signal != -1) - reaper = prev_thread(reaper); - else - reaper = child_reaper; - + reaper = father->group_leader; if (reaper == father) reaper = child_reaper; @@ -681,21 +675,25 @@ asmlinkage long sys_exit(int error_code) */ asmlinkage long sys_exit_group(int error_code) { - struct signal_struct *sig = current->sig; + unsigned int exit_code = (error_code & 0xff) << 8; - spin_lock_irq(&sig->siglock); - if (sig->group_exit) { - spin_unlock_irq(&sig->siglock); + if (!list_empty(¤t->thread_group)) { + struct signal_struct *sig = current->sig; - /* another thread was faster: */ - do_exit(sig->group_exit_code); + spin_lock_irq(&sig->siglock); + if (sig->group_exit) { + spin_unlock_irq(&sig->siglock); + + /* another thread was faster: */ + do_exit(sig->group_exit_code); + } + sig->group_exit = 1; + sig->group_exit_code = exit_code; + __broadcast_thread_group(current, SIGKILL); + spin_unlock_irq(&sig->siglock); } - sig->group_exit = 1; - sig->group_exit_code = (error_code & 0xff) << 8; - __broadcast_thread_group(current, SIGKILL); - spin_unlock_irq(&sig->siglock); - do_exit(sig->group_exit_code); + do_exit(exit_code); } static int eligible_child(pid_t pid, int options, task_t *p) @@ -731,7 +729,7 @@ static int eligible_child(pid_t pid, int options, task_t *p) * in a non-empty thread group: */ if (current->tgid != p->tgid && delay_group_leader(p)) - return 0; + return 2; if (security_ops->task_wait(p)) return 0; @@ -757,11 +755,16 @@ repeat: do { struct task_struct *p; struct list_head *_p; + int ret; + list_for_each(_p,&tsk->children) { p = list_entry(_p,struct task_struct,sibling); - if (!eligible_child(pid, options, p)) + + ret = eligible_child(pid, options, p); + if (!ret) continue; flag = 1; + switch (p->state) { case TASK_STOPPED: if (!p->exit_code) @@ -784,8 +787,11 @@ repeat: } goto end_wait4; case TASK_ZOMBIE: - current->cutime += p->utime + p->cutime; - current->cstime += p->stime + p->cstime; + /* + * Eligible but we cannot release it yet: + */ + if (ret == 2) + continue; read_unlock(&tasklist_lock); retval = ru ? getrusage(p, RUSAGE_BOTH, ru) : 0; if (!retval && stat_addr) { |
