rt: Refactor the scheduler loop so that it can be driven from without

This commit is contained in:
Brian Anderson 2012-03-29 17:07:50 -07:00
parent 243790836a
commit 771c1be6a6
2 changed files with 58 additions and 25 deletions

View File

@ -182,6 +182,7 @@ rust_sched_loop::log_state() {
}
}
}
/**
* Starts the main scheduler loop which performs task scheduling for this
* domain.
@ -191,11 +192,29 @@ rust_sched_loop::log_state() {
*/
void
rust_sched_loop::start_main_loop() {
lock.lock();
DLOG(this, dom, "started domain loop %d", id);
while (!should_exit) {
rust_sched_loop_state state = sched_loop_state_keep_going;
while (state != sched_loop_state_exit) {
state = run_single_turn();
scoped_lock with(lock);
if (!should_exit && running_tasks.length() == 0) {
lock.wait();
}
DLOG(this, task,
"scheduler %d resuming ...", id);
}
}
rust_sched_loop_state
rust_sched_loop::run_single_turn() {
lock.lock();
if (!should_exit) {
A(this, dead_task == NULL,
"Tasks should only die after running");
DLOG(this, dom, "worker %d, number_of_live_tasks = %d",
id, number_of_live_tasks());
@ -206,12 +225,9 @@ rust_sched_loop::start_main_loop() {
DLOG(this, task,
"all tasks are blocked, scheduler id %d yielding ...",
id);
lock.wait();
A(this, dead_task == NULL,
"Tasks should only die after running");
DLOG(this, task,
"scheduler %d resuming ...", id);
continue;
lock.unlock();
return sched_loop_state_block;
}
I(this, scheduled_task->running());
@ -239,23 +255,27 @@ rust_sched_loop::start_main_loop() {
id);
reap_dead_tasks();
lock.unlock();
return sched_loop_state_keep_going;
} else {
A(this, running_tasks.is_empty(), "Should have no running tasks");
A(this, blocked_tasks.is_empty(), "Should have no blocked tasks");
A(this, dead_task == NULL, "Should have no dead tasks");
DLOG(this, dom, "finished main-loop %d", id);
lock.unlock();
I(this, !extra_c_stack);
if (cached_c_stack) {
destroy_stack(kernel->region(), cached_c_stack);
cached_c_stack = NULL;
}
sched->release_task_thread();
return sched_loop_state_exit;
}
A(this, running_tasks.is_empty(), "Should have no running tasks");
A(this, blocked_tasks.is_empty(), "Should have no blocked tasks");
A(this, dead_task == NULL, "Should have no dead tasks");
DLOG(this, dom, "finished main-loop %d", id);
lock.unlock();
I(this, !extra_c_stack);
if (cached_c_stack) {
destroy_stack(kernel->region(), cached_c_stack);
cached_c_stack = NULL;
}
sched->release_task_thread();
}
rust_task *
@ -360,6 +380,7 @@ rust_sched_loop::place_task_in_tls(rust_task *task) {
void
rust_sched_loop::exit() {
scoped_lock with(lock);
DLOG(this, dom, "Requesting exit for thread %d", id);
should_exit = true;
lock.signal();
}

View File

@ -12,6 +12,16 @@ enum rust_task_state {
task_state_dead
};
/*
The result of every turn of the scheduler loop. Instructs the loop
driver how to proceed.
*/
enum rust_sched_loop_state {
sched_loop_state_keep_going,
sched_loop_state_block,
sched_loop_state_exit
};
typedef indexed_list<rust_task> rust_task_list;
struct rust_sched_loop
@ -49,6 +59,8 @@ private:
rust_task_list *state_list(rust_task_state state);
const char *state_name(rust_task_state state);
rust_sched_loop_state run_single_turn();
public:
rust_kernel *kernel;
rust_scheduler *sched;