Added multiple threads per process

This commit is contained in:
Xnoe 2022-06-18 17:45:16 +01:00
parent f3b1bfc5ef
commit b00f6d6217
Signed by: xnoe
GPG Key ID: 45AC398F44F0DAFE
8 changed files with 138 additions and 74 deletions

View File

@ -27,3 +27,5 @@ syscall_hdlr_0(uint32_t, getCurrentTerminalWidth, "21");
syscall_hdlr_0(uint32_t, getCurrentTerminalHeight, "22"); syscall_hdlr_0(uint32_t, getCurrentTerminalHeight, "22");
syscall_hdlr_1(uint32_t, getProcessState, "23", uint32_t, PID); syscall_hdlr_1(uint32_t, getProcessState, "23", uint32_t, PID);
syscall_hdlr_1(void, spawnThread, "24", uint32_t, functionPointer);

View File

@ -4,6 +4,7 @@ namespace Global {
Allocator* allocator = 0; Allocator* allocator = 0;
Kernel* kernel = 0; Kernel* kernel = 0;
Process* currentProc = 0; Process* currentProc = 0;
Thread* currentThread = 0;
tss_struct* tss = 0; tss_struct* tss = 0;
bool currentProcValid = false; bool currentProcValid = false;
uint32_t milliseconds_elapsed = 0; uint32_t milliseconds_elapsed = 0;

View File

@ -6,6 +6,7 @@
class Kernel; class Kernel;
class Allocator; class Allocator;
class Process; class Process;
class Thread;
struct tss_struct; struct tss_struct;
class ReadWriter; class ReadWriter;
@ -13,6 +14,7 @@ namespace Global {
extern Allocator* allocator; extern Allocator* allocator;
extern Kernel* kernel; extern Kernel* kernel;
extern Process* currentProc; extern Process* currentProc;
extern Thread* currentThread;
extern tss_struct* tss; extern tss_struct* tss;
extern bool currentProcValid; extern bool currentProcValid;
extern uint32_t milliseconds_elapsed; extern uint32_t milliseconds_elapsed;

View File

@ -84,15 +84,15 @@ void context_switch(frame_struct* frame) {
asm ("cli"); // Disable interrupts whilst handling the context switch. asm ("cli"); // Disable interrupts whilst handling the context switch.
xnoe::linkedlist<Process*>* processes = &Global::kernel->processes; xnoe::linkedlist<Thread*>* threads = &Global::kernel->threads;
if (!processes->start) { if (!threads->start) {
Global::kernel->terminal->printf("[FATAL] No more processes! Halting!\n"); Global::kernel->terminal->printf("[FATAL] No more processes! Halting!\n");
while (1) asm ("hlt"); while (1) asm ("hlt");
} }
if (Global::currentProcValid) 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 // 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 // - 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 // - If it has more than two, add the start to the end then set start to the second element
uint32_t count = 0; uint32_t count = 0;
do { do {
if (count++ == processes->length) if (count++ == threads->length)
return; return;
if (Global::currentProc) { if (Global::currentThread) {
if (processes->start->next != 0) { if (threads->start->next != 0) {
if (processes->end->prev == processes->start) { if (threads->end->prev == threads->start) {
xnoe::linkedlistelem<Process*>* tmp = processes->start; xnoe::linkedlistelem<Thread*>* tmp = threads->start;
processes->start = processes->end; threads->start = threads->end;
processes->end = tmp; threads->end = tmp;
processes->start->prev = 0; threads->start->prev = 0;
processes->end->next = 0; threads->end->next = 0;
processes->end->prev = processes->start; threads->end->prev = threads->start;
processes->start->next = processes->end; threads->start->next = threads->end;
} else { } else {
processes->end->next = processes->start; threads->end->next = threads->start;
processes->start = processes->start->next; threads->start = threads->start->next;
processes->start->prev = 0; threads->start->prev = 0;
xnoe::linkedlistelem<Process*>* tmp = processes->end; xnoe::linkedlistelem<Thread*>* tmp = threads->end;
processes->end = processes->end->next; threads->end = threads->end->next;
processes->end->next = 0; threads->end->next = 0;
processes->end->prev = tmp; threads->end->prev = tmp;
} }
} }
} }
Global::currentProc = processes->start->elem; Global::currentThread = threads->start->elem;
} while (Global::currentProc->state != Running); Global::currentProc = threads->start->elem->parent;
} while (Global::currentThread->state != Running);
// Select the next processes page directory // 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. // 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 // Set the current proc to valid
Global::currentProcValid = true; Global::currentProcValid = true;
@ -171,8 +172,8 @@ namespace Timer {
} }
} }
void awaken(frame_struct* frame, Process* p) { void awaken(frame_struct* frame, Thread* t) {
p->state = Running; t->state = Running;
} }
void syscall(frame_struct* frame) { void syscall(frame_struct* frame) {
@ -351,8 +352,8 @@ void syscall(frame_struct* frame) {
} }
case 18: { // sleep case 18: { // sleep
Global::currentProc->state = Suspended; Global::currentThread->state = Suspended;
Timer::register_event(frame->ebx, &awaken, (void*)Global::currentProc, true); Timer::register_event(frame->ebx, &awaken, (void*)Global::currentThread, true);
context_switch(frame); context_switch(frame);
break; break;
} }
@ -375,11 +376,18 @@ void syscall(frame_struct* frame) {
xnoe::maybe<Process*> p = Global::kernel->pid_map->get(frame->ebx); xnoe::maybe<Process*> p = Global::kernel->pid_map->get(frame->ebx);
if (p.is_ok()) { if (p.is_ok()) {
Process* proc = p.get(); Process* proc = p.get();
rval = proc->state; //rval = proc->state;
} }
break; break;
} }
case 24: { // Spawn Thread
Thread* thread = new Thread(Global::currentProc);
thread->initKernelStack(frame->ebx, thread->stack);
Global::kernel->threads.append(thread);
break;
}
default: default:
break; break;
} }

