summaryrefslogtreecommitdiff
path: root/fs/exec.c
diff options
context:
space:
mode:
authorGreg Kroah-Hartman <greg@kroah.com>2004-10-18 18:03:51 -0700
committerGreg Kroah-Hartman <greg@kroah.com>2004-10-18 18:03:51 -0700
commitbffe01870598b7a0a77073e25ee94e026bc98e6b (patch)
treef5f5b65fec1239b18a4c2634807ff5d7e5729de9 /fs/exec.c
parent23aebb6f8755121394ef088d84a7fa483b444aa9 (diff)
parenta4946826c30c56a5830326552a395c5b6afc13ef (diff)
merge
Diffstat (limited to 'fs/exec.c')
-rw-r--r--fs/exec.c122
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(&current->tasks);
list_add_tail(&current->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(&current->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;
/*