summaryrefslogtreecommitdiff
path: root/kernel/exit.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/exit.c')
-rw-r--r--kernel/exit.c66
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(&current->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) {