Fixed a nasty spinlock issue with wake_up_all that didn't get caught.

This commit is contained in:
Bahadir Balban
2009-10-31 20:47:20 +02:00
parent 638df9e238
commit c763679aaa
6 changed files with 67 additions and 15 deletions

View File

@@ -54,6 +54,54 @@ int thread_suspend(struct ktcb *task)
return thread_signal(task, TASK_SUSPENDING, TASK_INACTIVE);
}
static inline int TASK_IS_CHILD(struct ktcb *task)
{
return (((task) != current) &&
((task)->pagerid == current->tid));
}
int thread_delete_children(void)
{
struct ktcb *task, *n;
spin_lock(&curcont->ktcb_list.list_lock);
list_foreach_removable_struct(task, n,
&curcont->ktcb_list.list,
task_list) {
if (TASK_IS_CHILD(task)) {
spin_unlock(&curcont->ktcb_list.list_lock);
tcb_remove(task);
wake_up_all(&current->wqh_send, 0);
wake_up_all(&current->wqh_recv, 0);
BUG_ON(task->wqh_pager.sleepers > 0);
BUG_ON(task->state != TASK_INACTIVE);
tcb_delete(task);
spin_lock(&curcont->ktcb_list.list_lock);
}
}
spin_unlock(&curcont->ktcb_list.list_lock);
return 0;
}
int thread_suspend_children(void)
{
struct ktcb *task, *n;
spin_lock(&curcont->ktcb_list.list_lock);
list_foreach_removable_struct(task, n,
&curcont->ktcb_list.list,
task_list) {
if (TASK_IS_CHILD(task)) {
spin_unlock(&curcont->ktcb_list.list_lock);
thread_suspend(task);
spin_lock(&curcont->ktcb_list.list_lock);
}
}
spin_unlock(&curcont->ktcb_list.list_lock);
return 0;
}
/*
* Put them in TASK_DEAD so that a suspended exiting thread
* does not run again if issued THREAD_RUN
@@ -61,20 +109,23 @@ int thread_suspend(struct ktcb *task)
int thread_destroy(struct ktcb *task)
{
if (task == current) {
if (current->tid == current->pagerid)
if (current->tid == current->pagerid) {
/* Suspend children */
thread_suspend_children();
thread_delete_children();
sched_exit_pager();
else
} else {
sched_suspend_sync();
}
return 0;
}
thread_suspend(task);
tcb_remove(task);
/* Wake up waiters */
wake_up_all(&current->wqh_send, 0);
wake_up_all(&current->wqh_recv, 0);
wake_up_all(&task->wqh_send, 0);
wake_up_all(&task->wqh_recv, 0);
BUG_ON(task->wqh_pager.sleepers > 0);
BUG_ON(task->state != TASK_INACTIVE);

View File

@@ -21,7 +21,7 @@
#include INC_SUBARCH(mm.h)
/* Abort debugging conditions */
// #define DEBUG_ABORTS
//#define DEBUG_ABORTS
#if defined (DEBUG_ABORTS)
#define dbg_abort(...) dprintk(__VA_ARGS__)
#else

View File

@@ -74,11 +74,9 @@ void do_irq(void)
printk("Spurious or broken irq\n"); BUG();
}
irq_enable(irq_index);
#if 0
/* Process any pending flags for currently runnable task */
if (!in_nested_irq_context()) {
/* This is buggy, races on prio_total */
if (in_user()) {
if (current->flags & TASK_SUSPENDING)
sched_suspend_async();

View File

@@ -107,11 +107,11 @@ int wait_on(struct waitqueue_head *wqh)
return 0;
}
/* Wake up all - FIXME: this is buggy with double spin_unlock */
/* Wake up all in the queue */
void wake_up_all(struct waitqueue_head *wqh, unsigned int flags)
{
BUG_ON(wqh->sleepers < 0);
spin_lock(&wqh->slock);
BUG_ON(wqh->sleepers < 0);
while (wqh->sleepers > 0) {
struct waitqueue *wq = link_to_struct(wqh->task_list.next,
struct waitqueue,
@@ -130,6 +130,8 @@ void wake_up_all(struct waitqueue_head *wqh, unsigned int flags)
sched_resume_sync(sleeper);
else
sched_resume_async(sleeper);
spin_lock(&wqh->slock);
}
spin_unlock(&wqh->slock);
}
@@ -150,7 +152,7 @@ void wake_up(struct waitqueue_head *wqh, unsigned int flags)
task_unset_wqh(sleeper);
if (flags & WAKEUP_INTERRUPT)
sleeper->flags |= TASK_INTERRUPTED;
// printk("(%d) Waking up (%d)\n", current->tid, sleeper->tid);
//printk("(%d) Waking up (%d)\n", current->tid, sleeper->tid);
spin_unlock(&wqh->slock);
if (flags & WAKEUP_SYNC)