67 lines
2.9 KiB
C++
67 lines
2.9 KiB
C++
|
#include "ultramodern.hpp"
|
||
|
|
||
|
void ultramodern::run_next_thread(RDRAM_ARG1) {
|
||
|
if (thread_queue_empty(PASS_RDRAM running_queue)) {
|
||
|
throw std::runtime_error("No threads left to run!\n");
|
||
|
}
|
||
|
|
||
|
OSThread* to_run = TO_PTR(OSThread, thread_queue_pop(PASS_RDRAM running_queue));
|
||
|
debug_printf("[Scheduling] Resuming execution of thread %d\n", to_run->id);
|
||
|
to_run->context->running.signal();
|
||
|
}
|
||
|
|
||
|
void ultramodern::schedule_running_thread(RDRAM_ARG PTR(OSThread) t_) {
|
||
|
debug_printf("[Scheduling] Adding thread %d to the running queue\n", TO_PTR(OSThread, t_)->id);
|
||
|
thread_queue_insert(PASS_RDRAM running_queue, t_);
|
||
|
TO_PTR(OSThread, t_)->state = OSThreadState::QUEUED;
|
||
|
}
|
||
|
|
||
|
void ultramodern::check_running_queue(RDRAM_ARG1) {
|
||
|
// Check if there are any threads in the running queue.
|
||
|
if (!thread_queue_empty(PASS_RDRAM running_queue)) {
|
||
|
// Check if the highest priority thread in the queue is higher priority than the current thread.
|
||
|
OSThread* next_thread = TO_PTR(OSThread, ultramodern::thread_queue_peek(PASS_RDRAM running_queue));
|
||
|
OSThread* self = TO_PTR(OSThread, ultramodern::this_thread());
|
||
|
if (next_thread->priority > self->priority) {
|
||
|
ultramodern::thread_queue_pop(PASS_RDRAM running_queue);
|
||
|
// Swap to the higher priority thread.
|
||
|
ultramodern::swap_to_thread(PASS_RDRAM next_thread);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void ultramodern::swap_to_thread(RDRAM_ARG OSThread *to) {
|
||
|
debug_printf("[Scheduling] Thread %d giving execution to thread %d\n", TO_PTR(OSThread, ultramodern::this_thread())->id, to->id);
|
||
|
// Insert this thread in the running queue.
|
||
|
thread_queue_insert(PASS_RDRAM running_queue, ultramodern::this_thread());
|
||
|
TO_PTR(OSThread, ultramodern::this_thread())->state = OSThreadState::QUEUED;
|
||
|
// Unpause the target thread and wait for this one to be unpaused.
|
||
|
ultramodern::resume_thread(to);
|
||
|
ultramodern::wait_for_resumed(PASS_RDRAM1);
|
||
|
}
|
||
|
|
||
|
void ultramodern::wait_for_resumed(RDRAM_ARG1) {
|
||
|
TO_PTR(OSThread, ultramodern::this_thread())->context->running.wait();
|
||
|
// If this thread was marked to be destroyed by another thre, destroy it again from its own context.
|
||
|
// This will actually destroy the thread instead of just marking it to be destroyed.
|
||
|
if (TO_PTR(OSThread, ultramodern::this_thread())->destroyed) {
|
||
|
osDestroyThread(PASS_RDRAM NULLPTR);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void ultramodern::resume_thread(OSThread *t) {
|
||
|
if (t->state != OSThreadState::QUEUED) {
|
||
|
assert(false && "Threads should only be resumed from the queued state!");
|
||
|
}
|
||
|
t->state = OSThreadState::RUNNING;
|
||
|
t->context->running.signal();
|
||
|
}
|
||
|
|
||
|
extern "C" void pause_self(RDRAM_ARG1) {
|
||
|
while (true) {
|
||
|
// Wait until an external message arrives, then allow the next thread to run.
|
||
|
ultramodern::wait_for_external_message(PASS_RDRAM1);
|
||
|
ultramodern::check_running_queue(PASS_RDRAM1);
|
||
|
}
|
||
|
}
|