diff --git a/mk/rt.mk b/mk/rt.mk index 5e01c158d7d..eee3f9cf3ea 100644 --- a/mk/rt.mk +++ b/mk/rt.mk @@ -52,6 +52,7 @@ RUNTIME_CS_$(1) := \ rt/rust_env.cpp \ rt/rust_sched_loop.cpp \ rt/rust_sched_launcher.cpp \ + rt/rust_sched_driver.cpp \ rt/rust_scheduler.cpp \ rt/rust_sched_reaper.cpp \ rt/rust_task.cpp \ diff --git a/src/rt/rust_sched_driver.cpp b/src/rt/rust_sched_driver.cpp new file mode 100644 index 00000000000..dd9ca9e7f10 --- /dev/null +++ b/src/rt/rust_sched_driver.cpp @@ -0,0 +1,46 @@ +#include +#include "rust_internal.h" +#include "rust_sched_driver.h" +#include "rust_sched_loop.h" + +rust_sched_driver::rust_sched_driver(rust_sched_loop *sched_loop) + : sched_loop(sched_loop), + signalled(false) { + + assert(sched_loop != NULL); + sched_loop->on_pump_loop(this); +} + +/** + * Starts the main scheduler loop which performs task scheduling for this + * domain. + * + * Returns once no more tasks can be scheduled and all task ref_counts + * drop to zero. + */ +void +rust_sched_driver::start_main_loop() { + assert(sched_loop != NULL); + + rust_sched_loop_state state = sched_loop_state_keep_going; + while (state != sched_loop_state_exit) { + DLOG(sched_loop, dom, "pumping scheduler"); + state = sched_loop->run_single_turn(); + + if (state == sched_loop_state_block) { + scoped_lock with(lock); + if (!signalled) { + DLOG(sched_loop, dom, "blocking scheduler"); + lock.wait(); + } + signalled = false; + } + } +} + +void +rust_sched_driver::signal() { + scoped_lock with(lock); + signalled = true; + lock.signal(); +} diff --git a/src/rt/rust_sched_driver.h b/src/rt/rust_sched_driver.h new file mode 100644 index 00000000000..c8dae9ca7b8 --- /dev/null +++ b/src/rt/rust_sched_driver.h @@ -0,0 +1,23 @@ +#ifndef RUST_SCHED_DRIVER_H +#define RUST_SCHED_DRIVER_H + +#include "sync/lock_and_signal.h" +#include "rust_signal.h" + +struct rust_sched_loop; + +class rust_sched_driver : public rust_signal { +private: + rust_sched_loop *sched_loop; + lock_and_signal lock; + bool signalled; + +public: + rust_sched_driver(rust_sched_loop *sched_loop); + + void start_main_loop(); + + virtual void signal(); +}; + +#endif /* RUST_SCHED_DRIVER_H */ diff --git a/src/rt/rust_sched_launcher.cpp b/src/rt/rust_sched_launcher.cpp index 08a5ff47f3f..2a001a619fa 100644 --- a/src/rt/rust_sched_launcher.cpp +++ b/src/rt/rust_sched_launcher.cpp @@ -7,10 +7,11 @@ rust_sched_launcher::rust_sched_launcher(rust_scheduler *sched, rust_srv *srv, int id) : rust_thread(SCHED_STACK_SIZE), kernel(sched->kernel), - sched_loop(sched, srv, id) { + sched_loop(sched, srv, id), + driver(&sched_loop) { } void rust_sched_launcher::run() { - sched_loop.start_main_loop(); + driver.start_main_loop(); } diff --git a/src/rt/rust_sched_launcher.h b/src/rt/rust_sched_launcher.h index 38d46042bcf..1baf1724341 100644 --- a/src/rt/rust_sched_launcher.h +++ b/src/rt/rust_sched_launcher.h @@ -3,12 +3,7 @@ #include "rust_internal.h" #include "sync/rust_thread.h" - -#ifndef _WIN32 -#include -#else -#include -#endif +#include "rust_sched_driver.h" class rust_sched_launcher : public kernel_owned, @@ -18,6 +13,7 @@ public: private: rust_sched_loop sched_loop; + rust_sched_driver driver; public: rust_sched_launcher(rust_scheduler *sched, rust_srv *srv, int id); diff --git a/src/rt/rust_sched_loop.cpp b/src/rt/rust_sched_loop.cpp index 3ddf23cd9a1..ce549db5236 100644 --- a/src/rt/rust_sched_loop.cpp +++ b/src/rt/rust_sched_loop.cpp @@ -25,6 +25,7 @@ rust_sched_loop::rust_sched_loop(rust_scheduler *sched, should_exit(false), cached_c_stack(NULL), dead_task(NULL), + pump_signal(NULL), kernel(sched->kernel), sched(sched), srv(srv), @@ -183,32 +184,24 @@ rust_sched_loop::log_state() { } } -/** - * Starts the main scheduler loop which performs task scheduling for this - * domain. - * - * Returns once no more tasks can be scheduled and all task ref_counts - * drop to zero. - */ void -rust_sched_loop::start_main_loop() { - DLOG(this, dom, "started domain loop %d", id); +rust_sched_loop::on_pump_loop(rust_signal *signal) { + I(this, pump_signal == NULL); + I(this, signal != NULL); + pump_signal = signal; +} - 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); - } +void +rust_sched_loop::pump_loop() { + I(this, pump_signal != NULL); + pump_signal->signal(); } rust_sched_loop_state rust_sched_loop::run_single_turn() { + DLOG(this, task, + "scheduler %d resuming ...", id); + lock.lock(); if (!should_exit) { @@ -344,7 +337,7 @@ rust_sched_loop::transition(rust_task *task, } task->set_state(dst, cond, cond_name); - lock.signal(); + pump_loop(); } #ifndef _WIN32 @@ -382,7 +375,7 @@ rust_sched_loop::exit() { scoped_lock with(lock); DLOG(this, dom, "Requesting exit for thread %d", id); should_exit = true; - lock.signal(); + pump_loop(); } // Before activating each task, make sure we have a C stack available. diff --git a/src/rt/rust_sched_loop.h b/src/rt/rust_sched_loop.h index c21dc9b0c34..e89e9a6313b 100644 --- a/src/rt/rust_sched_loop.h +++ b/src/rt/rust_sched_loop.h @@ -3,6 +3,7 @@ #include "rust_internal.h" #include "rust_stack.h" +#include "rust_signal.h" #include "context.h" enum rust_task_state { @@ -22,6 +23,8 @@ enum rust_sched_loop_state { sched_loop_state_exit }; +struct rust_task; + typedef indexed_list rust_task_list; struct rust_sched_loop @@ -53,13 +56,15 @@ private: rust_task_list blocked_tasks; rust_task *dead_task; + rust_signal *pump_signal; + void prepare_c_stack(rust_task *task); void unprepare_c_stack(); rust_task_list *state_list(rust_task_state state); const char *state_name(rust_task_state state); - rust_sched_loop_state run_single_turn(); + void pump_loop(); public: rust_kernel *kernel; @@ -96,7 +101,8 @@ public: void reap_dead_tasks(); rust_task *schedule_task(); - void start_main_loop(); + void on_pump_loop(rust_signal *signal); + rust_sched_loop_state run_single_turn(); void log_state(); diff --git a/src/rt/rust_signal.h b/src/rt/rust_signal.h new file mode 100644 index 00000000000..3f27f1fad97 --- /dev/null +++ b/src/rt/rust_signal.h @@ -0,0 +1,10 @@ +#ifndef RUST_SIGNAL_H +#define RUST_SIGNAL_H + +// Just an abstrict class that reperesents something that can be signalled +class rust_signal { +public: + virtual void signal() = 0; +}; + +#endif /* RUST_SIGNAL_H */