From 5ca2b6994a8fbc88d61204a646f79c3da761f348 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Lov=C3=A9n?= Date: Fri, 16 Dec 2016 19:22:33 +0100 Subject: [PATCH] [MULTITASKING] Processes --- kernel/boot/kmain.c | 30 ++++++++--- kernel/include/process.h | 34 +++++++++++++ kernel/include/thread.h | 4 ++ kernel/interrupts/interrupts.c | 2 + kernel/mem/vmm.c | 7 ++- kernel/proc/process.c | 91 ++++++++++++++++++++++++++++++++++ kernel/proc/scheduler.c | 13 ++++- kernel/proc/thread.c | 4 ++ 8 files changed, 177 insertions(+), 8 deletions(-) create mode 100644 kernel/include/process.h create mode 100644 kernel/proc/process.c diff --git a/kernel/boot/kmain.c b/kernel/boot/kmain.c index 8c23c98..de9ef35 100644 --- a/kernel/boot/kmain.c +++ b/kernel/boot/kmain.c @@ -4,12 +4,19 @@ #include #include #include +#include +#include void thread_function() { + char *str = (char *)0x10000; + str[0] = (char)((unsigned int)'0' + get_current_process()->pid); + str[1] = (char)((unsigned int)'0' + get_current_thread()->tid); + str[3] = '-'; + str[2] = '\0'; while(1) { - debug("%d", get_current_thread()->tid); + debug((char *)0x10000); schedule(); } } @@ -28,12 +35,23 @@ int kmain(uint64_t multiboot_magic, void *multiboot_data) gdt_init(); scheduler_init(); + process_t *p1 = process_spawn(0); + process_t *p2 = process_spawn(p1); - scheduler_insert(new_thread(thread_function)); - scheduler_insert(new_thread(thread_function)); - scheduler_insert(new_thread(thread_function)); - scheduler_insert(new_thread(thread_function)); - scheduler_insert(new_thread(thread_function)); + thread_t *t1 = new_thread(thread_function); + thread_t *t2 = new_thread(thread_function); + thread_t *t3 = new_thread(thread_function); + + process_attach(p1, t1); + process_attach(p2, t2); + process_attach(p1, t3); + + vmm_set_page(p1->P4, 0x10000, pmm_alloc(), PAGE_PRESENT | PAGE_WRITE); + vmm_set_page(p2->P4, 0x10000, pmm_alloc(), PAGE_PRESENT | PAGE_WRITE); + + scheduler_insert(t1); + scheduler_insert(t2); + scheduler_insert(t3); debug_info("BOOT COMPLETE\n"); schedule(); diff --git a/kernel/include/process.h b/kernel/include/process.h new file mode 100644 index 0000000..ccfad96 --- /dev/null +++ b/kernel/include/process.h @@ -0,0 +1,34 @@ +#pragma once +typedef struct process_st process_t; +#include +#include +#include + +typedef struct process_st +{ + uint64_t pid; + uint64_t state; + uint64_t status; + struct process_st *parent; + page_table *P4; + LIST(struct process_st, children); + LIST(struct process_st, siblings); + LIST(thread_t, threads); +} process_t; + +#define PROC_STATE_READY 1 +#define PROC_STATE_RUNNING 2 +#define PROC_STATE_ZOMBIE 3 +#define PROC_STATE_DONE 4 + +#define process_alive(proc) ((proc)->state == PROC_STATE_READY || (proc)->state == PROC_STATE_RUNNING) + +process_t *current_process; +#define get_current_process() (current_process) +#define set_current_process(proc) (current_process = (proc)) + +process_t *process_spawn(process_t *parent); +void process_attach(process_t *proc, thread_t *th); +void switch_process(process_t *proc); +void process_exit(process_t *proc, uint64_t status); +void process_free(process_t *proc); diff --git a/kernel/include/thread.h b/kernel/include/thread.h index b74f34b..abee69c 100644 --- a/kernel/include/thread.h +++ b/kernel/include/thread.h @@ -1,6 +1,8 @@ #pragma once +typedef struct thread_st thread_t; #include #include +#include #define THREAD_STACK_SIZE 0x1000-sizeof(thread_t) @@ -9,6 +11,8 @@ typedef struct thread_st uint64_t stack_pointer; // Top of the kernel stack for thread uint64_t tid; uint64_t state; + process_t *process; + LIST(struct thread_st, process_threads); LIST(struct thread_st, ready_queue); } thread_t; diff --git a/kernel/interrupts/interrupts.c b/kernel/interrupts/interrupts.c index d7e9b0d..6052948 100644 --- a/kernel/interrupts/interrupts.c +++ b/kernel/interrupts/interrupts.c @@ -63,6 +63,8 @@ registers_t *int_handler(registers_t *r) #ifndef NDEBUG thread_t *th = get_current_thread(); (void)th; + process_t *proc = get_current_process(); + (void)proc; asm("int_handler_breakpoint:"); #endif diff --git a/kernel/mem/vmm.c b/kernel/mem/vmm.c index 3912872..ff72a5a 100644 --- a/kernel/mem/vmm.c +++ b/kernel/mem/vmm.c @@ -22,7 +22,10 @@ page_table *vmm_new_P4() void vmm_set_P4(page_table *P4) { - write_cr3((uint64_t)P4); + if(P4) + write_cr3((uint64_t)P4); + else + write_cr3(V2P(&BootP4)); } void vmm_free_P4(page_table *P4) @@ -145,6 +148,8 @@ registers_t *page_fault_handler(registers_t *r) #ifndef NDEBUG thread_t *th = get_current_thread(); (void)th; + process_t *proc = get_current_process(); + (void)proc; asm("page_fault_breakpoint:"); #endif for(;;); diff --git a/kernel/proc/process.c b/kernel/proc/process.c new file mode 100644 index 0000000..8c4905c --- /dev/null +++ b/kernel/proc/process.c @@ -0,0 +1,91 @@ +#include +#include +#include +#include + +uint64_t pid = 1; +process_t *init_proc = 0; + +process_t *process_spawn(process_t *parent) +{ + process_t *proc = kcalloc(1, sizeof(process_t)); + proc->pid = pid++; + proc->parent = parent; + proc->P4 = vmm_new_P4(); + proc->state = PROC_STATE_READY; + + LIST_INIT(proc, children); + LIST_INIT(proc, siblings); + LIST_INIT(proc, threads); + + if(parent) + { + LIST_APPEND(parent->children, proc, siblings); + } + + if(proc->pid == 1) + init_proc = proc; + + return proc; +} + +void process_attach(process_t *proc, thread_t *th) +{ + LIST_APPEND(proc->threads, th, process_threads); + th->process = proc; +} + +void switch_process(process_t *proc) +{ + process_t *old = get_current_process(); + if(old) + { + if(old == proc) + return; + if(old->state == PROC_STATE_RUNNING) + old->state = PROC_STATE_READY; + } + set_current_process(proc); + + if(proc) + { + proc->state = PROC_STATE_RUNNING; + vmm_set_P4(proc->P4); + } + else + { + vmm_set_P4(0); + } +} + +void process_exit(process_t *proc, uint64_t status) +{ + proc->status = status; + LIST_FOREACH(proc->children, process_t, c, siblings) + { + // Make init process adopt orphaned children + LIST_REMOVE(proc->children, c, siblings); + c->parent = init_proc; + LIST_APPEND(init_proc->children, c, siblings); + } + proc->state = PROC_STATE_ZOMBIE; +} + +void process_free(process_t *proc) +{ + if(proc->state != PROC_STATE_ZOMBIE) + { + debug_error("Trying to free an unfinished process!\n"); + for(;;); + } + LIST_FOREACH(proc->threads, thread_t, th, process_threads) + { + while(th->state == THREAD_STATE_RUNNING || th->state == THREAD_STATE_READY) schedule(); + free_thread(th); + } + LIST_REMOVE(proc->parent->children, proc, siblings); + // Free page directory + vmm_free_P4(proc->P4); + // Free process structure + kfree(proc); +} diff --git a/kernel/proc/scheduler.c b/kernel/proc/scheduler.c index e4af472..d0d2363 100644 --- a/kernel/proc/scheduler.c +++ b/kernel/proc/scheduler.c @@ -41,15 +41,25 @@ void scheduler() thread_t *old = 0, *new = 0; if((old = get_last_thread())) { - if(old->state == THREAD_STATE_RUNNING) + if(old->state != THREAD_STATE_FINISHED && process_alive(old->process)) { old->state = THREAD_STATE_READY; scheduler_insert(old); + } else { + old->state = THREAD_STATE_FINISHED; } } + while(!(new = scheduler_next())); + + if(!process_alive(new->process)) + { + new->state = THREAD_STATE_FINISHED; + continue; + } new->state = THREAD_STATE_RUNNING; set_last_thread(new); + switch_process(new->process); switch_thread(scheduler_th, new); } } @@ -60,6 +70,7 @@ void schedule() thread_t *old = get_current_thread(); + switch_process(0); switch_thread(old, scheduler_th); } diff --git a/kernel/proc/thread.c b/kernel/proc/thread.c index 5f598db..221cdb4 100644 --- a/kernel/proc/thread.c +++ b/kernel/proc/thread.c @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -23,6 +24,7 @@ thread_t *new_thread(void (*func)(void)) th->stack_pointer = (uint64_t)&stack->RBP; LIST_INIT(th, ready_queue); + LIST_INIT(th, process_threads); return th; } @@ -42,6 +44,8 @@ void free_thread(thread_t *th) debug_error("Trying to free a live thread!\n"); for(;;); } + if(!LIST_EMPTY(th->process_threads)) + LIST_REMOVE(th->process->threads, th, process_threads); thread_stack_t *stack = incptr(th, -offsetof(thread_stack_t, tcb)); kfree(stack); }