summaryrefslogtreecommitdiff
path: root/src/stem/task
diff options
context:
space:
mode:
Diffstat (limited to 'src/stem/task')
-rw-r--r--src/stem/task/idt.c6
-rw-r--r--src/stem/task/syscall.c6
-rw-r--r--src/stem/task/task.c108
-rw-r--r--src/stem/task/task.h23
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](&regs);
+ if (syscalls[regs.eax] != 0) {
+ syscalls[regs.eax](&regs);
+ } 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);