diff options
Diffstat (limited to 'src/kernel/user')
-rw-r--r-- | src/kernel/user/process.c | 123 | ||||
-rw-r--r-- | src/kernel/user/syscall.c | 72 |
2 files changed, 190 insertions, 5 deletions
diff --git a/src/kernel/user/process.c b/src/kernel/user/process.c index 973e9d8..2812fc6 100644 --- a/src/kernel/user/process.c +++ b/src/kernel/user/process.c @@ -239,7 +239,8 @@ void process_exit(process_t *p, int status, int exit_code) { // notify parent process_t *par = p->parent; if (par->status == PS_RUNNING) { - // TODO: notify that child is exited + resume_on(par->children); + resume_on(p); } mutex_unlock(&p->lock); @@ -286,7 +287,127 @@ process_t *process_find_child(process_t *p, int pid) { mutex_unlock(&p->lock); return ret; +} + +void process_get_status(process_t *p, proc_status_t *st) { + st->pid = p->pid; + st->status = p->status; + st->exit_code = p->exit_code; +} + +void process_wait(process_t *p, proc_status_t *st, bool wait) { + // This is such a mess... + + process_t *par = p->parent; + + st->pid = 0; + st->status = 0; + + mutex_lock(&par->lock); + + while (true) { + // problem : p may not be in parent's children list anymore, + // meaning the associated process_t* has been deleted + bool found = false; + for (process_t *it = par->children; it != 0; it = it->next_child) { + if (it == p) { + found = true; + break; + } + } + + if (found) { + if (p->status != PS_LOADING && p->status != PS_RUNNING) { + process_get_status(p, st); + + if (par->children == p) { + par->children = p->next_child; + } else { + for (process_t *it = par->children; it->next_child != 0; it = it->next_child) { + if (it->next_child == p) { + it->next_child = p->next_child; + break; + } + } + } + + free(p); + } else if (wait) { + bool wait_ok; + + { int st = enter_critical(CL_NOSWITCH); + + mutex_unlock(&par->lock); + wait_ok = wait_on(p); + + exit_critical(st); } + + if (!wait_ok) return; + + mutex_lock(&par->lock); + continue; // loop around + } + } + break; + } + + mutex_unlock(&par->lock); +} + +void process_wait_any_child(process_t *par, proc_status_t *st, bool wait) { + st->pid = 0; + st->status = 0; + + mutex_lock(&par->lock); + + while (true) { + // problem : p may not be in parent's children list anymore, + // meaning the associated process_t* has been deleted + process_t *p = 0; + + for (process_t *it = par->children; it != 0; it = it->next_child) { + if (it->status != PS_LOADING && it->status != PS_RUNNING) { + p = it; + break; + } + } + + if (p) { + process_get_status(p, st); + + if (par->children == p) { + par->children = p->next_child; + } else { + for (process_t *it = par->children; it->next_child != 0; it = it->next_child) { + if (it->next_child == p) { + it->next_child = p->next_child; + break; + } + } + } + + free(p); + } else { + if (wait) { + bool wait_ok; + + { int st = enter_critical(CL_NOSWITCH); + + mutex_unlock(&par->lock); + wait_ok = wait_on(par); + + exit_critical(st); } + + if (!wait_ok) return; + + mutex_lock(&par->lock); + continue; // loop around + } + } + break; + } + mutex_unlock(&par->lock); } diff --git a/src/kernel/user/syscall.c b/src/kernel/user/syscall.c index fe9b4fe..04144d4 100644 --- a/src/kernel/user/syscall.c +++ b/src/kernel/user/syscall.c @@ -1,6 +1,7 @@ #include <string.h> #include <process.h> #include <vfs.h> +#include <elf.h> #include <sct.h> @@ -456,19 +457,82 @@ end_bind_fd: } static uint32_t proc_exec_sc(sc_args_t args) { - return -1; //TODO + bool ok = false; + + process_t *p = 0; + char* exec_name = 0; + fs_handle_t *h = 0; + + p = process_find_child(current_process(), args.a); + if (p == 0) goto end_exec; + + exec_name = sc_copy_string_x(args.b, args.c); + if (exec_name == 0) goto end_exec; + + char* sep = strchr(exec_name, ':'); + if (sep == 0) goto end_exec; + + *sep = 0; + char* file = sep + 1; + + fs_t *fs = proc_find_fs(current_process(), exec_name); + if (fs == 0) goto end_exec; + + h = fs_open(fs, file, FM_READ | FM_MMAP); + if (h == 0) h = fs_open(fs, file, FM_READ); + if (h == 0) goto end_exec; + + proc_entry_t *entry = elf_load(h, p); + if (entry == 0) goto end_exec; + + ok = start_process(p, entry); + +end_exec: + if (exec_name) free(exec_name); + if (h) unref_file(h); + return ok; } static uint32_t proc_status_sc(sc_args_t args) { - return -1; //TODO + proc_status_t *st = (proc_status_t*)args.b; + probe_for_write(st, sizeof(proc_status_t)); + + process_t *p = process_find_child(current_process(), args.a); + if (p == 0) return false; + + process_get_status(p, st); + return true; } static uint32_t proc_kill_sc(sc_args_t args) { - return -1; //TODO + proc_status_t *st = (proc_status_t*)args.b; + probe_for_write(st, sizeof(proc_status_t)); + + process_t *p = process_find_child(current_process(), args.a); + if (p == 0) return false; + + process_exit(p, PS_KILLED, 0); + process_wait(p, st, true); // (should return immediately) + + return true; } static uint32_t proc_wait_sc(sc_args_t args) { - return -1; //TODO + proc_status_t *st = (proc_status_t*)args.c; + probe_for_write(st, sizeof(proc_status_t)); + + bool wait = (args.b != 0); + + if (args.a == 0) { + process_wait_any_child(current_process(), st, wait); + return true; + } else { + process_t *p = process_find_child(current_process(), args.a); + if (p == 0) return false; + + process_wait(p, st, wait); + return true; + } } // ====================== // |