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

@@ -36,6 +36,7 @@ int exit_test(void)
// l4_thread_switch(0);
#if 0
/* Kill it */
printf("Killing Thread (%d).\n", ids.tid);
if ((ret = l4_thread_control(THREAD_DESTROY, &ids)) < 0)
@@ -43,7 +44,7 @@ int exit_test(void)
else
printf("Success: Killed Thread (%d)\n", ids.tid);
return 0;
#endif
#if 0
/* Wait on it */
@@ -53,9 +54,9 @@ int exit_test(void)
else
printf("Error. Wait on (%d) failed. err = %d\n",
ids.tid, ret);
return 0;
#endif
return 0;
out_err:
BUG();
}
@@ -70,7 +71,7 @@ int main(void)
exit_test();
/* Now quit to demo self-paging quit */
//l4_exit(0);
l4_exit(0);
/* Now quit by null pointer */
// *((int *)0) = 5;

View File

@@ -59,7 +59,7 @@ do { \
task_set_wqh(current, wqh, &wq); \
(wqh)->sleepers++; \
list_insert_tail(&wq.task_list, &(wqh)->task_list);\
/* printk("(%d) waiting...\n", current->tid);*/ \
/* printk("(%d) waiting...\n", current->tid); */ \
sched_prepare_sleep(); \
spin_unlock(&(wqh)->slock); \
schedule(); \

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)