From 638df9e238b4af0ba71ebd31aa92960e45a7a009 Mon Sep 17 00:00:00 2001 From: Bahadir Balban Date: Sat, 31 Oct 2009 18:45:22 +0200 Subject: [PATCH] Simultaneous exit/thread_destroy working Reiterating again to simplify: Working: - Pager issues destroy, client also issues exit they work in sync. Missing - Pager killing itself - Pager killing all children while killing itself - Pager waiting on children --- conts/test/main.c | 5 +- include/l4/generic/scheduler.h | 2 +- include/l4/generic/tcb.h | 1 + src/api/thread.c | 88 +++++++++++++--------------------- src/generic/scheduler.c | 27 ++--------- 5 files changed, 42 insertions(+), 81 deletions(-) diff --git a/conts/test/main.c b/conts/test/main.c index de95bdb..dbf53e0 100644 --- a/conts/test/main.c +++ b/conts/test/main.c @@ -15,6 +15,7 @@ int exit_test_thread(void *arg) { + l4_thread_switch(0); l4_exit(0); return 0; } @@ -38,11 +39,11 @@ int exit_test(void) /* Kill it */ printf("Killing Thread (%d).\n", ids.tid); if ((ret = l4_thread_control(THREAD_DESTROY, &ids)) < 0) - printf("Error: Killing Thread (%d)\n", ids.tid); + printf("Error: Killing Thread (%d), err = %d\n", ids.tid, ret); else printf("Success: Killed Thread (%d)\n", ids.tid); - + return 0; #if 0 /* Wait on it */ diff --git a/include/l4/generic/scheduler.h b/include/l4/generic/scheduler.h index ee3298c..b1e2d7b 100644 --- a/include/l4/generic/scheduler.h +++ b/include/l4/generic/scheduler.h @@ -61,7 +61,7 @@ extern struct scheduler scheduler; void sched_init_runqueue(struct runqueue *rq); void sched_init_task(struct ktcb *task, int priority); void sched_prepare_sleep(void); -void sched_pager_exit(void); +void sched_exit_pager(void); void sched_exit_sync(void); void sched_suspend_sync(void); void sched_suspend_async(void); diff --git a/include/l4/generic/tcb.h b/include/l4/generic/tcb.h index 73a4adb..aa13f87 100644 --- a/include/l4/generic/tcb.h +++ b/include/l4/generic/tcb.h @@ -36,6 +36,7 @@ enum task_state { TASK_INACTIVE = 0, TASK_SLEEPING = 1, TASK_RUNNABLE = 2, + TASK_DEAD = 3, }; #define TASK_ID_INVALID -1 diff --git a/src/api/thread.c b/src/api/thread.c index 35d0c0a..9390d46 100644 --- a/src/api/thread.c +++ b/src/api/thread.c @@ -28,8 +28,8 @@ int sys_thread_switch(void) * doing, and take action on the signal provided. Currently this * may be a suspension or an exit signal. */ -int thread_signal_sync(struct ktcb *task, unsigned int flags, - unsigned int task_state) +int thread_signal(struct ktcb *task, unsigned int flags, + unsigned int task_state) { int ret = 0; @@ -42,7 +42,7 @@ int thread_signal_sync(struct ktcb *task, unsigned int flags, /* Wake it up if it's sleeping */ wake_up_task(task, WAKEUP_INTERRUPT | WAKEUP_SYNC); - /* Wait until task suspends itself */ + /* Wait until task switches to desired state */ WAIT_EVENT(&task->wqh_pager, task->state == task_state, ret); @@ -51,7 +51,36 @@ int thread_signal_sync(struct ktcb *task, unsigned int flags, int thread_suspend(struct ktcb *task) { - return thread_signal_sync(task, TASK_SUSPENDING, TASK_INACTIVE); + return thread_signal(task, TASK_SUSPENDING, TASK_INACTIVE); +} + +/* + * Put them in TASK_DEAD so that a suspended exiting thread + * does not run again if issued THREAD_RUN + */ +int thread_destroy(struct ktcb *task) +{ + if (task == current) { + if (current->tid == current->pagerid) + sched_exit_pager(); + else + sched_suspend_sync(); + return 0; + } + + thread_suspend(task); + + tcb_remove(task); + + /* Wake up waiters */ + wake_up_all(¤t->wqh_send, 0); + wake_up_all(¤t->wqh_recv, 0); + + BUG_ON(task->wqh_pager.sleepers > 0); + BUG_ON(task->state != TASK_INACTIVE); + + tcb_delete(task); + return 0; } int arch_clear_thread(struct ktcb *tcb) @@ -113,57 +142,6 @@ int thread_recycle(struct ktcb *task) return 0; } -int thread_destroy(struct ktcb *task) -{ - int ret; - - /* If we're a self-destructing pager */ - if (task == current && - current->tid == current->pagerid) { - struct ktcb *child, *n; - - /* Make all children exit synchronously */ - spin_lock(&curcont->ktcb_list.list_lock); - list_foreach_removable_struct(child, n, - &curcont->ktcb_list.list, - task_list) { - if (child->pagerid == current->tid && - child != current) { - spin_unlock(&curcont->ktcb_list.list_lock); - - /* Its a bug since nobody can interrupt us */ - BUG_ON(thread_signal_sync(child, TASK_EXITING, - TASK_INACTIVE) < 0); - spin_lock(&curcont->ktcb_list.list_lock); - } - } - spin_unlock(&curcont->ktcb_list.list_lock); - - /* Delete all exited children */ - spin_lock(¤t->child_exit_list.list_lock); - printk("(%d) To delete %d children\n", current->tid, current->child_exit_list.count); - list_foreach_removable_struct(child, n, - ¤t->child_exit_list.list, - task_list) { - list_remove(&child->task_list); - tcb_delete(child); - } - spin_unlock(¤t->child_exit_list.list_lock); - - /* Destroy yourself */ - sched_pager_exit(); - BUG(); - } - - if ((ret = thread_signal_sync(task, TASK_EXITING, TASK_INACTIVE)) < 0) - return ret; - - ktcb_list_remove(task, ¤t->child_exit_list); - tcb_delete(task); - - return 0; -} - /* Runs a thread for the first time */ int thread_start(struct ktcb *task) { diff --git a/src/generic/scheduler.c b/src/generic/scheduler.c index eda2d1a..2999e46 100644 --- a/src/generic/scheduler.c +++ b/src/generic/scheduler.c @@ -229,7 +229,7 @@ void sched_resume_async(struct ktcb *task) * A self-paging thread deletes itself, * schedules and disappears from the system. */ -void sched_pager_exit(void) +void sched_exit_pager(void) { // printk("Pager (%d) Exiting...\n", current->tid); /* Remove from its list, callers get -ESRCH */ @@ -269,13 +269,6 @@ void sched_exit_sync(void) { struct ktcb *pager = tcb_find(current->pagerid); - /* Quit global list */ - tcb_remove(current); - - /* Wake up waiters */ - wake_up_all(¤t->wqh_send, 0); - wake_up_all(¤t->wqh_recv, 0); - /* Go to exit list */ ktcb_list_add(current, &pager->child_exit_list); @@ -285,8 +278,8 @@ void sched_exit_sync(void) wake_up(¤t->wqh_pager, 0); sched_rq_remove_task(current); - current->state = TASK_INACTIVE; - current->flags &= ~TASK_SUSPENDING; + current->state = TASK_DEAD; + current->flags &= ~TASK_EXITING; preempt_enable(); /* Quit */ @@ -294,16 +287,6 @@ void sched_exit_sync(void) BUG(); } -/* - * TODO: - * Instead of sched_suspend_sync() - * call sched_die_sync() on killer suspends: - * (e.g. if also kill flag set, call sched_die_sync instead) - * and handle dying on its own and dying over a pager - * in there. (e.g. put yourself in a task_dead queue, take - * care of pager calling destroy on you, calling wait on you etc.) - */ - /* * NOTE: Could do these as sched_prepare_suspend() * + schedule() or need_resched = 1 @@ -328,12 +311,10 @@ void sched_suspend_async(void) sched_rq_remove_task(current); current->state = TASK_INACTIVE; current->flags &= ~TASK_SUSPENDING; - - /* This will make sure we yield soon */ preempt_enable(); if (current->pagerid != current->tid) - wake_up_task(tcb_find(current->pagerid), 0); + wake_up(¤t->wqh_pager, 0); need_resched = 1; }