Add thread and process states.

Add a thread exit call.
This commit is contained in:
Drew Galbraith 2023-05-29 13:51:00 -07:00
parent 8d87791fa2
commit a06c9dced4
8 changed files with 78 additions and 9 deletions

View File

@ -15,7 +15,7 @@ add_subdirectory(sys)
add_custom_command( add_custom_command(
OUTPUT disk.img OUTPUT disk.img
COMMAND sudo sh ../scripts/build_image.sh disk.img COMMAND sudo sh ../scripts/build_image.sh disk.img
DEPENDS zion DEPENDS zion test
USES_TERMINAL USES_TERMINAL
) )

View File

@ -2,7 +2,7 @@
#include <stdint.h> #include <stdint.h>
#define Z_DEBUG_PRINT 100 #define Z_THREAD_EXIT 0x01
#define Z_DEBUG_PRINT 0x100
uint64_t ZDebug(const char* message);
uint64_t ZDebug(const char* message);

View File

@ -25,7 +25,7 @@ Process* Process::RootProcess() {
return proc; return proc;
} }
Process::Process(uint64_t elf_ptr) : id_(gNextId++) { Process::Process(uint64_t elf_ptr) : id_(gNextId++), state_(RUNNING) {
cr3_ = phys_mem::AllocatePage(); cr3_ = phys_mem::AllocatePage();
InitializePml4(cr3_); InitializePml4(cr3_);
CreateThread(elf_ptr); CreateThread(elf_ptr);
@ -60,3 +60,15 @@ Thread* Process::GetThread(uint64_t tid) {
panic("Bad thread access."); panic("Bad thread access.");
return nullptr; return nullptr;
} }
void Process::CheckState() {
ThreadEntry* entry = thread_list_front_;
while (entry != nullptr) {
if (entry->thread->GetState() != Thread::FINISHED) {
return;
}
entry = entry->next;
}
state_ = FINISHED;
}

View File

@ -7,6 +7,12 @@ class Thread;
class Process { class Process {
public: public:
enum State {
UNSPECIFIED,
SETUP,
RUNNING,
FINISHED,
};
// Caller takes ownership of returned process. // Caller takes ownership of returned process.
static Process* RootProcess(); static Process* RootProcess();
Process(uint64_t elf_ptr); Process(uint64_t elf_ptr);
@ -17,10 +23,17 @@ class Process {
void CreateThread(uint64_t elf_ptr); void CreateThread(uint64_t elf_ptr);
Thread* GetThread(uint64_t tid); Thread* GetThread(uint64_t tid);
// Checks the state of all child threads and transitions to
// finished if all have finished.
void CheckState();
State GetState() { return state_; }
private: private:
Process(uint64_t id, uint64_t cr3) : id_(id), cr3_(cr3) {} Process(uint64_t id, uint64_t cr3) : id_(id), cr3_(cr3) {}
uint64_t id_; uint64_t id_;
uint64_t cr3_; uint64_t cr3_;
State state_;
uint64_t next_thread_id_ = 0; uint64_t next_thread_id_ = 0;

View File

@ -34,6 +34,15 @@ class ProcList {
}; };
} }
void DumpProcessStates() {
ProcEntry* p = front_;
dbgln("Process States:");
while (p != nullptr) {
dbgln("%u: %u", p->proc->id(), p->proc->GetState());
p = p->next;
}
}
private: private:
struct ProcEntry { struct ProcEntry {
Process* proc; Process* proc;
@ -71,16 +80,26 @@ class Scheduler {
asm volatile("cli"); asm volatile("cli");
if (current_thread_->next_thread_ == nullptr) { if (current_thread_->next_thread_ == nullptr) {
dbgln("No next thread, continue"); if (current_thread_->GetState() == Thread::RUNNING) {
return; dbgln("No next thread, continue");
return;
} else {
proc_list_.DumpProcessStates();
panic("FIXME: Implement Sleep");
}
} }
Thread* prev = current_thread_; Thread* prev = current_thread_;
current_thread_ = current_thread_->next_thread_; current_thread_ = current_thread_->next_thread_;
prev->next_thread_ = nullptr; prev->next_thread_ = nullptr;
if (prev->pid() != 0) { if (prev->pid() != 0 && prev->GetState() == Thread::RUNNING) {
prev->SetState(Thread::RUNNABLE);
Enqueue(prev); Enqueue(prev);
} }
if (current_thread_->GetState() != Thread::RUNNABLE) {
panic("Non-runnable thread in the queue");
}
current_thread_->SetState(Thread::RUNNING);
context_switch(prev->Rsp0Ptr(), current_thread_->Rsp0Ptr()); context_switch(prev->Rsp0Ptr(), current_thread_->Rsp0Ptr());
asm volatile("sti"); asm volatile("sti");

View File

@ -47,3 +47,10 @@ void Thread::Init() {
SetRsp0(rsp0_start_); SetRsp0(rsp0_start_);
jump_user_space(rip, rsp); jump_user_space(rip, rsp);
} }
void Thread::Exit() {
dbgln("[%u.%u] Exiting", pid(), id_);
state_ = FINISHED;
process_->CheckState();
sched::Yield();
}

View File

@ -7,6 +7,14 @@ class Process;
class Thread { class Thread {
public: public:
enum State {
UNSPECIFIED,
CREATED,
RUNNING,
RUNNABLE,
BLOCKED,
FINISHED,
};
static Thread* RootThread(Process* root_proc); static Thread* RootThread(Process* root_proc);
explicit Thread(Process* proc, uint64_t tid, uint64_t elf_ptr); explicit Thread(Process* proc, uint64_t tid, uint64_t elf_ptr);
@ -22,6 +30,11 @@ class Thread {
// Called the first time the thread starts up. // Called the first time the thread starts up.
void Init(); void Init();
// State Management.
State GetState() { return state_; };
void SetState(State state) { state_ = state; }
void Exit();
// FIXME: Probably make this private. // FIXME: Probably make this private.
Thread* next_thread_; Thread* next_thread_;
@ -30,6 +43,7 @@ class Thread {
Thread(Process* proc) : process_(proc), id_(0) {} Thread(Process* proc) : process_(proc), id_(0) {}
Process* process_; Process* process_;
uint64_t id_; uint64_t id_;
State state_ = RUNNABLE;
uint64_t elf_ptr_; uint64_t elf_ptr_;

View File

@ -56,8 +56,12 @@ void InitSyscall() {
extern "C" void SyscallHandler(uint64_t call_id, char* message) { extern "C" void SyscallHandler(uint64_t call_id, char* message) {
Thread& thread = sched::CurrentThread(); Thread& thread = sched::CurrentThread();
switch (call_id) { switch (call_id) {
case Z_THREAD_EXIT:
thread.Exit();
panic("Returned from thread exit");
break;
case Z_DEBUG_PRINT: case Z_DEBUG_PRINT:
dbgln("[%u.%u] %s", thread.pid(), thread.tid(), message); dbgln("[%u.%u] [Debug] %s", thread.pid(), thread.tid(), message);
break; break;
default: default:
panic("Unhandled syscall number: %u", call_id); panic("Unhandled syscall number: %u", call_id);