Rework scheduler to store the current thread separately.

This works better with the sleep thread and lets us check state
transitions more easily.
This commit is contained in:
Drew Galbraith 2023-05-29 22:54:22 -07:00
parent 656687b183
commit 3fee5ac9d7
2 changed files with 46 additions and 27 deletions

View File

@ -44,16 +44,22 @@ class LinkedList {
return ret;
}
T CycleFront() {
/*
* Returns the front item in the list and pushes the passed item to the back.
*
* Done in one function to avoid a memory alloc/dealloc during scheduling.
**/
T CycleFront(const T& new_item) {
if (size_ == 0 || front_ == nullptr) {
panic("Cycling empty list");
}
T ret = front_->item;
front_->item = new_item;
if (size_ == 1) {
return front_->item;
return ret;
}
T ret = front_->item;
ListItem* old_front = front_;
ListItem* iter = front_;
front_ = front_->next;

View File

@ -22,13 +22,14 @@ class Scheduler {
Scheduler() {
SharedPtr<Process> root = Process::RootProcess();
sleep_thread_ = root->GetThread(0);
runnable_threads_.PushBack(sleep_thread_);
proc_list_.PushBack(Process::RootProcess());
// TODO: Implement a separate sleep thread?
current_thread_ = sleep_thread_;
proc_list_.PushBack(root);
}
void Enable() { enabled_ = true; }
Process& CurrentProcess() { return CurrentThread().process(); }
Thread& CurrentThread() { return *runnable_threads_.PeekFront(); }
Thread& CurrentThread() { return *current_thread_; }
void InsertProcess(Process* process) { proc_list_.PushBack(process); }
void Enqueue(Thread* thread) { runnable_threads_.PushBack(thread); }
@ -39,35 +40,45 @@ class Scheduler {
}
asm volatile("cli");
SharedPtr<Thread> prev;
if (CurrentThread().GetState() == Thread::RUNNING) {
prev = runnable_threads_.CycleFront();
prev->SetState(Thread::RUNNABLE);
} else {
// This technically is a memory operation but should only occur when a
// thread is blocking so may be ok?
prev = runnable_threads_.PopFront();
}
SharedPtr<Thread> prev = current_thread_;
SharedPtr<Thread> next;
if (runnable_threads_.size() == 0) {
next = sleep_thread_;
DumpProcessStates(proc_list_);
if (prev == sleep_thread_) {
if (runnable_threads_.size() == 0) {
// Continue sleeping.
return;
} else {
// FIXME: Memory operation.
next = runnable_threads_.PopFront();
prev->SetState(Thread::RUNNABLE);
}
} else {
next = runnable_threads_.PeekFront();
// Normal thread running.
if (prev->GetState() == Thread::RUNNING) {
if (runnable_threads_.size() == 0) {
// This thread can continue.
return;
}
prev->SetState(Thread::RUNNABLE);
next = runnable_threads_.CycleFront(prev);
} else {
// Thread blocked/exited.
if (runnable_threads_.size() == 0) {
next = sleep_thread_;
dbgln("Sleeping");
DumpProcessStates(proc_list_);
} else {
// FIXME: Memory operation.
next = runnable_threads_.PopFront();
}
}
}
if (next->GetState() != Thread::RUNNABLE) {
panic("Non-runnable thread in the queue");
}
// Needs to be before the next == prev check
// otherwise the active thread will be RUNNABLE instead of RUNNING.
next->SetState(Thread::RUNNING);
if (next == prev) {
dbgln("No next thread, continue");
return;
}
next->SetState(Thread::RUNNING);
current_thread_ = next;
context_switch(prev->Rsp0Ptr(), next->Rsp0Ptr());
@ -78,6 +89,8 @@ class Scheduler {
bool enabled_ = false;
// TODO: move this to a separate process manager class.
LinkedList<SharedPtr<Process>> proc_list_;
SharedPtr<Thread> current_thread_;
LinkedList<SharedPtr<Thread>> runnable_threads_;
SharedPtr<Thread> sleep_thread_;