diff options
author | dzwdz | 2021-08-22 11:35:00 +0200 |
---|---|---|
committer | dzwdz | 2021-08-22 11:35:00 +0200 |
commit | 5aaf1d48ec052d1582eae2c7642adc8829a6711b (patch) | |
tree | 40745bc8d62035b812c6f36f0629c13221ae42e3 | |
parent | c0a5b44bc8261dec6d4ffaadb244ecbff962719b (diff) |
await() 2: pass the exit message
-rw-r--r-- | src/init/main.c | 11 | ||||
-rw-r--r-- | src/kernel/mem.c | 32 | ||||
-rw-r--r-- | src/kernel/mem.h | 4 | ||||
-rw-r--r-- | src/kernel/proc.h | 6 | ||||
-rw-r--r-- | src/kernel/syscalls.c | 45 |
5 files changed, 81 insertions, 17 deletions
diff --git a/src/init/main.c b/src/init/main.c index 4298516..3403a3b 100644 --- a/src/init/main.c +++ b/src/init/main.c @@ -14,6 +14,9 @@ const char *multipageify(const char *str) { } int main() { + char buf[64]; + int len = 64; + // try to print a string crossing page boundaries _syscall_debuglog( multipageify("I cross pages. "), @@ -23,12 +26,14 @@ int main() { _syscall_debuglog("parent ", sizeof("parent ") - 1); - _syscall_await(NULL, NULL); - _syscall_debuglog("death ", - sizeof("death ") - 1); + len = _syscall_await(buf, 64); + _syscall_debuglog(buf, len); } else { _syscall_debuglog("child ", sizeof("child ") - 1); + _syscall_exit( + multipageify("this is the child's exit message!"), + sizeof("this is the child's exit message!") - 1); } _syscall_exit("bye from init! ", diff --git a/src/kernel/mem.c b/src/kernel/mem.c index 9ba0231..63f5379 100644 --- a/src/kernel/mem.c +++ b/src/kernel/mem.c @@ -1,5 +1,6 @@ #include <kernel/arch/generic.h> #include <kernel/mem.h> +#include <kernel/util.h> #include <stdint.h> static void *highest_page; @@ -78,3 +79,34 @@ bool virt_iter_next(struct virt_iter *iter) { iter->_virt += partial; return true; } + +bool virt_user_cpy( + struct pagedir *dest_pages, void *dest, + struct pagedir *src_pages, const void *src, size_t length) +{ + struct virt_iter dest_iter, src_iter; + size_t min; + + virt_iter_new(&dest_iter, dest, length, dest_pages, true, true); + virt_iter_new( &src_iter, src, length, src_pages, true, false); + dest_iter.frag_len = 0; + src_iter.frag_len = 0; + + for (;;) { + if (dest_iter.frag_len <= 0) + if (!virt_iter_next(&dest_iter)) break; + if ( src_iter.frag_len <= 0) + if (!virt_iter_next( &src_iter)) break; + + min = src_iter.frag_len < dest_iter.frag_len + ? src_iter.frag_len : dest_iter.frag_len; + memcpy(dest_iter.frag, src_iter.frag, min); + + dest_iter.frag_len -= min; + dest_iter.frag += min; + src_iter.frag_len -= min; + src_iter.frag += min; + } + + return !(dest_iter.error || src_iter.error); +} diff --git a/src/kernel/mem.h b/src/kernel/mem.h index 78de8db..d8496fd 100644 --- a/src/kernel/mem.h +++ b/src/kernel/mem.h @@ -33,3 +33,7 @@ void virt_iter_new( struct pagedir *pages, bool user, bool writeable); bool virt_iter_next(struct virt_iter *); + +bool virt_user_cpy( + struct pagedir *dest_pages, void *dest, + struct pagedir *src_pages, const void *src, size_t length); diff --git a/src/kernel/proc.h b/src/kernel/proc.h index c4d9fe0..2f39f2e 100644 --- a/src/kernel/proc.h +++ b/src/kernel/proc.h @@ -19,6 +19,12 @@ struct process { struct process *parent; uint32_t id; // only for debugging, don't expose to userland + + // meaning changes depending on the state + // PS_DEAD - death message + // PS_WAITS4CHILDDEATH - buffer for said message + void *saved_addr; + size_t saved_len; }; extern struct process *process_first; diff --git a/src/kernel/syscalls.c b/src/kernel/syscalls.c index 060b983..bdf77af 100644 --- a/src/kernel/syscalls.c +++ b/src/kernel/syscalls.c @@ -5,16 +5,32 @@ #include <kernel/syscalls.h> #include <stdint.h> +_Noreturn static void await_finish(struct process *dead, struct process *listener) { + size_t len; + bool res; + + if ( dead->state != PS_DEAD ) panic(); + if (listener->state != PS_WAITS4CHILDDEATH) panic(); + dead->state = PS_DEADER; + listener->state = PS_RUNNING; + + len = listener->saved_len < dead->saved_len + ? listener->saved_len : dead->saved_len; + res = virt_user_cpy( + listener->pages, listener->saved_addr, + dead->pages, dead->saved_addr, len); + regs_savereturn(&listener->regs, res ? len : -1); + process_switch(listener); +} + + _Noreturn void _syscall_exit(const char *msg, size_t len) { process_current->state = PS_DEAD; + process_current->saved_addr = msg; + process_current->saved_len = len; - // 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); - } + if (process_current->parent->state == PS_WAITS4CHILDDEATH) + await_finish(process_current, process_current->parent); process_current = process_find(PS_RUNNING); if (process_current) @@ -25,20 +41,21 @@ _Noreturn void _syscall_exit(const char *msg, size_t len) { } int _syscall_await(char *buf, int *len) { + process_current->state = PS_WAITS4CHILDDEATH; + process_current->saved_addr = buf; + process_current->saved_len = 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; - } + iter; iter = iter->sibling) + { + if (iter->state == PS_DEAD) + await_finish(iter, process_current); // doesn't return } // 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); |