aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKimplul <kimi.h.kuparinen@gmail.com>2024-07-04 23:40:37 +0300
committerKimplul <kimi.h.kuparinen@gmail.com>2024-07-04 23:40:37 +0300
commita6557ed0233e2193cef0ab5b4cea7f1d7f19ad5d (patch)
tree1562d5100331d45395b009be44a612a7c792108e
parentfdbc5adf83741d7e3af0c3f0ffdb59bdf42493b6 (diff)
downloadkmi-a6557ed0233e2193cef0ab5b4cea7f1d7f19ad5d.tar.gz
kmi-a6557ed0233e2193cef0ab5b4cea7f1d7f19ad5d.zip
use notification framework for orphanizing threads
-rw-r--r--arch/riscv64/kernel/vmem.c2
-rw-r--r--include/kmi/syscalls.h3
-rw-r--r--include/kmi/uapi.h8
-rw-r--r--src/uapi/ipc.c15
-rw-r--r--src/uapi/proc.c26
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);
}