2012-04-02 22:18:01 -05:00
|
|
|
|
2012-04-03 04:37:00 -05:00
|
|
|
#include "rust_globals.h"
|
2012-02-03 17:12:18 -06:00
|
|
|
#include "rust_scheduler.h"
|
2012-04-02 22:18:01 -05:00
|
|
|
#include "rust_task.h"
|
2012-02-03 17:12:18 -06:00
|
|
|
#include "rust_util.h"
|
2012-03-29 17:21:32 -05:00
|
|
|
#include "rust_sched_launcher.h"
|
2012-02-03 17:12:18 -06:00
|
|
|
|
|
|
|
rust_scheduler::rust_scheduler(rust_kernel *kernel,
|
2012-09-14 08:01:17 -05:00
|
|
|
size_t max_num_threads,
|
2012-04-01 18:38:42 -05:00
|
|
|
rust_sched_id id,
|
2012-04-01 20:42:28 -05:00
|
|
|
bool allow_exit,
|
2012-07-20 17:06:17 -05:00
|
|
|
bool killed,
|
2012-04-01 20:42:28 -05:00
|
|
|
rust_sched_launcher_factory *launchfac) :
|
2012-07-20 17:47:47 -05:00
|
|
|
ref_count(1),
|
2012-02-03 17:12:18 -06:00
|
|
|
kernel(kernel),
|
2012-09-14 08:01:17 -05:00
|
|
|
live_threads(0),
|
2012-02-07 01:38:22 -06:00
|
|
|
live_tasks(0),
|
2012-03-31 13:14:54 -05:00
|
|
|
cur_thread(0),
|
2012-04-01 18:38:42 -05:00
|
|
|
may_exit(allow_exit),
|
2012-09-14 08:01:17 -05:00
|
|
|
killed(killed),
|
|
|
|
launchfac(launchfac),
|
|
|
|
max_num_threads(max_num_threads),
|
2012-02-06 20:00:49 -06:00
|
|
|
id(id)
|
2012-02-03 17:12:18 -06:00
|
|
|
{
|
2012-09-14 08:01:17 -05:00
|
|
|
// Create the first thread
|
2012-09-18 05:28:05 -05:00
|
|
|
scoped_lock with(lock);
|
2012-09-14 08:01:17 -05:00
|
|
|
threads.push(create_task_thread(0));
|
2012-02-03 17:12:18 -06:00
|
|
|
}
|
|
|
|
|
2012-07-20 17:47:47 -05:00
|
|
|
void rust_scheduler::delete_this() {
|
2012-02-03 17:12:18 -06:00
|
|
|
destroy_task_threads();
|
2012-09-14 08:01:17 -05:00
|
|
|
delete launchfac;
|
2012-07-20 17:47:47 -05:00
|
|
|
delete this;
|
2012-02-03 17:12:18 -06:00
|
|
|
}
|
|
|
|
|
2012-03-29 17:21:32 -05:00
|
|
|
rust_sched_launcher *
|
2012-09-14 08:01:17 -05:00
|
|
|
rust_scheduler::create_task_thread(int id) {
|
2012-09-18 05:28:05 -05:00
|
|
|
lock.must_have_lock();
|
2012-09-14 08:01:17 -05:00
|
|
|
live_threads++;
|
2012-07-20 17:06:17 -05:00
|
|
|
rust_sched_launcher *thread = launchfac->create(this, id, killed);
|
2012-09-14 08:01:17 -05:00
|
|
|
KLOG(kernel, kern, "created task thread: " PTR
|
|
|
|
", id: %d, live_threads: %d",
|
|
|
|
thread, id, live_threads);
|
2012-02-03 17:12:18 -06:00
|
|
|
return thread;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2012-03-29 17:21:32 -05:00
|
|
|
rust_scheduler::destroy_task_thread(rust_sched_launcher *thread) {
|
|
|
|
KLOG(kernel, kern, "deleting task thread: " PTR, thread);
|
2012-02-03 17:12:18 -06:00
|
|
|
delete thread;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
rust_scheduler::destroy_task_threads() {
|
2012-09-18 05:28:05 -05:00
|
|
|
scoped_lock with(lock);
|
2012-09-14 08:01:17 -05:00
|
|
|
for(size_t i = 0; i < threads.size(); ++i) {
|
2012-02-03 17:12:18 -06:00
|
|
|
destroy_task_thread(threads[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
rust_scheduler::start_task_threads()
|
|
|
|
{
|
2012-09-18 05:28:05 -05:00
|
|
|
scoped_lock with(lock);
|
2012-09-14 08:01:17 -05:00
|
|
|
for(size_t i = 0; i < threads.size(); ++i) {
|
2012-03-29 17:21:32 -05:00
|
|
|
rust_sched_launcher *thread = threads[i];
|
2012-02-03 17:12:18 -06:00
|
|
|
thread->start();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-02-27 15:36:54 -06:00
|
|
|
void
|
|
|
|
rust_scheduler::join_task_threads()
|
|
|
|
{
|
2012-09-18 05:28:05 -05:00
|
|
|
scoped_lock with(lock);
|
2012-09-14 08:01:17 -05:00
|
|
|
for(size_t i = 0; i < threads.size(); ++i) {
|
2012-03-29 17:21:32 -05:00
|
|
|
rust_sched_launcher *thread = threads[i];
|
2012-02-27 15:36:54 -06:00
|
|
|
thread->join();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-02-03 17:12:18 -06:00
|
|
|
void
|
|
|
|
rust_scheduler::kill_all_tasks() {
|
2012-09-18 05:28:05 -05:00
|
|
|
array_list<rust_sched_launcher *> copied_threads;
|
|
|
|
{
|
|
|
|
scoped_lock with(lock);
|
|
|
|
killed = true;
|
|
|
|
for (size_t i = 0; i < threads.size(); ++i) {
|
|
|
|
copied_threads.push(threads[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for(size_t i = 0; i < copied_threads.size(); ++i) {
|
|
|
|
rust_sched_launcher *thread = copied_threads[i];
|
2012-03-29 17:21:32 -05:00
|
|
|
thread->get_loop()->kill_all_tasks();
|
2012-02-03 17:12:18 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-03-14 22:22:34 -05:00
|
|
|
rust_task *
|
2012-03-21 16:47:48 -05:00
|
|
|
rust_scheduler::create_task(rust_task *spawner, const char *name) {
|
2012-02-03 17:12:18 -06:00
|
|
|
size_t thread_no;
|
|
|
|
{
|
2012-03-31 01:57:29 -05:00
|
|
|
scoped_lock with(lock);
|
|
|
|
live_tasks++;
|
2012-09-14 08:01:17 -05:00
|
|
|
|
2012-09-18 05:28:05 -05:00
|
|
|
if (cur_thread < threads.size()) {
|
|
|
|
thread_no = cur_thread;
|
|
|
|
} else {
|
|
|
|
assert(threads.size() < max_num_threads);
|
|
|
|
thread_no = threads.size();
|
|
|
|
rust_sched_launcher *thread = create_task_thread(thread_no);
|
|
|
|
thread->start();
|
|
|
|
threads.push(thread);
|
2012-09-14 08:01:17 -05:00
|
|
|
}
|
2012-09-18 05:28:05 -05:00
|
|
|
cur_thread = (thread_no + 1) % max_num_threads;
|
2012-02-03 17:12:18 -06:00
|
|
|
}
|
2012-09-14 08:01:17 -05:00
|
|
|
KLOG(kernel, kern, "Creating task %s, on thread %d.", name, thread_no);
|
2012-04-06 19:03:00 -05:00
|
|
|
kernel->register_task();
|
2012-03-29 17:21:32 -05:00
|
|
|
rust_sched_launcher *thread = threads[thread_no];
|
|
|
|
return thread->get_loop()->create_task(spawner, name);
|
2012-02-03 17:12:18 -06:00
|
|
|
}
|
|
|
|
|
2012-02-07 01:38:22 -06:00
|
|
|
void
|
|
|
|
rust_scheduler::release_task() {
|
|
|
|
bool need_exit = false;
|
|
|
|
{
|
2012-03-31 01:57:29 -05:00
|
|
|
scoped_lock with(lock);
|
|
|
|
live_tasks--;
|
2012-04-01 18:38:42 -05:00
|
|
|
if (live_tasks == 0 && may_exit) {
|
2012-03-31 01:57:29 -05:00
|
|
|
need_exit = true;
|
|
|
|
}
|
2012-02-07 01:38:22 -06:00
|
|
|
}
|
2012-04-06 19:03:00 -05:00
|
|
|
kernel->unregister_task();
|
2012-02-07 01:38:22 -06:00
|
|
|
if (need_exit) {
|
2012-04-01 01:12:06 -05:00
|
|
|
exit();
|
2012-02-07 01:38:22 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-02-03 17:12:18 -06:00
|
|
|
void
|
|
|
|
rust_scheduler::exit() {
|
2012-09-14 08:01:17 -05:00
|
|
|
// Take a copy of the number of threads. After the last thread exits this
|
2012-02-07 01:38:22 -06:00
|
|
|
// scheduler will get destroyed, and our fields will cease to exist.
|
2012-09-18 05:28:05 -05:00
|
|
|
//
|
|
|
|
// This is also the reason we can't use the lock here (as in the other
|
|
|
|
// cases when accessing `threads`), after the loop the lock won't exist
|
|
|
|
// anymore. This is safe because this method is only called when all the
|
|
|
|
// task are dead, so there is no chance of a task trying to create new
|
|
|
|
// threads.
|
2012-09-14 08:01:17 -05:00
|
|
|
size_t current_num_threads = threads.size();
|
2012-02-07 01:38:22 -06:00
|
|
|
for(size_t i = 0; i < current_num_threads; ++i) {
|
2012-03-29 17:21:32 -05:00
|
|
|
threads[i]->get_loop()->exit();
|
2012-02-03 17:12:18 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-09-14 08:01:17 -05:00
|
|
|
size_t
|
|
|
|
rust_scheduler::max_number_of_threads() {
|
|
|
|
return max_num_threads;
|
|
|
|
}
|
|
|
|
|
2012-02-03 17:12:18 -06:00
|
|
|
size_t
|
|
|
|
rust_scheduler::number_of_threads() {
|
2012-09-18 05:28:05 -05:00
|
|
|
scoped_lock with(lock);
|
2012-09-14 08:01:17 -05:00
|
|
|
return threads.size();
|
2012-02-03 17:12:18 -06:00
|
|
|
}
|
2012-02-04 16:54:10 -06:00
|
|
|
|
|
|
|
void
|
|
|
|
rust_scheduler::release_task_thread() {
|
|
|
|
uintptr_t new_live_threads;
|
|
|
|
{
|
2012-03-31 01:57:29 -05:00
|
|
|
scoped_lock with(lock);
|
|
|
|
new_live_threads = --live_threads;
|
2012-02-04 16:54:10 -06:00
|
|
|
}
|
|
|
|
if (new_live_threads == 0) {
|
2012-03-31 01:57:29 -05:00
|
|
|
kernel->release_scheduler_id(id);
|
2012-02-04 16:54:10 -06:00
|
|
|
}
|
|
|
|
}
|
2012-04-01 18:38:42 -05:00
|
|
|
|
|
|
|
void
|
|
|
|
rust_scheduler::allow_exit() {
|
|
|
|
bool need_exit = false;
|
|
|
|
{
|
|
|
|
scoped_lock with(lock);
|
|
|
|
may_exit = true;
|
|
|
|
need_exit = live_tasks == 0;
|
|
|
|
}
|
|
|
|
if (need_exit) {
|
|
|
|
exit();
|
|
|
|
}
|
|
|
|
}
|
2012-04-03 19:39:35 -05:00
|
|
|
|
|
|
|
void
|
|
|
|
rust_scheduler::disallow_exit() {
|
|
|
|
scoped_lock with(lock);
|
|
|
|
may_exit = false;
|
|
|
|
}
|