From b00f6d6217bc61feeadbd835ef2d5578a1be72ec Mon Sep 17 00:00:00 2001 From: Xnoe Date: Sat, 18 Jun 2022 17:45:16 +0100 Subject: [PATCH] Added multiple threads per process --- src/common/syscalls.h | 4 ++- src/kernel/global.cpp | 1 + src/kernel/global.h | 2 ++ src/kernel/idt.cpp | 70 +++++++++++++++++++++----------------- src/kernel/kernel.cpp | 8 +++-- src/kernel/process.cpp | 60 +++++++++++++++++++------------- src/kernel/process.h | 25 +++++++++----- src/programs/world/world.c | 42 ++++++++++++++++++----- 8 files changed, 138 insertions(+), 74 deletions(-) diff --git a/src/common/syscalls.h b/src/common/syscalls.h index 7ad7933..6993c39 100644 --- a/src/common/syscalls.h +++ b/src/common/syscalls.h @@ -26,4 +26,6 @@ syscall_hdlr_0(uint32_t, getInitPages, "20"); syscall_hdlr_0(uint32_t, getCurrentTerminalWidth, "21"); syscall_hdlr_0(uint32_t, getCurrentTerminalHeight, "22"); -syscall_hdlr_1(uint32_t, getProcessState, "23", uint32_t, PID); \ No newline at end of file +syscall_hdlr_1(uint32_t, getProcessState, "23", uint32_t, PID); + +syscall_hdlr_1(void, spawnThread, "24", uint32_t, functionPointer); \ No newline at end of file diff --git a/src/kernel/global.cpp b/src/kernel/global.cpp index 785553a..68b3e77 100644 --- a/src/kernel/global.cpp +++ b/src/kernel/global.cpp @@ -4,6 +4,7 @@ namespace Global { Allocator* allocator = 0; Kernel* kernel = 0; Process* currentProc = 0; + Thread* currentThread = 0; tss_struct* tss = 0; bool currentProcValid = false; uint32_t milliseconds_elapsed = 0; diff --git a/src/kernel/global.h b/src/kernel/global.h index de1df7a..a2ee118 100644 --- a/src/kernel/global.h +++ b/src/kernel/global.h @@ -6,6 +6,7 @@ class Kernel; class Allocator; class Process; +class Thread; struct tss_struct; class ReadWriter; @@ -13,6 +14,7 @@ namespace Global { extern Allocator* allocator; extern Kernel* kernel; extern Process* currentProc; + extern Thread* currentThread; extern tss_struct* tss; extern bool currentProcValid; extern uint32_t milliseconds_elapsed; diff --git a/src/kernel/idt.cpp b/src/kernel/idt.cpp index 1e1bbbe..63beafd 100644 --- a/src/kernel/idt.cpp +++ b/src/kernel/idt.cpp @@ -84,15 +84,15 @@ void context_switch(frame_struct* frame) { asm ("cli"); // Disable interrupts whilst handling the context switch. - xnoe::linkedlist* processes = &Global::kernel->processes; + xnoe::linkedlist* threads = &Global::kernel->threads; - if (!processes->start) { + if (!threads->start) { Global::kernel->terminal->printf("[FATAL] No more processes! Halting!\n"); while (1) asm ("hlt"); } if (Global::currentProcValid) - Global::currentProc->kernelStackPtr = frame->new_esp; + Global::currentThread->kernelStackPtr = frame->new_esp; // This cursed bit of code first determines if the processes list is longer than 1 and if it is // - Determines if it has 2 or more elements @@ -100,40 +100,41 @@ void context_switch(frame_struct* frame) { // - If it has more than two, add the start to the end then set start to the second element uint32_t count = 0; do { - if (count++ == processes->length) + if (count++ == threads->length) return; - if (Global::currentProc) { - if (processes->start->next != 0) { - if (processes->end->prev == processes->start) { - xnoe::linkedlistelem* tmp = processes->start; - processes->start = processes->end; - processes->end = tmp; + if (Global::currentThread) { + if (threads->start->next != 0) { + if (threads->end->prev == threads->start) { + xnoe::linkedlistelem* tmp = threads->start; + threads->start = threads->end; + threads->end = tmp; - processes->start->prev = 0; - processes->end->next = 0; - processes->end->prev = processes->start; - processes->start->next = processes->end; + threads->start->prev = 0; + threads->end->next = 0; + threads->end->prev = threads->start; + threads->start->next = threads->end; } else { - processes->end->next = processes->start; - processes->start = processes->start->next; - processes->start->prev = 0; - xnoe::linkedlistelem* tmp = processes->end; - processes->end = processes->end->next; - processes->end->next = 0; - processes->end->prev = tmp; + threads->end->next = threads->start; + threads->start = threads->start->next; + threads->start->prev = 0; + xnoe::linkedlistelem* tmp = threads->end; + threads->end = threads->end->next; + threads->end->next = 0; + threads->end->prev = tmp; } } } - Global::currentProc = processes->start->elem; - } while (Global::currentProc->state != Running); + Global::currentThread = threads->start->elem; + Global::currentProc = threads->start->elem->parent; + } while (Global::currentThread->state != Running); // Select the next processes page directory - frame->new_cr3 = Global::currentProc->PD->phys_addr; + frame->new_cr3 = Global::currentThread->parent->PD->phys_addr; // Restore kernelStackPtr of the new process. - frame->new_esp = Global::currentProc->kernelStackPtr; + frame->new_esp = Global::currentThread->kernelStackPtr; - Global::tss->esp0 = Global::currentProc->kernelStackPtrDefault; + Global::tss->esp0 = Global::currentThread->kernelStackPtrDefault; // Set the current proc to valid Global::currentProcValid = true; @@ -171,8 +172,8 @@ namespace Timer { } } -void awaken(frame_struct* frame, Process* p) { - p->state = Running; +void awaken(frame_struct* frame, Thread* t) { + t->state = Running; } void syscall(frame_struct* frame) { @@ -351,8 +352,8 @@ void syscall(frame_struct* frame) { } case 18: { // sleep - Global::currentProc->state = Suspended; - Timer::register_event(frame->ebx, &awaken, (void*)Global::currentProc, true); + Global::currentThread->state = Suspended; + Timer::register_event(frame->ebx, &awaken, (void*)Global::currentThread, true); context_switch(frame); break; } @@ -375,11 +376,18 @@ void syscall(frame_struct* frame) { xnoe::maybe p = Global::kernel->pid_map->get(frame->ebx); if (p.is_ok()) { Process* proc = p.get(); - rval = proc->state; + //rval = proc->state; } break; } + case 24: { // Spawn Thread + Thread* thread = new Thread(Global::currentProc); + thread->initKernelStack(frame->ebx, thread->stack); + Global::kernel->threads.append(thread); + break; + } + default: break; } diff --git a/src/kernel/kernel.cpp b/src/kernel/kernel.cpp index fbca1f2..73c7894 100644 --- a/src/kernel/kernel.cpp +++ b/src/kernel/kernel.cpp @@ -25,7 +25,7 @@ Process* Kernel::createProcess(ReadWriter* file) { this->pid_map->set(currentPID, p); currentPID++; - this->processes.append(p); + this->threads.append(p->threads.start->elem); return p; } @@ -39,7 +39,11 @@ Process* Kernel::createProcess(ReadWriter* file, ReadWriter* stdout) { void Kernel::destroyProcess(Process* p) { if (Global::currentProc == p) Global::currentProcValid = false; - this->processes.remove(p); + xnoe::linkedlistelem* currentThread = p->threads.start; + while (currentThread) { + this->threads.remove(currentThread->elem); + currentThread = currentThread->next; + } this->pid_map->remove(p->PID); delete p; } diff --git a/src/kernel/process.cpp b/src/kernel/process.cpp index 346ed18..99df2f2 100644 --- a/src/kernel/process.cpp +++ b/src/kernel/process.cpp @@ -21,8 +21,6 @@ Process::Process(uint32_t PID, void* stack, PageDirectory* page_directory, PageM this->PID = PID; this->page_remaining = 0; this->last_page_pointer = virt_alloc_base; - this->stack = stack; - this->state = Running; } Process::Process(uint32_t PID) @@ -30,9 +28,6 @@ Process::Process(uint32_t PID) this->PID = PID; this->page_remaining = 0; this->last_page_pointer = 0; - this->stack = this->allocate(0x8000); - this->kernelStackPtr = (new uint8_t[0x4000]) + 0x4000; - this->state = Running; this->file_handlers = new xnoe::dynarray(8); } @@ -41,12 +36,9 @@ Process::Process(uint32_t PID, PageDirectory* inherit, uint32_t inheritBase, Rea this->stdout = 0; this->stdin = 0; - this->firstRun = true; - this->PID = PID; this->page_remaining = 0; this->last_page_pointer = 0; - this->state = Running; this->file_handlers = new xnoe::dynarray(8); @@ -56,17 +48,14 @@ Process::Process(uint32_t PID, PageDirectory* inherit, uint32_t inheritBase, Rea uint32_t filesize = filereader->size(); uint8_t* program_data = this->allocate(filesize + 12) + 12; - uint8_t* argenvarea = this->allocate(0x2000); - - this->stack = this->allocate(0x8000); - this->kernelStackPtr = (new uint8_t[0x4000]) + 0x4000; - this->kernelStackPtrDefault = this->kernelStackPtr; + Thread* thread = new Thread(this); uint32_t pCR3; asm ("mov %%cr3, %0" : "=a" (pCR3) :); this->PD->select(); - uint32_t* stack = this->stack + 0x8000; + uint32_t* stack = thread->stack + 0x8000; + uint8_t* argenvarea = this->allocate(0x2000); uint32_t argenv = argenvarea + 0x2000; for (int i=argc; i>0; i--) { char* s = argv[i-1]; @@ -79,14 +68,39 @@ Process::Process(uint32_t PID, PageDirectory* inherit, uint32_t inheritBase, Rea *(--stack) = argc; - // We also need to initialise ESP and the stack + filereader->seek(0); + filereader->read(filesize, program_data); + + asm ("mov %0, %%cr3" : : "r" (pCR3)); + + thread->initKernelStack(program_data, stack); + + this->threads.append(thread); +} + +Thread::Thread(Process* parent) { + this->parent = parent; + + this->stack = this->parent->allocate(0x8000); + this->kernelStackPtr = (new uint8_t[0x4000]) + 0x4000; + this->kernelStackPtrDefault = this->kernelStackPtr; +} + +Thread::~Thread() { + delete kernelStackPtr; +} + +void Thread::initKernelStack(void* entryPoint, void* esp) { + uint32_t pCR3; + asm ("mov %%cr3, %0" : "=a" (pCR3) :); + this->parent->PD->select(); uint32_t* stack32 = ((uint32_t)this->kernelStackPtr); *(--stack32) = 0x23; // SS - *(--stack32) = ((uint32_t)stack); // ESP + *(--stack32) = ((uint32_t)esp); // ESP *(--stack32) = 0x200; // EFLAGS *(--stack32) = 27; // CS - *(--stack32) = (uint32_t)program_data; // EIP - *(--stack32) = ((uint32_t)stack); // EBP + *(--stack32) = (uint32_t)entryPoint; // EIP + *(--stack32) = ((uint32_t)esp); // EBP uint32_t rEBP = stack32; @@ -100,10 +114,6 @@ Process::Process(uint32_t PID, PageDirectory* inherit, uint32_t inheritBase, Rea *(--stack32) = 0; // EDI this->kernelStackPtr = stack32; - - filereader->seek(0); - filereader->read(filesize, program_data); - asm ("mov %0, %%cr3" : : "r" (pCR3)); } @@ -127,7 +137,11 @@ Process::~Process() { delete r.get(); } - delete kernelStackPtr; + xnoe::linkedlistelem* currentThread = threads.start; + while (currentThread) { + delete currentThread->elem; + currentThread = currentThread->next; + } } void* Process::allocate(uint32_t size) { diff --git a/src/kernel/process.h b/src/kernel/process.h index aaf03b8..18ad990 100644 --- a/src/kernel/process.h +++ b/src/kernel/process.h @@ -12,6 +12,22 @@ #include "datatypes/dynarray.h" #include "filesystem/fstree.h" +class Process; +class Thread { +public: + void* stack; + void* kernelStackPtr; + void* kernelStackPtrDefault; + Process* parent; + ProcessState state; + bool firstRun; + + Thread(Process* parent); + ~Thread(); + + void Thread::initKernelStack(void* entryPoint, void* esp); +}; + struct AllocTracker { void* page_base; uint32_t page_size; @@ -25,8 +41,6 @@ private: uint32_t last_page_pointer; uint32_t page_remaining; - void* stack; - // List of pages this process has allocated xnoe::linkedlist allocations; @@ -40,15 +54,10 @@ public: uint32_t PID; uint32_t esp; - void* kernelStackPtr; - void* kernelStackPtrDefault; - ReadWriter* stdout; ReadWriter* stdin; - bool firstRun; - - ProcessState state; + xnoe::linkedlist threads; Process(uint32_t PID, void* stack, PageDirectory* page_directory, PageMap* phys, PageMap* virt, uint32_t virt_alloc_base); Process(uint32_t PID); diff --git a/src/programs/world/world.c b/src/programs/world/world.c index ea255c7..a1b8dda 100644 --- a/src/programs/world/world.c +++ b/src/programs/world/world.c @@ -151,11 +151,38 @@ bool strcmpcnt(int count, char* a, char* b) { return true; } +procbuffer b1; +procbuffer b2; + +int bufferWidth; + +void displayBuffer1() { + char c[128]; + int succ=0; + while (1) { + if (b1.process) + if (succ = read(128, b1.stdout, c)) + writeCountToBuf(succ, c, &b1); + displayBuf(&b1, 2, 2); + } +} + +void displayBuffer2() { + char c[128]; + int succ=0; + while (1) { + if (b2.process) + if (succ = read(128, b2.stdout, c)) + writeCountToBuf(succ, c, &b2); + displayBuf(&b2, bufferWidth+4, 2); + } +} + int main() { int width = getCurrentTerminalWidth(); int height = getCurrentTerminalHeight(); - int bufferWidth = (width - 4) / 2; + bufferWidth = (width - 4) / 2; int bufferHeight = (height - 4); bindToKeyboard(); @@ -201,7 +228,7 @@ int main() { uint32_t p2in = bindStdin(p2); fclose(program); - procbuffer b1 = { + b1 = (procbuffer) { .buffer = malloc(bufferWidth * bufferHeight), .x = 0, .y = 0, @@ -212,7 +239,7 @@ int main() { .height = bufferHeight }; - procbuffer b2 = { + b2 = (procbuffer) { .buffer = malloc(bufferWidth * bufferHeight), .x = 0, .y = 0, @@ -223,6 +250,9 @@ int main() { .height = bufferHeight }; + spawnThread(&displayBuffer1); + spawnThread(&displayBuffer2); + procbuffer* selectedBuf = &b1; writeStrToBuf("XoSH (XOS SHell) v0.0.1\nPress : to use commands.\n :help for help.\n", &b1); @@ -230,9 +260,6 @@ int main() { while (1) { char c[128]; int succ = 0; - if (b1.process) - if (succ = read(128, b1.stdout, c)) - writeCountToBuf(succ, c, &b1); if (b2.process) if (succ = read(128, b2.stdout, c)) writeCountToBuf(succ, c, &b2); @@ -309,8 +336,5 @@ int main() { write(1, selectedBuf->stdin, c); } } - - displayBuf(&b1, 2, 2); - displayBuf(&b2, bufferWidth+4, 2); } } \ No newline at end of file