/** * 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_scheduler::start_main_loop() { lock.lock(); // Make sure someone is watching, to pull us out of infinite loops. // // FIXME: time-based interruption is not presently working; worked // in rustboot and has been completely broken in rustc. // // rust_timer timer(this); DLOG(this, dom, "started domain loop %d", id); while (kernel->live_tasks > 0) { A(this, kernel->is_deadlocked() == false, "deadlock"); DLOG(this, dom, "worker %d, number_of_live_tasks = %d, total = %d", id, number_of_live_tasks(), kernel->live_tasks); rust_task *scheduled_task = schedule_task(id); if (scheduled_task == NULL) { log_state(); DLOG(this, task, "all tasks are blocked, scheduler id %d yielding ...", id); lock.timed_wait(10); reap_dead_tasks(id); DLOG(this, task, "scheduler %d resuming ...", id); continue; } I(this, scheduled_task->running()); DLOG(this, task, "activating task %s 0x%" PRIxPTR ", sp=0x%" PRIxPTR ", state: %s", scheduled_task->name, (uintptr_t)scheduled_task, scheduled_task->user.rust_sp, scheduled_task->state->name); place_task_in_tls(scheduled_task); interrupt_flag = 0; DLOG(this, task, "Running task %p on worker %d", scheduled_task, id); scheduled_task->running_on = id; activate(scheduled_task); scheduled_task->running_on = -1; DLOG(this, task, "returned from task %s @0x%" PRIxPTR " in state '%s', sp=0x%x, worker id=%d" PRIxPTR, scheduled_task->name, (uintptr_t)scheduled_task, scheduled_task->state->name, scheduled_task->user.rust_sp, id); reap_dead_tasks(id); } DLOG(this, dom, "terminated scheduler loop, reaping dead tasks ..."); while (dead_tasks.length() > 0) { DLOG(this, dom, "waiting for %d dead tasks to become dereferenced, " "scheduler yielding ...", dead_tasks.length()); log_state(); lock.unlock(); sync::yield(); lock.lock(); reap_dead_tasks(id); } DLOG(this, dom, "finished main-loop %d", id); lock.unlock(); }
rust_sched_loop_state rust_sched_loop::run_single_turn() { DLOG(this, task, "scheduler %d resuming ...", id); lock.lock(); if (!should_exit) { assert(dead_task == NULL && "Tasks should only die after running"); DLOG(this, dom, "worker %d, number_of_live_tasks = %d", id, number_of_live_tasks()); rust_task *scheduled_task = schedule_task(); if (scheduled_task == NULL) { log_state(); DLOG(this, task, "all tasks are blocked, scheduler id %d yielding ...", id); lock.unlock(); return sched_loop_state_block; } scheduled_task->assert_is_running(); DLOG(this, task, "activating task %s 0x%" PRIxPTR ", state: %s", scheduled_task->name, (uintptr_t)scheduled_task, state_name(scheduled_task->get_state())); place_task_in_tls(scheduled_task); DLOG(this, task, "Running task %p on worker %d", scheduled_task, id); activate(scheduled_task); DLOG(this, task, "returned from task %s @0x%" PRIxPTR " in state '%s', worker id=%d" PRIxPTR, scheduled_task->name, (uintptr_t)scheduled_task, state_name(scheduled_task->get_state()), id); reap_dead_tasks(); lock.unlock(); return sched_loop_state_keep_going; } else { assert(running_tasks.is_empty() && "Should have no running tasks"); assert(blocked_tasks.is_empty() && "Should have no blocked tasks"); assert(dead_task == NULL && "Should have no dead tasks"); DLOG(this, dom, "finished main-loop %d", id); lock.unlock(); assert(!extra_c_stack); if (cached_c_stack) { destroy_exchange_stack(kernel->region(), cached_c_stack); cached_c_stack = NULL; } assert(!extra_big_stack); if (cached_big_stack) { destroy_exchange_stack(kernel->region(), cached_big_stack); cached_big_stack = NULL; } sched->release_task_thread(); return sched_loop_state_exit; } }
/** * 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_task_thread::start_main_loop() { lock.lock(); DLOG(this, dom, "started domain loop %d", id); while (!should_exit) { DLOG(this, dom, "worker %d, number_of_live_tasks = %d", id, number_of_live_tasks()); rust_task *scheduled_task = schedule_task(); if (scheduled_task == NULL) { log_state(); DLOG(this, task, "all tasks are blocked, scheduler id %d yielding ...", id); lock.wait(); reap_dead_tasks(); DLOG(this, task, "scheduler %d resuming ...", id); continue; } I(this, scheduled_task->running()); DLOG(this, task, "activating task %s 0x%" PRIxPTR ", sp=0x%" PRIxPTR ", state: %s", scheduled_task->name, (uintptr_t)scheduled_task, scheduled_task->user.rust_sp, scheduled_task->state->name); place_task_in_tls(scheduled_task); DLOG(this, task, "Running task %p on worker %d", scheduled_task, id); activate(scheduled_task); DLOG(this, task, "returned from task %s @0x%" PRIxPTR " in state '%s', sp=0x%x, worker id=%d" PRIxPTR, scheduled_task->name, (uintptr_t)scheduled_task, scheduled_task->state->name, scheduled_task->user.rust_sp, id); reap_dead_tasks(); } A(this, newborn_tasks.is_empty(), "Should have no newborn tasks"); 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_tasks.is_empty(), "Should have no dead tasks"); DLOG(this, dom, "finished main-loop %d", id); lock.unlock(); }