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; 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) { if (size_ == 0 || front_ == nullptr) {
panic("Cycling empty list"); panic("Cycling empty list");
} }
T ret = front_->item;
front_->item = new_item;
if (size_ == 1) { if (size_ == 1) {
return front_->item; return ret;
} }
T ret = front_->item;
ListItem* old_front = front_; ListItem* old_front = front_;
ListItem* iter = front_; ListItem* iter = front_;
front_ = front_->next; front_ = front_->next;

View File

@ -22,13 +22,14 @@ class Scheduler {
Scheduler() { Scheduler() {
SharedPtr<Process> root = Process::RootProcess(); SharedPtr<Process> root = Process::RootProcess();
sleep_thread_ = root->GetThread(0); sleep_thread_ = root->GetThread(0);
runnable_threads_.PushBack(sleep_thread_); // TODO: Implement a separate sleep thread?
proc_list_.PushBack(Process::RootProcess()); current_thread_ = sleep_thread_;
proc_list_.PushBack(root);
} }
void Enable() { enabled_ = true; } void Enable() { enabled_ = true; }
Process& CurrentProcess() { return CurrentThread().process(); } 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 InsertProcess(Process* process) { proc_list_.PushBack(process); }
void Enqueue(Thread* thread) { runnable_threads_.PushBack(thread); } void Enqueue(Thread* thread) { runnable_threads_.PushBack(thread); }
@ -39,35 +40,45 @@ class Scheduler {
} }
asm volatile("cli"); asm volatile("cli");
SharedPtr<Thread> prev; SharedPtr<Thread> prev = current_thread_;
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> next; SharedPtr<Thread> next;
if (runnable_threads_.size() == 0) { if (prev == sleep_thread_) {
next = sleep_thread_; if (runnable_threads_.size() == 0) {
DumpProcessStates(proc_list_); // Continue sleeping.
return;
} else {
// FIXME: Memory operation.
next = runnable_threads_.PopFront();
prev->SetState(Thread::RUNNABLE);
}
} else { } 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) { if (next->GetState() != Thread::RUNNABLE) {
panic("Non-runnable thread in the queue"); 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) { next->SetState(Thread::RUNNING);
dbgln("No next thread, continue"); current_thread_ = next;
return;
}
context_switch(prev->Rsp0Ptr(), next->Rsp0Ptr()); context_switch(prev->Rsp0Ptr(), next->Rsp0Ptr());
@ -78,6 +89,8 @@ class Scheduler {
bool enabled_ = false; bool enabled_ = false;
// TODO: move this to a separate process manager class. // TODO: move this to a separate process manager class.
LinkedList<SharedPtr<Process>> proc_list_; LinkedList<SharedPtr<Process>> proc_list_;
SharedPtr<Thread> current_thread_;
LinkedList<SharedPtr<Thread>> runnable_threads_; LinkedList<SharedPtr<Thread>> runnable_threads_;
SharedPtr<Thread> sleep_thread_; SharedPtr<Thread> sleep_thread_;