From a6557ed0233e2193cef0ab5b4cea7f1d7f19ad5d Mon Sep 17 00:00:00 2001 From: Kimplul Date: Thu, 4 Jul 2024 23:40:37 +0300 Subject: use notification framework for orphanizing threads --- arch/riscv64/kernel/vmem.c | 2 +- include/kmi/syscalls.h | 3 +++ include/kmi/uapi.h | 8 +++----- src/uapi/ipc.c | 15 +++++++++------ src/uapi/proc.c | 26 ++++++++++++++++++-------- 5 files changed, 34 insertions(+), 20 deletions(-) diff --git a/arch/riscv64/kernel/vmem.c b/arch/riscv64/kernel/vmem.c index d4ae937..cc6f3ac 100644 --- a/arch/riscv64/kernel/vmem.c +++ b/arch/riscv64/kernel/vmem.c @@ -520,7 +520,7 @@ void setup_rpc_stack(struct tcb *t) void destroy_rpc_stack(struct tcb *t) { for (size_t i = 0; i < rpc_pages; ++i) { - pm_t page; enum mm_order order; + pm_t page = 0; enum mm_order order = BASE_PAGE; stat_vpage(t->rpc.vmem, RPC_STACK_BASE + BASE_PAGE_SIZE * i, &page, &order, NULL); free_page(page, order); diff --git a/include/kmi/syscalls.h b/include/kmi/syscalls.h index 93d0ac9..4ae0f0b 100644 --- a/include/kmi/syscalls.h +++ b/include/kmi/syscalls.h @@ -186,6 +186,9 @@ enum notify_flag { /** An interrupt request. */ NOTIFY_IRQ = (1 << 2), + + /** Thread has become orphaned. */ + NOTIFY_ORPHANED = (1 << 3), }; /* function declarations should be somewhere else, this file could be used in diff --git a/include/kmi/uapi.h b/include/kmi/uapi.h index 76a759f..42d6e5b 100644 --- a/include/kmi/uapi.h +++ b/include/kmi/uapi.h @@ -843,18 +843,16 @@ SYSCALL_DECLARE1(exit, tid); /** * Request that a thread becomes orphant, i.e. eventually attached to the init - * process. Can be used to stop threads within a process by sending an - * appropriate signal to the troublesome thread which then detaches itself from - * its root process. + * process. Can be used to stop threads within a process. * * @param t Current tcb. - * @param a Unused. + * @param tid Which thread to orphanize. * @param b Unused. * @param c Unused. * @param d Unused. * @param e Unused. */ -SYSCALL_DECLARE0(detach); +SYSCALL_DECLARE1(detach, tid); /** @} */ diff --git a/src/uapi/ipc.c b/src/uapi/ipc.c index bc49dbb..ddc7242 100644 --- a/src/uapi/ipc.c +++ b/src/uapi/ipc.c @@ -138,8 +138,8 @@ static bool __enough_rpc_stack(struct tcb *t) /** * Actually run notification handler, no ifs or buts. * - * @param t Previous thread. - * @param r Next thread. + * @param t Current thread. + * @param r Process where notification handler is. * * \p t and \p r may be the same thread. */ @@ -148,12 +148,15 @@ static __noreturn void __run_notify(struct tcb *t, struct tcb *r) use_tcb(r); enum sys_user code = SYS_USER_NOTIFY; - /* if we're not in RPC, we can safely notify of a signal while we're at - * it */ - enum notify_flag flags = is_rpc(t) ? 0 : NOTIFY_SIGNAL; + enum notify_flag flags = 0; + + /* if we're in the root process, we can safely handle signals and + * becoming orphaned */ + if (!is_rpc(t)) + set_bits(flags, t->notify_flags & (NOTIFY_SIGNAL | NOTIFY_ORPHANED)); /* handle critical notifications with special care */ - if (is_set(flags, NOTIFY_IRQ | NOTIFY_TIMER)) { + if (is_set(t->notify_flags, NOTIFY_IRQ | NOTIFY_TIMER)) { set_bits(flags, t->notify_flags & (NOTIFY_IRQ | NOTIFY_TIMER)); disable_irqs(); } diff --git a/src/uapi/proc.c b/src/uapi/proc.c index 231cc32..5b64dce 100644 --- a/src/uapi/proc.c +++ b/src/uapi/proc.c @@ -92,10 +92,17 @@ SYSCALL_DEFINE0(fork)(struct tcb *t) SYSCALL_DEFINE2(exec)(struct tcb *t, sys_arg_t bin, sys_arg_t interp) { /** @todo probably make sure thread is root thread of process? */ + if (!is_proc(t)) + return_args1(t, ERR_PERM); + + /* exec is only allowed if we own all our own resources */ + if (t->refcount) + return_args1(t, ERR_INVAL) + /* mark binary to be kept */ struct mem_region *b = find_used_region(&t->sp_r, bin); if (!b) - return_args1(t, ERR_INVAL); + return_args1(t, ERR_ADDR); set_bit(b->flags, MR_KEEP); @@ -237,28 +244,31 @@ 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. + * @param t Current thread. + * @param tid Thread we want to orphanize. May be ourselves. * @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) +SYSCALL_DEFINE1(detach)(struct tcb *t, sys_arg_t tid) { struct tcb *c = get_cproc(t); if (!(has_cap(c->caps, CAP_PROC))) return_args1(t, ERR_PERM); - if (orphan(t)) + struct tcb *o = get_tcb(tid); + if (!o || orphan(o)) return_args1(t, ERR_INVAL); - struct tcb *r = get_tcb(t->rid); + struct tcb *r = get_tcb(o->rid); if (r) unreference_proc(r); - orphanize(t); + orphanize(o); - if (!is_rpc(t)) - unorphanize(t); + /* generally the thread shouldn't do anything with this information, but + * it fits really nicely into the notification framework so just do it */ + notify(o, NOTIFY_ORPHANED); return_args1(t, OK); } -- cgit v1.3