aboutsummaryrefslogtreecommitdiff
path: root/src/kernel/user
diff options
context:
space:
mode:
authorAlex Auvolat <alex.auvolat@ens.fr>2015-03-02 23:30:16 +0100
committerAlex Auvolat <alex.auvolat@ens.fr>2015-03-03 10:30:03 +0100
commit155f63c4f6995acff2b9c7467cfd91d1f77f3272 (patch)
tree28e8239e13b50ad3d07b1e777f919ac5297bf6bf /src/kernel/user
parentbb1a5fc74769301c0a792cb83d3fa0bda8a780cb (diff)
downloadkogata-155f63c4f6995acff2b9c7467cfd91d1f77f3272.tar.gz
kogata-155f63c4f6995acff2b9c7467cfd91d1f77f3272.zip
Implement process termination and cleaning up (not completely though)
Diffstat (limited to 'src/kernel/user')
-rw-r--r--src/kernel/user/process.c158
-rw-r--r--src/kernel/user/syscall.c4
2 files changed, 137 insertions, 25 deletions
diff --git a/src/kernel/user/process.c b/src/kernel/user/process.c
index 649c801..af7d86f 100644
--- a/src/kernel/user/process.c
+++ b/src/kernel/user/process.c
@@ -5,7 +5,7 @@
#include <frame.h>
#include <process.h>
#include <freemem.h>
-
+#include <worker.h>
static int next_pid = 1;
@@ -22,6 +22,11 @@ typedef struct {
void *sp;
} setup_data_t;
+typedef struct {
+ process_t *proc;
+ int status, exit_code;
+} exit_data_t;
+
// ============================== //
// CREATING AND RUNNING PROCESSES //
// ============================== //
@@ -48,6 +53,7 @@ process_t *new_process(process_t *parent) {
proc->pid = (next_pid++);
proc->parent = parent;
proc->next_fd = 1;
+ proc->status = PS_LOADING;
return proc;
@@ -62,15 +68,15 @@ error:
static void run_user_code(void* param) {
setup_data_t *d = (setup_data_t*)param;
+ void* esp = d->sp;
+ proc_entry_t entry = d->entry;
+ free(d);
+
process_t *proc = current_thread->proc;
ASSERT(proc != 0);
switch_pagedir(proc->pd);
- void* esp = d->sp;
- proc_entry_t entry = d->entry;
- free(d);
-
asm volatile(" \
cli; \
\
@@ -91,18 +97,6 @@ static void run_user_code(void* param) {
iret \
"::"b"(esp),"c"(entry));
}
-bool start_process(process_t *p, void* entry) {
- bool stack_ok = mmap(p, (void*)USERSTACK_ADDR, USERSTACK_SIZE, MM_READ | MM_WRITE);
- if (!stack_ok) return false;
-
- bool ok = process_new_thread(p, entry, (void*)USERSTACK_ADDR + USERSTACK_SIZE);
- if (!ok) {
- munmap(p, (void*)USERSTACK_ADDR);
- return false;
- }
-
- return true;
-}
bool process_new_thread(process_t *p, proc_entry_t entry, void* sp) {
setup_data_t *d = (setup_data_t*)malloc(sizeof(setup_data_t));
@@ -117,7 +111,7 @@ bool process_new_thread(process_t *p, proc_entry_t entry, void* sp) {
th->proc = p;
th->user_ex_handler = proc_user_exception;
- { int st = enter_critical(CL_NOINT); // it's a bit complicated to use mutexes on process_t (TODO: think)
+ { int st = enter_critical(CL_NOSWITCH); // it's a bit complicated to use mutexes on process_t
th->next_in_proc = p->threads;
p->threads = th;
@@ -129,6 +123,124 @@ bool process_new_thread(process_t *p, proc_entry_t entry, void* sp) {
return true;
}
+bool start_process(process_t *p, void* entry) {
+ bool stack_ok = mmap(p, (void*)USERSTACK_ADDR, USERSTACK_SIZE, MM_READ | MM_WRITE);
+ if (!stack_ok) return false;
+
+ bool ok = process_new_thread(p, entry, (void*)USERSTACK_ADDR + USERSTACK_SIZE);
+ if (!ok) {
+ munmap(p, (void*)USERSTACK_ADDR);
+ return false;
+ }
+
+ p->status = PS_RUNNING;
+
+ return true;
+}
+
+void process_exit(process_t *p, int status, int exit_code) {
+ // --- Make sure we are not running in a thread we are about to kill
+
+ void process_exit_v(void* args) {
+ exit_data_t *d = (exit_data_t*)args;
+ process_exit(d->proc, d->status, d->exit_code);
+ free(d);
+ }
+
+ if (current_process() == p) {
+ exit_data_t *d = (exit_data_t*)malloc(sizeof(exit_data_t));
+
+ d->proc = p;
+ d->status = status;
+ d->exit_code = exit_code;
+
+ worker_push(process_exit_v, d);
+ pause();
+ }
+
+ // ---- Now we can do the actual cleanup
+
+ int st = enter_critical(CL_NOSWITCH);
+
+ p->status = status;
+ p->exit_code = exit_code;
+
+ while (p->threads != 0) {
+ thread_t *t = p->threads;
+ p->threads = p->threads->next_in_proc;
+
+ t->proc = 0;
+ kill_thread(t);
+ }
+
+ // release file descriptors
+ void release_fd(void* a, void* fd) {
+ unref_file((fs_handle_t*)fd);
+ }
+ hashtbl_iter(p->files, release_fd);
+ delete_hashtbl(p->files);
+ p->files = 0;
+
+ // unmap memory
+ while (p->regions != 0) {
+ munmap(p, p->regions->addr);
+ }
+ ASSERT(btree_count(p->regions_idx) == 0);
+ delete_btree(p->regions_idx);
+ p->regions_idx = 0;
+
+ // release filesystems
+ void release_fs(void* a, void* fs) {
+ unref_fs((fs_t*)fs);
+ }
+ hashtbl_iter(p->filesystems, release_fs);
+ delete_hashtbl(p->filesystems);
+ p->filesystems = 0;
+
+ // delete page directory
+ switch_pagedir(get_kernel_pagedir());
+ delete_pagedir(p->pd);
+ p->pd = 0;
+
+ // orphan children
+ while (p->children != 0) {
+ process_t *c = p->children;
+ p->children = c->next_child;
+
+ c->parent = 0;
+ c->next_child = 0;
+ }
+
+ if (p->parent == 0) {
+ free(p);
+ } else {
+ // TODO : notify parent
+ }
+
+ exit_critical(st);
+}
+
+void process_thread_deleted(thread_t *t) {
+ int st = enter_critical(CL_NOSWITCH);
+
+ process_t *p = t->proc;
+ if (p->threads == t) {
+ p->threads = t->next_in_proc;
+ } else {
+ for (thread_t *it = p->threads; it != 0; it = it->next_in_proc) {
+ if (it->next_in_proc == t) {
+ it->next_in_proc = t->next_in_proc;
+ break;
+ }
+ }
+ }
+
+ if (p->threads == 0 && p->status == PS_RUNNING)
+ process_exit(p, PS_FINISHED, 0);
+
+ exit_critical(st);
+}
+
// ================================== //
// MANAGING FILESYSTEMS FOR PROCESSES //
@@ -344,7 +456,7 @@ bool munmap(process_t *proc, void* addr) {
static void proc_user_exception(registers_t *regs) {
dbg_printf("Usermode exception in user process : exiting.\n");
dbg_dump_registers(regs);
- exit();
+ process_exit(current_process(), PS_FAILURE, FAIL_EXCEPTION);
}
static void proc_usermem_pf(void* p, registers_t *regs, void* addr) {
process_t *proc = (process_t*)p;
@@ -353,13 +465,13 @@ static void proc_usermem_pf(void* p, registers_t *regs, void* addr) {
if (r == 0) {
dbg_printf("Segmentation fault in process %d (0x%p : not mapped) : exiting.\n", proc->pid, addr);
dbg_dump_registers(regs);
- exit();
+ process_exit(current_process(), PS_FAILURE, (addr < (void*)PAGE_SIZE ? FAIL_ZEROPTR : FAIL_SEGFAULT));
}
bool wr = ((regs->err_code & PF_WRITE_BIT) != 0);
if (wr && !(r->mode & MM_WRITE)) {
dbg_printf("Segmentation fault in process %d (0x%p : not allowed to write) : exiting.\n", proc->pid, addr);
- exit();
+ process_exit(current_process(), PS_FAILURE, (addr < (void*)PAGE_SIZE ? FAIL_ZEROPTR : FAIL_SEGFAULT));
}
bool pr = ((regs->err_code & PF_PRESENT_BIT) != 0);
@@ -393,7 +505,7 @@ void probe_for_read(const void* addr, size_t len) {
if (r == 0 || addr + len > r->addr + r->size || !(r->mode & MM_READ)) {
dbg_printf("Access violation on read at 0x%p len 0x%p in process %d : exiting.\n",
addr, len, proc->pid);
- exit();
+ process_exit(current_process(), PS_FAILURE, FAIL_SC_SEGFAULT);
}
}
@@ -403,7 +515,7 @@ void probe_for_write(const void* addr, size_t len) {
if (r == 0 || addr + len > r->addr + r->size || !(r->mode & MM_WRITE)) {
dbg_printf("Access violation on write at 0x%p len 0x%p in process %d : exiting.\n",
addr, len, proc->pid);
- exit();
+ process_exit(current_process(), PS_FAILURE, FAIL_SC_SEGFAULT);
}
}
diff --git a/src/kernel/user/syscall.c b/src/kernel/user/syscall.c
index 009903c..d9131b2 100644
--- a/src/kernel/user/syscall.c
+++ b/src/kernel/user/syscall.c
@@ -33,9 +33,9 @@ static char* sc_copy_string(uint32_t s, uint32_t slen) {
static uint32_t exit_sc(sc_args_t args) {
dbg_printf("Proc %d exit with code %d\n", current_process()->pid, args.a);
- // TODO : use code... and process exiting is not supposed to be done this way
- exit();
+ process_exit(current_process(), PS_FINISHED, args.a);
+ ASSERT(false);
return 0;
}