diff options
| author | Greg Kroah-Hartman <greg@kroah.com> | 2004-10-18 18:03:51 -0700 |
|---|---|---|
| committer | Greg Kroah-Hartman <greg@kroah.com> | 2004-10-18 18:03:51 -0700 |
| commit | bffe01870598b7a0a77073e25ee94e026bc98e6b (patch) | |
| tree | f5f5b65fec1239b18a4c2634807ff5d7e5729de9 /fs/exec.c | |
| parent | 23aebb6f8755121394ef088d84a7fa483b444aa9 (diff) | |
| parent | a4946826c30c56a5830326552a395c5b6afc13ef (diff) | |
merge
Diffstat (limited to 'fs/exec.c')
| -rw-r--r-- | fs/exec.c | 122 |
1 files changed, 55 insertions, 67 deletions
diff --git a/fs/exec.c b/fs/exec.c index bdf32393b3c5..e715541b2db4 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -377,7 +377,7 @@ int setup_arg_pages(struct linux_binprm *bprm, int executable_stack) bprm->p = PAGE_SIZE * i - offset; /* Limit stack size to 1GB */ - stack_base = current->rlim[RLIMIT_STACK].rlim_max; + stack_base = current->signal->rlim[RLIMIT_STACK].rlim_max; if (stack_base > (1 << 30)) stack_base = 1 << 30; stack_base = PAGE_ALIGN(STACK_TOP - stack_base); @@ -564,7 +564,7 @@ static int exec_mmap(struct mm_struct *mm) */ static inline int de_thread(struct task_struct *tsk) { - struct signal_struct *newsig, *oldsig = tsk->signal; + struct signal_struct *sig = tsk->signal; struct sighand_struct *newsighand, *oldsighand = tsk->sighand; spinlock_t *lock = &oldsighand->siglock; int count; @@ -573,43 +573,16 @@ static inline int de_thread(struct task_struct *tsk) * If we don't share sighandlers, then we aren't sharing anything * and we can just re-use it all. */ - if (atomic_read(&oldsighand->count) <= 1) + if (atomic_read(&oldsighand->count) <= 1) { + BUG_ON(atomic_read(&sig->count) != 1); + exit_itimers(sig); return 0; + } newsighand = kmem_cache_alloc(sighand_cachep, GFP_KERNEL); if (!newsighand) return -ENOMEM; - spin_lock_init(&newsighand->siglock); - atomic_set(&newsighand->count, 1); - memcpy(newsighand->action, oldsighand->action, sizeof(newsighand->action)); - - /* - * See if we need to allocate a new signal structure - */ - newsig = NULL; - if (atomic_read(&oldsig->count) > 1) { - newsig = kmem_cache_alloc(signal_cachep, GFP_KERNEL); - if (!newsig) { - kmem_cache_free(sighand_cachep, newsighand); - return -ENOMEM; - } - atomic_set(&newsig->count, 1); - newsig->group_exit = 0; - newsig->group_exit_code = 0; - newsig->group_exit_task = NULL; - newsig->group_stop_count = 0; - newsig->curr_target = NULL; - init_sigpending(&newsig->shared_pending); - INIT_LIST_HEAD(&newsig->posix_timers); - - newsig->tty = oldsig->tty; - newsig->pgrp = oldsig->pgrp; - newsig->session = oldsig->session; - newsig->leader = oldsig->leader; - newsig->tty_old_pgrp = oldsig->tty_old_pgrp; - } - if (thread_group_empty(current)) goto no_thread_group; @@ -619,7 +592,7 @@ static inline int de_thread(struct task_struct *tsk) */ read_lock(&tasklist_lock); spin_lock_irq(lock); - if (oldsig->group_exit) { + if (sig->group_exit) { /* * Another group action in progress, just * return so that the signal is processed. @@ -627,11 +600,9 @@ static inline int de_thread(struct task_struct *tsk) spin_unlock_irq(lock); read_unlock(&tasklist_lock); kmem_cache_free(sighand_cachep, newsighand); - if (newsig) - kmem_cache_free(signal_cachep, newsig); return -EAGAIN; } - oldsig->group_exit = 1; + sig->group_exit = 1; zap_other_threads(current); read_unlock(&tasklist_lock); @@ -641,14 +612,16 @@ static inline int de_thread(struct task_struct *tsk) count = 2; if (current->pid == current->tgid) count = 1; - while (atomic_read(&oldsig->count) > count) { - oldsig->group_exit_task = current; - oldsig->notify_count = count; + while (atomic_read(&sig->count) > count) { + sig->group_exit_task = current; + sig->notify_count = count; __set_current_state(TASK_UNINTERRUPTIBLE); spin_unlock_irq(lock); schedule(); spin_lock_irq(lock); } + sig->group_exit_task = NULL; + sig->notify_count = 0; spin_unlock_irq(lock); /* @@ -659,14 +632,14 @@ static inline int de_thread(struct task_struct *tsk) if (current->pid != current->tgid) { struct task_struct *leader = current->group_leader, *parent; struct dentry *proc_dentry1, *proc_dentry2; - unsigned long state, ptrace; + unsigned long exit_state, ptrace; /* * Wait for the thread group leader to be a zombie. * It should already be zombie at this point, most * of the time. */ - while (leader->state != TASK_ZOMBIE) + while (leader->exit_state != EXIT_ZOMBIE) yield(); spin_lock(&leader->proc_lock); @@ -710,7 +683,7 @@ static inline int de_thread(struct task_struct *tsk) list_del(¤t->tasks); list_add_tail(¤t->tasks, &init_task.tasks); current->exit_signal = SIGCHLD; - state = leader->state; + exit_state = leader->exit_state; write_unlock_irq(&tasklist_lock); spin_unlock(&leader->proc_lock); @@ -718,36 +691,51 @@ static inline int de_thread(struct task_struct *tsk) proc_pid_flush(proc_dentry1); proc_pid_flush(proc_dentry2); - if (state != TASK_ZOMBIE) + if (exit_state != EXIT_ZOMBIE) BUG(); release_task(leader); } + /* + * Now there are really no other threads at all, + * so it's safe to stop telling them to kill themselves. + */ + sig->group_exit = 0; + no_thread_group: + BUG_ON(atomic_read(&sig->count) != 1); + exit_itimers(sig); - write_lock_irq(&tasklist_lock); - spin_lock(&oldsighand->siglock); - spin_lock(&newsighand->siglock); - - if (current == oldsig->curr_target) - oldsig->curr_target = next_thread(current); - if (newsig) - current->signal = newsig; - current->sighand = newsighand; - init_sigpending(¤t->pending); - recalc_sigpending(); - - spin_unlock(&newsighand->siglock); - spin_unlock(&oldsighand->siglock); - write_unlock_irq(&tasklist_lock); - - if (newsig && atomic_dec_and_test(&oldsig->count)) { - exit_itimers(oldsig); - kmem_cache_free(signal_cachep, oldsig); - } + if (atomic_read(&oldsighand->count) == 1) { + /* + * Now that we nuked the rest of the thread group, + * it turns out we are not sharing sighand any more either. + * So we can just keep it. + */ + kmem_cache_free(sighand_cachep, newsighand); + } else { + /* + * Move our state over to newsighand and switch it in. + */ + spin_lock_init(&newsighand->siglock); + atomic_set(&newsighand->count, 1); + memcpy(newsighand->action, oldsighand->action, + sizeof(newsighand->action)); - if (atomic_dec_and_test(&oldsighand->count)) - kmem_cache_free(sighand_cachep, oldsighand); + write_lock_irq(&tasklist_lock); + spin_lock(&oldsighand->siglock); + spin_lock(&newsighand->siglock); + + current->sighand = newsighand; + recalc_sigpending(); + + spin_unlock(&newsighand->siglock); + spin_unlock(&oldsighand->siglock); + write_unlock_irq(&tasklist_lock); + + if (atomic_dec_and_test(&oldsighand->count)) + kmem_cache_free(sighand_cachep, oldsighand); + } if (!thread_group_empty(current)) BUG(); @@ -1393,7 +1381,7 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs) current->signal->group_exit_code = exit_code; coredump_wait(mm); - if (current->rlim[RLIMIT_CORE].rlim_cur < binfmt->min_coredump) + if (current->signal->rlim[RLIMIT_CORE].rlim_cur < binfmt->min_coredump) goto fail_unlock; /* |
