summaryrefslogtreecommitdiff
path: root/src/kernel/task/task.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/kernel/task/task.cpp')
-rw-r--r--src/kernel/task/task.cpp129
1 files changed, 97 insertions, 32 deletions
diff --git a/src/kernel/task/task.cpp b/src/kernel/task/task.cpp
index 1a5d535..02294bd 100644
--- a/src/kernel/task/task.cpp
+++ b/src/kernel/task/task.cpp
@@ -6,6 +6,10 @@
#include <mem/gdt.h>
#include "timer.h"
+#include <linker/elf.h>
+
+#include <vfs/node.h>
+#include <lib/earray.h>
#include <ui/vt.h>
#define KSTACKSIZE 0x8000
@@ -14,29 +18,37 @@
static void thread_exit_stackJmp(uint32_t reason);
static void thread_exit2(uint32_t reason);
static void thread_delete(thread *th);
-static void process_delete(process *pr);
+static void process_finish(process *pr, int retval);
//From task_.asm
extern "C" uint32_t read_eip();
extern "C" void task_idle(void*);
-static uint32_t nextpid = 1;
-process *processes = 0, *kernel_process = 0, *current_process = 0;
+earray<process> *proc_by_pid;
+earray<void> *proc_retval;
+
+process *kernel_process = 0, *current_process = 0;
thread *current_thread = 0, *idle_thread = 0;
+int proc_count = 0;
+
uint32_t tasking_tmpStack[KSTACKSIZE];
/* Sets up tasking. Called by kmain on startup.
Creates a kernel process and an IDLE thread in it. */
void tasking_init() {
+ proc_by_pid = new earray<process>(12, 32);
+ proc_retval = new earray<void>(12, 32);
+
cli();
- kernel_process = new process(); //This process must be hidden to users
- kernel_process->pid = kernel_process->uid = kernel_process->thread_count = 0;
+ kernel_process = new process();
+ kernel_process->uid = kernel_process->thread_count = 0;
+ kernel_process->pid = proc_by_pid->add(kernel_process);
kernel_process->privilege = PL_KERNEL;
kernel_process->parent = kernel_process;
kernel_process->pagedir = kernel_pagedir;
- kernel_process->next = 0;
kernel_process->threads = 0;
+ kernel_process->threads_waiting = 0;
current_thread = 0;
idle_thread = new thread(kernel_process, task_idle, 0, 0);
sti();
@@ -46,17 +58,17 @@ void tasking_init() {
Updates the page directories of all the processes. */
void tasking_updateKernelPagetable(uint32_t idx, page_table *table, uint32_t tablephysical) {
if (idx < FIRST_KERNEL_PAGETABLE) return;
- process* it = processes;
- while (it != 0) {
+ for (int i = 0; i < proc_by_pid->count(); i++) {
+ process *it = proc_by_pid->at(i);
+ if (it == 0) continue;
it->pagedir->tables[idx] = table;
it->pagedir->tablesPhysical[idx] = tablephysical;
- it = it->next;
}
}
/* Called when a timer IRQ fires. Does a context switch. */
void schedule() {
- if (processes == 0) PANIC("No processes are running !");
+ //if (processes == 0) PANIC("No processes are running !");
asm volatile("cli");
uint32_t esp, ebp, eip;
@@ -97,7 +109,7 @@ void schedule() {
Ends the thread for most exceptions, ends the whole process for page faults. */
uint32_t tasking_handleException(registers *regs) {
if (current_thread == 0) return 0; //No tasking yet
- NL; WHERE; ke_vt->writeStr("exception:`");
+ NL; WHERE; ke_vt->writeStr("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",
@@ -105,10 +117,9 @@ uint32_t tasking_handleException(registers *regs) {
*ke_vt << exception_messages[regs->int_no];
*ke_vt << "'\teip:" << regs->eip;
if (regs->eip >= K_HIGHHALF_ADDR) {
- *ke_vt << "\n Exception stack trace :\n";
+ *ke_vt << "\nException in kernel. Stack trace:\n";
stack_trace(regs->ebp);
- PANIC("Kernel error'd.");
- }
+ }
if (regs->int_no == 14) {
*ke_vt << "\n>>> Process exiting.\n";
thread_exit_stackJmp(EX_PR_EXCEPTION);
@@ -155,7 +166,7 @@ void thread_exit2(uint32_t reason) { //See EX_TH_* defines in task.h
if ((reason == EX_TH_NORMAL || reason == EX_TH_EXCEPTION) && pr->thread_count > 1) {
thread_delete(th);
} else {
- process_delete(pr);
+ process_finish(pr, reason);
}
retrn:
sti();
@@ -274,14 +285,13 @@ thread::thread(class process *proc, thread_entry entry_point, void *data, void *
/* Creates a new process. Creates a struct process and fills it up. */
process::process(process* _parent, uint32_t _uid, uint32_t _privilege) : fd(12, 64) {
- pid = (nextpid++);
uid = _uid;
thread_count = 0;
threads = 0;
+ threads_waiting = 0;
privilege = _privilege;
parent = _parent;
pagedir = pagedir_new();
- next = processes;
data = 0;
dataseg = 0;
@@ -294,7 +304,9 @@ process::process(process* _parent, uint32_t _uid, uint32_t _privilege) : fd(12,
stack = stacksBottom + USER_STACK_SIZE - 4;
}
- processes = this;
+ pid = proc_by_pid->add(this);
+
+ proc_count++;
}
/* Deletes given thread, freeing the stack(s). */
@@ -318,26 +330,25 @@ static void thread_delete(thread *th) {
}
/* Deletes a process. First, deletes all its threads. Also deletes the corresponding page directory. */
-static void process_delete(process *pr) {
+static void process_finish(process *pr, int retval) {
+ proc_retval->set(pr->pid, (void*)retval);
+
+
thread *it = pr->threads;
while (it != 0) {
thread_delete(it);
it = it->next;
}
- if (processes == pr) {
- processes = pr->next;
- } else {
- process *it = processes;
- while (it) {
- if (it->next == pr) {
- it->next = pr->next;
- break;
- }
- it = it->next;
- }
- }
pagedir_delete(pr->pagedir);
+ proc_by_pid->set(pr->pid, 0);
+ while (pr->threads_waiting != 0) {
+ pr->threads_waiting->wakeUp();
+ pr->threads_waiting = pr->threads_waiting->queue_next;
+ }
kfree(pr);
+
+ proc_count--;
+ if (proc_count == 0) PANIC("No more processes are running! This is bad! Or is it?");
}
size_t process::sbrk(size_t size) {
@@ -408,11 +419,65 @@ void* process::set_args(char** args) {
return p;
}
-// syscalls
+// ===================== SYSTEM CALLS
+
+
size_t process_sbrk(size_t size) {
return current_process->sbrk(size);
}
+
void process_brk(size_t ptr) {
ASSERT(ptr < K_HIGHHALF_ADDR);
current_process->sbrk(ptr - current_process->data);
}
+
+int process_run(char* file, char** args) {
+ node* bin = vfs_find(root, file);
+ if (bin == 0) return E_NOT_FOUND;
+ if ((bin->type & FT_FILE) == 0) return E_INVALID;
+
+ int len = bin->get_size();
+ void *v = kmalloc(len);
+ int r = bin->read(0, len, (char*)v);
+ if (r != len) {
+ kfree(v);
+ return E_NOT_IMPLEMENTED;
+ }
+ if (elf_check((uint8_t*)v) != 0) {
+ kfree(v);
+ return E_NOT_IMPLEMENTED;
+ }
+
+ // copy arguments to kernel
+ char **arg_data;
+ int argc = 0;
+ if (args != 0) {
+ for (char** a = args; *a != 0; a++) argc++;
+ arg_data = (char**)kmalloc(sizeof(char*) * (argc + 2));
+ for (int i = 0; i < argc; i++) arg_data[i+1] = strdup(args[i]);
+ } else {
+ arg_data = (char**)kmalloc(sizeof(char*)*2);
+ }
+ arg_data[0] = strdup(file);
+ arg_data[argc + 1] = 0;
+
+ // load
+ process *p = elf_exec((uint8_t*)v, PL_USER, arg_data);
+
+ kfree(v);
+ for (int i = 0; arg_data[i] != 0; i++) kfree(arg_data[i]);
+ kfree(arg_data);
+ return (p == 0 ? E_INVALID : p->pid);
+}
+
+int process_waitpid(int pid) {
+ if (pid <= 0) return E_INVALID_RANGE;
+
+ process *p = proc_by_pid->at(pid);
+ if (p != 0) {
+ current_thread->queue_next = p->threads_waiting;
+ p->threads_waiting = current_thread;
+ thread_goInactive();
+ }
+ return (int)proc_retval->at(pid);
+}