aboutsummaryrefslogtreecommitdiff
path: root/src/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'src/kernel')
-rw-r--r--src/kernel/core/kmain.c2
-rw-r--r--src/kernel/user/process.c123
-rw-r--r--src/kernel/user/syscall.c72
3 files changed, 191 insertions, 6 deletions
diff --git a/src/kernel/core/kmain.c b/src/kernel/core/kmain.c
index 8242f99..5cd71c5 100644
--- a/src/kernel/core/kmain.c
+++ b/src/kernel/core/kmain.c
@@ -299,7 +299,7 @@ void launch_init(btree_t *cmdline, fs_t *iofs, fs_t *rootfs) {
unref_file(init_bin);
- start_process(init_p, e);
+ ASSERT(start_process(init_p, e));
}
/* vim: set ts=4 sw=4 tw=0 noet :*/
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;
+ }
}
// ====================== //