diff options
-rw-r--r-- | src/init/main.c | 4 | ||||
-rw-r--r-- | src/init/syscalls.c | 4 | ||||
-rw-r--r-- | src/kernel/proc.h | 4 | ||||
-rw-r--r-- | src/kernel/syscalls.c | 33 | ||||
-rw-r--r-- | src/kernel/syscalls.h | 6 |
5 files changed, 50 insertions, 1 deletions
diff --git a/src/init/main.c b/src/init/main.c index c6d19a3..4298516 100644 --- a/src/init/main.c +++ b/src/init/main.c @@ -22,6 +22,10 @@ int main() { if (_syscall_fork() > 0) { _syscall_debuglog("parent ", sizeof("parent ") - 1); + + _syscall_await(NULL, NULL); + _syscall_debuglog("death ", + sizeof("death ") - 1); } else { _syscall_debuglog("child ", sizeof("child ") - 1); diff --git a/src/init/syscalls.c b/src/init/syscalls.c index d0da33e..4bbd83a 100644 --- a/src/init/syscalls.c +++ b/src/init/syscalls.c @@ -12,6 +12,10 @@ int _syscall_fork() { return _syscall(_SYSCALL_FORK, 0, 0, 0); } +int _syscall_await(char *buf, int *len) { + return _syscall(_SYSCALL_AWAIT, (int)buf, (int)len, 0); +} + int _syscall_debuglog(const char *msg, size_t len) { return _syscall(_SYSCALL_DEBUGLOG, (int)msg, len, 0); } diff --git a/src/kernel/proc.h b/src/kernel/proc.h index 6bafca9..c4d9fe0 100644 --- a/src/kernel/proc.h +++ b/src/kernel/proc.h @@ -3,7 +3,9 @@ enum process_state { PS_RUNNING, - PS_DEAD, + PS_DEAD, // return message wasn't collected + PS_DEADER, // return message was collected + PS_WAITS4CHILDDEATH, }; struct process { diff --git a/src/kernel/syscalls.c b/src/kernel/syscalls.c index 6a61a9d..060b983 100644 --- a/src/kernel/syscalls.c +++ b/src/kernel/syscalls.c @@ -8,6 +8,14 @@ _Noreturn void _syscall_exit(const char *msg, size_t len) { process_current->state = PS_DEAD; + // check if our parent is awaiting our death + if (process_current->parent->state == PS_WAITS4CHILDDEATH) { + // how cruel + process_current->state = PS_DEADER; + process_current->parent->state = PS_RUNNING; + process_switch(process_current->parent); + } + process_current = process_find(PS_RUNNING); if (process_current) process_switch(process_current); @@ -16,6 +24,29 @@ _Noreturn void _syscall_exit(const char *msg, size_t len) { panic(); } +int _syscall_await(char *buf, int *len) { + // find any already dead children + for (struct process *iter = process_current->child; + iter; iter = iter->sibling) { + if (iter->state == PS_DEAD) { + iter->state = PS_DEADER; + // TODO copy return message + return 0; + } + } + + // no dead children yet + // TODO check if the process even has children + + process_current->state = PS_WAITS4CHILDDEATH; + process_current = process_find(PS_RUNNING); + if (process_current) + process_switch(process_current); + + tty_const("this error will be fixed in the next commit."); // TODO + panic(); +} + int _syscall_fork() { struct process *child = process_fork(process_current); regs_savereturn(&child->regs, 0); @@ -38,6 +69,8 @@ int syscall_handler(int num, int a, int b, int c) { switch (num) { case _SYSCALL_EXIT: _syscall_exit((void*)a, b); + case _SYSCALL_AWAIT: + return _syscall_await((void*)a, (void*)b); case _SYSCALL_FORK: return _syscall_fork(); case _SYSCALL_DEBUGLOG: diff --git a/src/kernel/syscalls.h b/src/kernel/syscalls.h index d3ad2a8..a986a33 100644 --- a/src/kernel/syscalls.h +++ b/src/kernel/syscalls.h @@ -5,6 +5,7 @@ enum { // idc about stable syscall numbers just yet _SYSCALL_EXIT, + _SYSCALL_AWAIT, _SYSCALL_FORK, _SYSCALL_DEBUGLOG @@ -15,6 +16,11 @@ enum { */ _Noreturn void _syscall_exit(const char *msg, size_t len); +/** Waits for a child to exit, putting its exit message into *buf. + * @return the length of the message + */ +int _syscall_await(char *buf, int *len); + /** Creates a copy of the current process, and executes it. * All user memory pages get copied too. * @return 0 in the child, a meaningless positive value in the parent. |