diff options
| author | Andrew Morton <akpm@digeo.com> | 2003-02-19 21:19:00 -0800 |
|---|---|---|
| committer | Paul Mackerras <paulus@samba.org> | 2003-02-19 21:19:00 -0800 |
| commit | 776969f04b4a372e9eea8f7ddf683907613765bf (patch) | |
| tree | 45fae7a66a495d6a9e051b6535aaa1a38c2afa6b /kernel | |
| parent | 3b6244e1374384311d6b262aa522a0f2ae7bd041 (diff) | |
[PATCH] Keep interrupts enabled in exit path
We are leaving local interrupts disabled coming out of exit_notify().
But we are about to call wait_task_inactive() which spins, waiting for
another CPU to end a task. If that CPU has issued smp_call_function() to
this CPU, deadlock.
So the patch enables interrupts again before returning from exit_notify().
Also, exit_notify() returns with preemption disabled, so there is no
need to perform another preempt_disable() in do_exit().
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/exit.c | 17 |
1 files changed, 11 insertions, 6 deletions
diff --git a/kernel/exit.c b/kernel/exit.c index c45159219e83..224cb7adc73f 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -674,13 +674,19 @@ static void exit_notify(struct task_struct *tsk) tsk->state = TASK_ZOMBIE; /* - * No need to unlock IRQs, we'll schedule() immediately - * anyway. In the preemption case this also makes it - * impossible for the task to get runnable again (thus - * the "_raw_" unlock - to make sure we don't try to - * preempt here). + * In the preemption case it must be impossible for the task + * to get runnable again, so use "_raw_" unlock to keep + * preempt_count elevated until we schedule(). + * + * To avoid deadlock on SMP, interrupts must be unmasked. If we + * don't, subsequently called functions (e.g, wait_task_inactive() + * via release_task()) will spin, with interrupt flags + * unwittingly blocked, until the other task sleeps. That task + * may itself be waiting for smp_call_function() to answer and + * complete, and with interrupts blocked that will never happen. */ _raw_write_unlock(&tasklist_lock); + local_irq_enable(); } NORET_TYPE void do_exit(long code) @@ -727,7 +733,6 @@ NORET_TYPE void do_exit(long code) tsk->exit_code = code; exit_notify(tsk); - preempt_disable(); if (tsk->exit_signal == -1) release_task(tsk); |