View File

@ -25,7 +25,7 @@ Process* Kernel::createProcess(ReadWriter* file) {
this->pid_map->set(currentPID, p); this->pid_map->set(currentPID, p);
currentPID++; currentPID++;
this->processes.append(p); this->threads.append(p->threads.start->elem);
return p; return p;
} }
@ -39,7 +39,11 @@ Process* Kernel::createProcess(ReadWriter* file, ReadWriter* stdout) {
void Kernel::destroyProcess(Process* p) { void Kernel::destroyProcess(Process* p) {
if (Global::currentProc == p) if (Global::currentProc == p)
Global::currentProcValid = false; Global::currentProcValid = false;
this->processes.remove(p); xnoe::linkedlistelem<Thread*>* currentThread = p->threads.start;
while (currentThread) {
this->threads.remove(currentThread->elem);
currentThread = currentThread->next;
}
this->pid_map->remove(p->PID); this->pid_map->remove(p->PID);
delete p; delete p;
} }

View File

@ -21,8 +21,6 @@ Process::Process(uint32_t PID, void* stack, PageDirectory* page_directory, PageM
this->PID = PID; this->PID = PID;
this->page_remaining = 0; this->page_remaining = 0;
this->last_page_pointer = virt_alloc_base; this->last_page_pointer = virt_alloc_base;
this->stack = stack;
this->state = Running;
} }
Process::Process(uint32_t PID) Process::Process(uint32_t PID)
@ -30,9 +28,6 @@ Process::Process(uint32_t PID)
this->PID = PID; this->PID = PID;
this->page_remaining = 0; this->page_remaining = 0;
this->last_page_pointer = 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<ReadWriter*>(8); this->file_handlers = new xnoe::dynarray<ReadWriter*>(8);
} }
@ -41,12 +36,9 @@ Process::Process(uint32_t PID, PageDirectory* inherit, uint32_t inheritBase, Rea
this->stdout = 0; this->stdout = 0;
this->stdin = 0; this->stdin = 0;
this->firstRun = true;
this->PID = PID; this->PID = PID;
this->page_remaining = 0; this->page_remaining = 0;
this->last_page_pointer = 0; this->last_page_pointer = 0;
this->state = Running;
this->file_handlers = new xnoe::dynarray<ReadWriter*>(8); this->file_handlers = new xnoe::dynarray<ReadWriter*>(8);
@ -56,17 +48,14 @@ Process::Process(uint32_t PID, PageDirectory* inherit, uint32_t inheritBase, Rea
uint32_t filesize = filereader->size(); uint32_t filesize = filereader->size();
uint8_t* program_data = this->allocate(filesize + 12) + 12; uint8_t* program_data = this->allocate(filesize + 12) + 12;
uint8_t* argenvarea = this->allocate(0x2000); Thread* thread = new Thread(this);
this->stack = this->allocate(0x8000);
this->kernelStackPtr = (new uint8_t[0x4000]) + 0x4000;
this->kernelStackPtrDefault = this->kernelStackPtr;
uint32_t pCR3; uint32_t pCR3;
asm ("mov %%cr3, %0" : "=a" (pCR3) :); asm ("mov %%cr3, %0" : "=a" (pCR3) :);
this->PD->select(); 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; uint32_t argenv = argenvarea + 0x2000;
for (int i=argc; i>0; i--) { for (int i=argc; i>0; i--) {
char* s = argv[i-1]; char* s = argv[i-1];
@ -79,14 +68,39 @@ Process::Process(uint32_t PID, PageDirectory* inherit, uint32_t inheritBase, Rea
*(--stack) = argc; *(--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); uint32_t* stack32 = ((uint32_t)this->kernelStackPtr);
*(--stack32) = 0x23; // SS *(--stack32) = 0x23; // SS
*(--stack32) = ((uint32_t)stack); // ESP *(--stack32) = ((uint32_t)esp); // ESP
*(--stack32) = 0x200; // EFLAGS *(--stack32) = 0x200; // EFLAGS
*(--stack32) = 27; // CS *(--stack32) = 27; // CS
*(--stack32) = (uint32_t)program_data; // EIP *(--stack32) = (uint32_t)entryPoint; // EIP
*(--stack32) = ((uint32_t)stack); // EBP *(--stack32) = ((uint32_t)esp); // EBP
uint32_t rEBP = stack32; uint32_t rEBP = stack32;
@ -100,10 +114,6 @@ Process::Process(uint32_t PID, PageDirectory* inherit, uint32_t inheritBase, Rea
*(--stack32) = 0; // EDI *(--stack32) = 0; // EDI
this->kernelStackPtr = stack32; this->kernelStackPtr = stack32;
filereader->seek(0);
filereader->read(filesize, program_data);
asm ("mov %0, %%cr3" : : "r" (pCR3)); asm ("mov %0, %%cr3" : : "r" (pCR3));
} }
@ -127,7 +137,11 @@ Process::~Process() {
delete r.get(); delete r.get();
} }
delete kernelStackPtr; xnoe::linkedlistelem<Thread*>* currentThread = threads.start;
while (currentThread) {
delete currentThread->elem;
currentThread = currentThread->next;
}
} }
void* Process::allocate(uint32_t size) { void* Process::allocate(uint32_t size) {

View File

@ -12,6 +12,22 @@
#include "datatypes/dynarray.h" #include "datatypes/dynarray.h"
#include "filesystem/fstree.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 { struct AllocTracker {
void* page_base; void* page_base;
uint32_t page_size; uint32_t page_size;
@ -25,8 +41,6 @@ private:
uint32_t last_page_pointer; uint32_t last_page_pointer;
uint32_t page_remaining; uint32_t page_remaining;
void* stack;
// List of pages this process has allocated // List of pages this process has allocated
xnoe::linkedlist<AllocTracker> allocations; xnoe::linkedlist<AllocTracker> allocations;
@ -40,15 +54,10 @@ public:
uint32_t PID; uint32_t PID;
uint32_t esp; uint32_t esp;
void* kernelStackPtr;
void* kernelStackPtrDefault;
ReadWriter* stdout; ReadWriter* stdout;
ReadWriter* stdin; ReadWriter* stdin;
bool firstRun; xnoe::linkedlist<Thread*> threads;
ProcessState state;
Process(uint32_t PID, void* stack, PageDirectory* page_directory, PageMap* phys, PageMap* virt, uint32_t virt_alloc_base); Process(uint32_t PID, void* stack, PageDirectory* page_directory, PageMap* phys, PageMap* virt, uint32_t virt_alloc_base);
Process(uint32_t PID); Process(uint32_t PID);

View File

@ -151,11 +151,38 @@ bool strcmpcnt(int count, char* a, char* b) {
return true; 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 main() {
int width = getCurrentTerminalWidth(); int width = getCurrentTerminalWidth();
int height = getCurrentTerminalHeight(); int height = getCurrentTerminalHeight();
int bufferWidth = (width - 4) / 2; bufferWidth = (width - 4) / 2;
int bufferHeight = (height - 4); int bufferHeight = (height - 4);
bindToKeyboard(); bindToKeyboard();
@ -201,7 +228,7 @@ int main() {
uint32_t p2in = bindStdin(p2); uint32_t p2in = bindStdin(p2);
fclose(program); fclose(program);
procbuffer b1 = { b1 = (procbuffer) {
.buffer = malloc(bufferWidth * bufferHeight), .buffer = malloc(bufferWidth * bufferHeight),
.x = 0, .x = 0,
.y = 0, .y = 0,
@ -212,7 +239,7 @@ int main() {
.height = bufferHeight .height = bufferHeight
}; };
procbuffer b2 = { b2 = (procbuffer) {
.buffer = malloc(bufferWidth * bufferHeight), .buffer = malloc(bufferWidth * bufferHeight),
.x = 0, .x = 0,
.y = 0, .y = 0,
@ -223,6 +250,9 @@ int main() {
.height = bufferHeight .height = bufferHeight
}; };
spawnThread(&displayBuffer1);
spawnThread(&displayBuffer2);
procbuffer* selectedBuf = &b1; procbuffer* selectedBuf = &b1;
writeStrToBuf("XoSH (XOS SHell) v0.0.1\nPress : to use commands.\n :help for help.\n", &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) { while (1) {
char c[128]; char c[128];
int succ = 0; int succ = 0;
if (b1.process)
if (succ = read(128, b1.stdout, c))
writeCountToBuf(succ, c, &b1);
if (b2.process) if (b2.process)
if (succ = read(128, b2.stdout, c)) if (succ = read(128, b2.stdout, c))
writeCountToBuf(succ, c, &b2); writeCountToBuf(succ, c, &b2);
@ -309,8 +336,5 @@ int main() {
write(1, selectedBuf->stdin, c); write(1, selectedBuf->stdin, c);
} }
} }
displayBuf(&b1, 2, 2);
displayBuf(&b2, bufferWidth+4, 2);
} }
} }