summaryrefslogtreecommitdiff
path: root/src/kernel
diff options
context:
space:
mode:
authordzwdz2021-08-18 20:23:59 +0200
committerdzwdz2021-08-18 20:23:59 +0200
commitc0a5b44bc8261dec6d4ffaadb244ecbff962719b (patch)
tree64043f4c174b1695541f4de2ee845681b14e300e /src/kernel
parent349420c51fe05bfb23b6eb4d30aa1aad034d3c33 (diff)
await() 1: wait for child to die, without message passing
The length is a int, because the syscall will have a signed output. A negative return value will mean an error (such as when it gets called by a childless process).
Diffstat (limited to 'src/kernel')
-rw-r--r--src/kernel/proc.h4
-rw-r--r--src/kernel/syscalls.c33
-rw-r--r--src/kernel/syscalls.h6
3 files changed, 42 insertions, 1 deletions
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.