summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordzwdz2021-08-22 11:35:00 +0200
committerdzwdz2021-08-22 11:35:00 +0200
commit5aaf1d48ec052d1582eae2c7642adc8829a6711b (patch)
tree40745bc8d62035b812c6f36f0629c13221ae42e3
parentc0a5b44bc8261dec6d4ffaadb244ecbff962719b (diff)
await() 2: pass the exit message
-rw-r--r--src/init/main.c11
-rw-r--r--src/kernel/mem.c32
-rw-r--r--src/kernel/mem.h4
-rw-r--r--src/kernel/proc.h6
-rw-r--r--src/kernel/syscalls.c45
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);