summaryrefslogtreecommitdiff
path: root/src/stem/task.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/stem/task.c')
-rw-r--r--src/stem/task.c123
1 files changed, 123 insertions, 0 deletions
diff --git a/src/stem/task.c b/src/stem/task.c
new file mode 100644
index 0000000..874f22d
--- /dev/null
+++ b/src/stem/task.c
@@ -0,0 +1,123 @@
+#include "task.h"
+#include "sys.h"
+#include "mem.h"
+#include "timer.h"
+#include "monitor.h"
+
+#define KSTACKSIZE 0x8000
+
+//From task_.asm
+extern uint32_t read_eip();
+extern void task_idle(void*);
+
+static uint32_t thread_runnable(struct thread *th);
+
+uint32_t nextpid = 1;
+
+struct process *processes = 0;
+struct thread *threads = 0, *current_thread = 0;
+
+void tasking_init(thread_entry whereToGo, void *data) {
+ cli();
+ struct process *pr = kmalloc(sizeof(struct process)); //This process must be hidden to users
+ pr->pid = pr->uid = 0;
+ pr->parent = pr;
+ pr->pagedir = kernel_pagedir;
+ pr->next = 0;
+ current_thread = 0;
+ thread_new(pr, task_idle, 0);
+ thread_new(pr, 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;
+ struct thread *ret = current_thread;
+ while (1) {
+ ret = ret->next;
+ if (ret == 0) ret = threads;
+ if (thread_runnable(ret)) {
+ return ret;
+ }
+ }
+}
+
+void tasking_switch() {
+ if (threads == 0) return; //no tasking yet
+ cli();
+
+ uint32_t esp, ebp, eip;
+
+ asm volatile("mov %%esp, %0" : "=r"(esp));
+ asm volatile("mov %%ebp, %0" : "=r"(ebp));
+ eip = read_eip();
+
+ if (eip == 0x12345) {
+ return;
+ }
+
+ if (current_thread != 0) {
+ current_thread->esp = esp;
+ current_thread->ebp = ebp;
+ current_thread->eip = eip;
+ }
+
+ current_thread = thread_next();
+
+ asm volatile(" \
+ mov %0, %%ebp; \
+ mov %1, %%esp; \
+ mov %2, %%ecx; \
+ mov $0x12345, %%eax; \
+ jmp *%%ecx;"
+ : : "r"(current_thread->ebp), "r"(current_thread->esp), "r"(current_thread->eip));
+}
+
+uint32_t tasking_handleException(struct registers *regs) {
+ if (threads == 0) return 0; //No tasking yet
+ return 0;
+}
+
+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;
+ return 0;
+}
+
+static void thread_run(struct thread *thread, thread_entry entry_point, void *data) {
+ pagedir_switch(thread->process->pagedir);
+ asm volatile("sti");
+ entry_point(data);
+ asm volatile("int $64");
+}
+
+void thread_new(struct process *proc, thread_entry entry_point, void *data) {
+ struct thread *t = kmalloc(sizeof(struct thread));
+ t->process = proc;
+ t->kernelStack_addr = kmalloc(KSTACKSIZE);
+ t->kernelStack_size = KSTACKSIZE;
+
+ uint32_t *stack = (uint32_t*)((size_t)t->kernelStack_addr + t->kernelStack_size);
+
+ //Pass parameters
+ stack--; *stack = (uint32_t)data;
+ stack--; *stack = (uint32_t)entry_point;
+ stack--; *stack = (uint32_t)t;
+ stack--; *stack = 0;
+ t->esp = (uint32_t)stack;
+ t->ebp = t->esp + 8;
+ t->eip = (uint32_t)thread_run;
+
+ t->state = TS_RUNNING;
+
+ if (threads == 0) {
+ threads = t;
+ } else {
+ struct thread *i = threads;
+ while (i->next != 0) i = i->next;
+ i->next = t;
+ }
+}
+