diff options
Diffstat (limited to 'src/stem/task')
-rw-r--r-- | src/stem/task/idt.c | 6 | ||||
-rw-r--r-- | src/stem/task/syscall.c | 6 | ||||
-rw-r--r-- | src/stem/task/task.c | 108 | ||||
-rw-r--r-- | src/stem/task/task.h | 23 |
4 files changed, 126 insertions, 17 deletions
diff --git a/src/stem/task/idt.c b/src/stem/task/idt.c index 4866550..360ac91 100644 --- a/src/stem/task/idt.c +++ b/src/stem/task/idt.c @@ -95,7 +95,11 @@ void idt_irqHandler(struct registers regs) { } void idt_syscallHandler(struct registers regs) { - syscalls[regs.eax](®s); + if (syscalls[regs.eax] != 0) { + syscalls[regs.eax](®s); + } else { + PANIC("unhandled syscall"); + } } static void idt_setGate(uint8_t num, uint32_t base, uint16_t sel, uint8_t flags) { diff --git a/src/stem/task/syscall.c b/src/stem/task/syscall.c index 6964b34..0878b30 100644 --- a/src/stem/task/syscall.c +++ b/src/stem/task/syscall.c @@ -6,13 +6,15 @@ #define CALL2(name, scname) static void scname(struct registers* r) { \ r->eax = name(r->ebx, r->ecx); } +CALL0(thread_exit, thread_exit_sc); CALL0(tasking_switch, schedule_sc); +CALL1(process_exit, process_exit_sc); CALL1(monitor_write, printk_sc); int_callback syscalls[] = { - 0, //Syscall 0 will be thread_exit + thread_exit_sc, schedule_sc, 0, //Syscall 2 will be thread_sleep - 0, //Syscall 3 will be process_exit + process_exit_sc, printk_sc, 0 }; diff --git a/src/stem/task/task.c b/src/stem/task/task.c index 8ed5190..5ab001c 100644 --- a/src/stem/task/task.c +++ b/src/stem/task/task.c @@ -6,6 +6,12 @@ #define KSTACKSIZE 0x8000 +//Static routines for handling threads exiting and all cleanup +static void thread_exit_stackJmp(uint32_t reason); +static void thread_exit2(uint32_t reason); +static void thread_delete(struct thread *th); +static void process_delete(struct process *pr); + //From task_.asm extern uint32_t read_eip(); extern void task_idle(void*); @@ -28,15 +34,16 @@ void tasking_init(thread_entry whereToGo, void *data) { kernel_process->pagedir = kernel_pagedir; kernel_process->next = 0; current_thread = 0; - thread_new(kernel_process, task_idle, 0); + idle_thread = thread_new(kernel_process, task_idle, 0); + threads = 0; //Do not include idle thread in threads thread_new(kernel_process, whereToGo, data); sti(); monitor_write("Tasking starting\n"); tasking_switch(); } -static struct thread *thread_next() { //NOT OPTIMAL : will allocate time slices to idle thread even if busy - if (current_thread == 0) current_thread = threads; +static struct thread *thread_next() { + if (current_thread == 0 || current_thread == idle_thread) current_thread = threads; struct thread *ret = current_thread; while (1) { ret = ret->next; @@ -44,12 +51,13 @@ static struct thread *thread_next() { //NOT OPTIMAL : will allocate time slices if (thread_runnable(ret)) { return ret; } + if (ret == current_thread) return idle_thread; } } void tasking_switch() { - if (threads == 0) return; //no tasking yet - cli(); + if (threads == 0) PANIC("No more threads to run !"); + asm volatile("cli"); uint32_t esp, ebp, eip; @@ -89,9 +97,65 @@ void tasking_updateKernelPagetable(uint32_t idx, struct page_table *table, uint3 uint32_t tasking_handleException(struct registers *regs) { if (threads == 0) return 0; //No tasking yet + monitor_write("\nUnhandled exception : "); + char *exception_messages[] = {"Division By Zero","Debug","Non Maskable Interrupt","Breakpoint", + "Into Detected Overflow","Out of Bounds","Invalid Opcode","No Coprocessor", "Double Fault", + "Coprocessor Segment Overrun","Bad TSS","Segment Not Present","Stack Fault","General Protection Fault", + "Page Fault","Unknown Interrupt","Coprocessor Fault","Alignment Check","Machine Check"}; + monitor_write(exception_messages[regs->int_no]); + monitor_write("\nThread exiting.\n"); + thread_exit_stackJmp(EX_TH_EXCEPTION); return 0; } +void thread_sleep(uint32_t msecs) { + if (current_thread == 0) return; + current_thread->state = TS_SLEEPING; + current_thread->timeWait = timer_time() + msecs; + asm volatile("int $64" : : "a"(1)); +} + +void thread_exit2(uint32_t reason) { //See EX_TH_* defines in task.h + /* + * if reason == EX_TH_NORMAL, it is just one thread exiting because it has to + * if reason == EX_TH_EXCEPTION, it is just one thread exiting because of an exception + * if reason is none of the two cases above, it is the whole process exiting (with error code = reason) + */ + struct thread *th = current_thread; + struct process *pr = th->process; + if ((reason == EX_TH_NORMAL || reason == EX_TH_EXCEPTION) && pr->threads > 1) { + thread_delete(th); + } else { + process_delete(pr); + } + sti(); + tasking_switch(); +} + +void thread_exit_stackJmp(uint32_t reason) { + uint32_t *stack; + cli(); + stack = tasking_tmpStack + 0x4000; + stack--; *stack = reason; + stack--; *stack = 0; + asm volatile(" \ + mov %0, %%esp; \ + mov %1, %%ebp; \ + mov %2, %%ecx; \ + mov %3, %%cr3; \ + jmp *%%ecx;" : : + "r"(stack), "r"(stack), "r"(thread_exit2), "r"(kernel_pagedir->physicalAddr)); +} + +void thread_exit() { + thread_exit_stackJmp(EX_TH_NORMAL); +} + +void process_exit(uint32_t retval) { + if (retval == EX_TH_NORMAL || retval == EX_TH_EXCEPTION) retval = EX_PR_EXCEPTION; + thread_exit_stackJmp(retval); +} + static uint32_t thread_runnable(struct thread *t) { if (t->state == TS_RUNNING) return 1; if (t->state == TS_SLEEPING && timer_time() >= t->timeWait) return 1; @@ -102,7 +166,7 @@ static void thread_run(struct thread *thread, thread_entry entry_point, void *da pagedir_switch(thread->process->pagedir); //TODO : take into account privilege level asm volatile("sti"); entry_point(data); - asm volatile("int $64"); + thread_exit(0); } struct thread *thread_new(struct process *proc, thread_entry entry_point, void *data) { @@ -147,3 +211,35 @@ struct process *process_new(struct process* parent, uint32_t uid, uint32_t privi processes = p; return p; } + +static void thread_delete(struct thread *th) { + kfree(th->kernelStack_addr); + th->process->threads--; + if (threads == th) { + threads = th->next; + } else { + struct thread *it = threads; + while (it->next != th && it->next != 0) it = it->next; + if (it->next == th) it->next = th->next; + } + kfree(th); +} + +static void process_delete(struct process *pr) { + struct thread *it; + while (threads->process == pr) thread_delete(threads); + it = threads; + while (it != 0) { + while (it->next->process == pr) thread_delete(it->next); + it = it->next; + } + pagedir_delete(pr->pagedir); + if (processes == pr) { + processes = pr->next; + } else { + struct process *it = processes; + while (it != 0 && it->next != pr) it = it->next; + if (it != 0 && it->next == pr) it->next = pr->next; + } + kfree(pr); +} diff --git a/src/stem/task/task.h b/src/stem/task/task.h index f59bb2b..1d1d121 100644 --- a/src/stem/task/task.h +++ b/src/stem/task/task.h @@ -5,14 +5,6 @@ #include <mem/paging.h> #include "idt.h" -struct process { - uint32_t pid, uid, privilege, threads; - struct process *parent; - struct page_directory *pagedir; - - struct process *next; //Forms a linked list -}; - #define TS_RUNNING 0 #define TS_SLEEPING 1 //Sleeping for a defined amount of time #define TS_WAIKWAIT 2 //Waiting to be waked up by something precise (thread currently blocked) @@ -22,8 +14,20 @@ struct process { #define PL_DRIVER 1 #define PL_KERNEL 0 +#define EX_TH_NORMAL 0x10000 //ERROR code : just one thread exits, because it has to +#define EX_TH_EXCEPTION 0x10001 //ERROR code : just one thread exits, because of an unhandled exception +#define EX_PR_EXCEPTION 0x10002 //ERROR code : all process finishes, because of an unhandled exception + typedef void (*thread_entry)(void*); +struct process { + uint32_t pid, uid, privilege, threads; + struct process *parent; + struct page_directory *pagedir; + + struct process *next; //Forms a linked list +}; + struct thread { struct process *process; uint32_t esp, ebp, eip; @@ -42,6 +46,9 @@ void tasking_switch(); void tasking_updateKernelPagetable(uint32_t idx, struct page_table *table, uint32_t tablePhysical); uint32_t tasking_handleException(struct registers *regs); +void thread_sleep(uint32_t msecs); +void thread_exit(); +void process_exit(uint32_t retval); struct thread * thread_new(struct process *proc, thread_entry entry_point, void *data); struct process* process_new(struct process *parent, uint32_t uid, uint32_t privilege); |