summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/init/main.c4
-rw-r--r--src/init/syscalls.c4
-rw-r--r--src/kernel/proc.h4
-rw-r--r--src/kernel/syscalls.c33
-rw-r--r--src/kernel/syscalls.h6
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.