aboutsummaryrefslogtreecommitdiff
path: root/src/uapi/ipc.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/uapi/ipc.c')
-rw-r--r--src/uapi/ipc.c40
1 files changed, 22 insertions, 18 deletions
diff --git a/src/uapi/ipc.c b/src/uapi/ipc.c
index 069ca59..f3896f5 100644
--- a/src/uapi/ipc.c
+++ b/src/uapi/ipc.c
@@ -6,6 +6,7 @@
* Interprocess communication syscall implementations.
*/
+#include <kmi/orphanage.h>
#include <kmi/debug.h>
#include <kmi/uapi.h>
#include <kmi/tcb.h>
@@ -29,9 +30,6 @@ struct call_ctx {
/** Current process ID. */
id_t pid;
-
- /** Whether this context should be skipped when responding. */
- bool kick;
};
/**
@@ -83,7 +81,9 @@ static void finalize_rpc(struct tcb *t, struct tcb *r, vm_t s)
static vm_t enter_rpc(struct tcb *t, struct sys_ret a,
enum ipc_kind kind)
{
- vm_t rpc_stack = rpc_position(t);
+ /* reuse current rpc stack location if we're being kicked */
+ vm_t rpc_stack = (kind == IPC_KICK &&
+ is_rpc(t)) ? t->rpc_stack :rpc_position(t);
struct call_ctx *ctx = (struct call_ctx *)(rpc_stack) - 1;
ctx->regs = t->regs;
@@ -98,9 +98,6 @@ static vm_t enter_rpc(struct tcb *t, struct sys_ret a,
ctx->eid = t->eid;
ctx->rpc_stack = rpc_stack;
- /* only rpcs can be kicked forward */
- ctx->kick = kind == IPC_KICK && is_rpc(t);
-
/** @todo if we run out of rpc_stack space we should just stop, likely
* return a status? except it shouldn't happen after we've run
* enough_rpc_stack(). */
@@ -223,17 +220,25 @@ static void leave_rpc(struct tcb *t, struct sys_ret a)
struct call_ctx *ctx = (struct call_ctx *)(rpc_stack) - 1;
vm_t top = ctx->rpc_stack;
- /* find first instance of not kicked context */
- while (ctx->kick) {
- rpc_stack = ctx->rpc_stack + BASE_PAGE_SIZE;
- ctx = (struct call_ctx *)(rpc_stack) - 1;
- unreference_proc(get_tcb(ctx->pid));
- }
-
t->regs = ctx->regs;
/* again, get rid of args as fast as possible */
set_args(t, 6, a);
+ struct tcb *r = get_tcb(ctx->pid);
+ while (!r || r->dead) {
+ /* we unwound back to our root process which is apparently dead,
+ * we're orphaned :( */
+ if (ctx->pid == t->rid) {
+ orphanize(t);
+ return;
+ }
+
+ rpc_stack = ctx->rpc_stack + BASE_PAGE_SIZE;
+ ctx = (struct call_ctx *)(rpc_stack) - 1;
+
+ r = get_tcb(ctx->pid);
+ }
+
set_return(t, ctx->exec);
/* if we're returning from a failed rpc, this should essentially be a
* no-op */
@@ -301,13 +306,12 @@ static void do_ipc(struct tcb *t,
vm_t s = enter_rpc(t, SYS_RET6(t->eid, t->tid, d0, d1, d2, d3), kind);
struct tcb *r = get_tcb(pid);
- if (unlikely(!r)) {
+ if (unlikely(!r || !is_proc(r))) {
leave_rpc(t, SYS_RET1(ERR_INVAL));
return;
}
- r = get_rproc(r);
- if (unlikely(r->dead)) {
+ if (unlikely(zombie(r))) {
leave_rpc(t, SYS_RET1(ERR_INVAL));
return;
}
@@ -430,7 +434,7 @@ SYSCALL_DEFINE0(ipc_ghost)(struct tcb *t)
* @param tid Thread ID to notify.
* @return \ref OK and 0.
*/
-SYSCALL_DEFINE1(ipc_notify)(struct tcb *t, sys_arg_t tid){
+SYSCALL_DEFINE1(notify)(struct tcb *t, sys_arg_t tid){
if (t->tid != tid && !has_cap(t->caps, CAP_NOTIFY))
return_args1(t, ERR_PERM);