diff options
Diffstat (limited to 'src/kernel/task')
-rw-r--r-- | src/kernel/task/syscall.cpp | 9 | ||||
-rw-r--r-- | src/kernel/task/task.cpp | 129 | ||||
-rw-r--r-- | src/kernel/task/task.h | 9 |
3 files changed, 110 insertions, 37 deletions
diff --git a/src/kernel/task/syscall.cpp b/src/kernel/task/syscall.cpp index e9f9d3a..4eddb61 100644 --- a/src/kernel/task/syscall.cpp +++ b/src/kernel/task/syscall.cpp @@ -28,6 +28,7 @@ CALL1V(idt_waitIrq, irq_wait_sc); CALL0(proc_priv, proc_priv_sc); CALL1(process_sbrk, proc_sbrk_sc); CALL1V(process_brk, proc_brk_sc); +CALL1(process_waitpid, waitpid_sc); CALL1V(close, close_sc); @@ -41,6 +42,10 @@ static void thread_new_sc(registers* r) { sti(); } +static void run_sc(registers *r) { + r->eax = process_run((char*)r->ebx, (char**)r->ecx); +} + static void open_sc(registers *r) { r->eax = open((char*)r->ebx, r->ecx); } @@ -89,8 +94,8 @@ int_callback syscalls[NUMBER_OF_SYSCALLS] = { // This must correspond to common proc_brk_sc, 0, 0, - 0, - 0, //15 + run_sc, + waitpid_sc, //15 0, 0, 0, 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); +} diff --git a/src/kernel/task/task.h b/src/kernel/task/task.h index 99738b9..2ebb66e 100644 --- a/src/kernel/task/task.h +++ b/src/kernel/task/task.h @@ -34,8 +34,8 @@ class process { segment_map *dataseg; - process *next; //Forms a linked list thread *threads; + thread *threads_waiting; // threads waiting for this process to end earray<node> fd; // file descriptors @@ -77,9 +77,12 @@ uint32_t tasking_handleException(registers *regs); void thread_goInactive(); //Blocks the current thread. it is then waked up by another thread or a system event. int proc_priv(); //Returns current privilege level -void thread_exit(); //syscall -void process_exit(size_t retval); //syscall +// syscalls +void thread_exit(); +void process_exit(size_t retval); size_t process_sbrk(size_t size); void process_brk(size_t ptr); +int process_run(char* file, char** args); +int process_waitpid(int pid); #endif |