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
This commit is contained in:
Bahadir Balban
2009-10-31 18:45:22 +02:00
parent 09197d1fb1
commit 638df9e238
5 changed files with 42 additions and 81 deletions

View File

@@ -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 */

View File

@@ -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);

View File

@@ -36,6 +36,7 @@ enum task_state {
TASK_INACTIVE = 0,
TASK_SLEEPING = 1,
TASK_RUNNABLE = 2,
TASK_DEAD = 3,
};
#define TASK_ID_INVALID -1

View File

@@ -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(&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);
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(&current->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,
&current->child_exit_list.list,
task_list) {
list_remove(&child->task_list);
tcb_delete(child);
}
spin_unlock(&current->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, &current->child_exit_list);
tcb_delete(task);
return 0;
}
/* Runs a thread for the first time */
int thread_start(struct ktcb *task)
{

View File

@@ -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(&current->wqh_send, 0);
wake_up_all(&current->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(&current->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(&current->wqh_pager, 0);
need_resched = 1;
}