diff options
Diffstat (limited to 'src/uapi')
| -rw-r--r-- | src/uapi/dispatch.c | 1 | ||||
| -rw-r--r-- | src/uapi/ipc.c | 19 | ||||
| -rw-r--r-- | src/uapi/proc.c | 29 |
3 files changed, 41 insertions, 8 deletions
diff --git a/src/uapi/dispatch.c b/src/uapi/dispatch.c index 7cfce4c..c4ad811 100644 --- a/src/uapi/dispatch.c +++ b/src/uapi/dispatch.c @@ -81,6 +81,7 @@ void handle_syscall(sys_arg_t syscall, sys_arg_t a, sys_arg_t b, case SYS_POWEROFF: sys_poweroff(t, a, b, c, d, e); break; case SYS_SLEEP: sys_sleep(t, a, b, c, d, e); break; case SYS_IRQ_REQ: sys_irq_req(t, a, b, c, d, e); break; + case SYS_DETACH: sys_detach(t, a, b, c, d, e); break; case SYS_EXIT: sys_exit(t, a, b, c, d, e); break; default: error("Syscall %zu outside allowed range [0 - %i]\n", syscall, diff --git a/src/uapi/ipc.c b/src/uapi/ipc.c index f3896f5..bc49dbb 100644 --- a/src/uapi/ipc.c +++ b/src/uapi/ipc.c @@ -83,7 +83,7 @@ static vm_t enter_rpc(struct tcb *t, struct sys_ret a, { /* 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); + is_rpc(t)) ? t->rpc_stack : rpc_position(t); struct call_ctx *ctx = (struct call_ctx *)(rpc_stack) - 1; ctx->regs = t->regs; @@ -179,8 +179,8 @@ void notify(struct tcb *t, enum notify_flag flag) return; struct tcb *r = get_tcb(t->notify_id); - if (!r || !r->callback) { - error("notify callback dead\n"); + if (!r || r->state || !r->callback) { + error("notify callback unavailable\n"); t->notify_flags = 0; return; } @@ -218,31 +218,34 @@ static void leave_rpc(struct tcb *t, struct sys_ret a) { vm_t rpc_stack = t->rpc_stack + BASE_PAGE_SIZE; struct call_ctx *ctx = (struct call_ctx *)(rpc_stack) - 1; - vm_t top = ctx->rpc_stack; 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) { + while (!r || !is_proc(r) || zombie(r)) { /* we unwound back to our root process which is apparently dead, * we're orphaned :( */ - if (ctx->pid == t->rid) { + if (rpc_stack_empty(ctx->rpc_stack)) { orphanize(t); - return; + break; } rpc_stack = ctx->rpc_stack + BASE_PAGE_SIZE; ctx = (struct call_ctx *)(rpc_stack) - 1; r = get_tcb(ctx->pid); + set_args1(t, ERR_NF); } + if (orphan(t) && !is_rpc(t)) + unorphanize(t); + set_return(t, ctx->exec); /* if we're returning from a failed rpc, this should essentially be a * no-op */ - mark_rpc_valid(t, top); + mark_rpc_valid(t, ctx->rpc_stack); t->rpc_stack = ctx->rpc_stack; t->pid = ctx->pid; t->eid = ctx->eid; diff --git a/src/uapi/proc.c b/src/uapi/proc.c index 3ce808f..231cc32 100644 --- a/src/uapi/proc.c +++ b/src/uapi/proc.c @@ -235,6 +235,35 @@ SYSCALL_DEFINE1(exit)(struct tcb *t, sys_arg_t tid) } /** + * Syscall handler for orphanizing a thread. + * + * @param t Thread that wants to make itself an orphant. + * @return \ref OK on success, + * \ref ERR_PERM if current process missing \ref CAP_PROC, + * \ref ERR_INVAL if already an orphant. + */ +SYSCALL_DEFINE0(detach)(struct tcb *t) +{ + struct tcb *c = get_cproc(t); + if (!(has_cap(c->caps, CAP_PROC))) + return_args1(t, ERR_PERM); + + if (orphan(t)) + return_args1(t, ERR_INVAL); + + struct tcb *r = get_tcb(t->rid); + if (r) + unreference_proc(r); + + orphanize(t); + + if (!is_rpc(t)) + unorphanize(t); + + return_args1(t, OK); +} + +/** * Swap syscall handler. * * \todo Implement. |
