rust/src/rt/rust_scheduler.cpp

142 lines
3.4 KiB
C++
Raw Normal View History

#include "rust_scheduler.h"
#include "rust_util.h"
rust_scheduler::rust_scheduler(rust_kernel *kernel,
rust_srv *srv,
2012-02-06 20:00:49 -06:00
size_t num_threads,
rust_sched_id id) :
kernel(kernel),
srv(srv),
env(srv->env),
live_threads(num_threads),
live_tasks(0),
2012-02-06 20:00:49 -06:00
num_threads(num_threads),
id(id)
{
2012-02-03 20:42:12 -06:00
isaac_init(kernel, &rctx);
create_task_threads();
}
rust_scheduler::~rust_scheduler() {
destroy_task_threads();
}
rust_task_thread *
rust_scheduler::create_task_thread(int id) {
rust_srv *srv = this->srv->clone();
rust_task_thread *thread =
new (kernel, "rust_task_thread") rust_task_thread(this, srv, id);
KLOG(kernel, kern, "created task thread: " PTR ", id: %d, index: %d",
thread, id, thread->list_index);
return thread;
}
void
rust_scheduler::destroy_task_thread(rust_task_thread *thread) {
KLOG(kernel, kern, "deleting task thread: " PTR ", name: %s, index: %d",
thread, thread->name, thread->list_index);
rust_srv *srv = thread->srv;
delete thread;
delete srv;
}
void
rust_scheduler::create_task_threads() {
KLOG(kernel, kern, "Using %d scheduler threads.", num_threads);
for(size_t i = 0; i < num_threads; ++i) {
threads.push(create_task_thread(i));
}
}
void
rust_scheduler::destroy_task_threads() {
for(size_t i = 0; i < num_threads; ++i) {
destroy_task_thread(threads[i]);
}
}
void
rust_scheduler::start_task_threads()
{
// Copy num_threads because it's possible for the last thread
// to terminate and have the kernel delete us before we
// hit the last check against num_threads, in which case
// we would be accessing invalid memory.
uintptr_t num_threads = this->num_threads;
for(size_t i = 0; i < num_threads; ++i) {
rust_task_thread *thread = threads[i];
thread->start();
}
}
void
rust_scheduler::kill_all_tasks() {
for(size_t i = 0; i < num_threads; ++i) {
rust_task_thread *thread = threads[i];
thread->kill_all_tasks();
}
}
rust_task_id
rust_scheduler::create_task(rust_task *spawner, const char *name,
size_t init_stack_sz) {
size_t thread_no;
{
scoped_lock with(lock);
thread_no = isaac_rand(&rctx) % num_threads;
live_tasks++;
}
rust_task_thread *thread = threads[thread_no];
return thread->create_task(spawner, name, init_stack_sz);
}
rust_task_id
rust_scheduler::create_task(rust_task *spawner, const char *name) {
return create_task(spawner, name, env->min_stack_size);
}
void
rust_scheduler::release_task() {
bool need_exit = false;
{
scoped_lock with(lock);
live_tasks--;
if (live_tasks == 0) {
need_exit = true;
}
}
if (need_exit) {
// There are no more tasks on this scheduler. Time to leave
exit();
}
}
void
rust_scheduler::exit() {
// Take a copy of num_threads. After the last thread exits this
// scheduler will get destroyed, and our fields will cease to exist.
size_t current_num_threads = num_threads;
for(size_t i = 0; i < current_num_threads; ++i) {
threads[i]->exit();
}
}
size_t
rust_scheduler::number_of_threads() {
return num_threads;
}
void
rust_scheduler::release_task_thread() {
I(this, !lock.lock_held_by_current_thread());
uintptr_t new_live_threads;
{
scoped_lock with(lock);
new_live_threads = --live_threads;
}
if (new_live_threads == 0) {
kernel->release_scheduler_id(id);
}
}