aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKimplul <kimi.h.kuparinen@gmail.com>2024-07-03 17:41:28 +0300
committerKimplul <kimi.h.kuparinen@gmail.com>2024-07-03 17:47:58 +0300
commit66e7f184a925247bac51aae02d01483faa5454fc (patch)
tree8e4b3d0ce59305ccf5f93fd8f5b75be528a58633
parente06772a964e269d2d9abcb43a1edd868a62d4610 (diff)
downloadkmi-66e7f184a925247bac51aae02d01483faa5454fc.tar.gz
kmi-66e7f184a925247bac51aae02d01483faa5454fc.zip
simplify notifications a little
-rw-r--r--include/kmi/notify.h3
-rw-r--r--include/kmi/syscalls.h2
-rw-r--r--include/kmi/tcb.h3
-rw-r--r--src/uapi/ipc.c83
-rw-r--r--src/uapi/proc.c15
5 files changed, 48 insertions, 58 deletions
diff --git a/include/kmi/notify.h b/include/kmi/notify.h
index 554758c..c0c5d8b 100644
--- a/include/kmi/notify.h
+++ b/include/kmi/notify.h
@@ -28,7 +28,8 @@
* Implemented in uapi/ipc.c.
*
* @param t Thread to send notification to.
- * @param flag Which type of notification to send.
+ * @param flag Which type of notification to send. If 0, sends out queued
+ * notifications if there are any, otherwise just returns.
*/
void notify(struct tcb *t, enum notify_flag flag);
diff --git a/include/kmi/syscalls.h b/include/kmi/syscalls.h
index 92ea264..c78ddae 100644
--- a/include/kmi/syscalls.h
+++ b/include/kmi/syscalls.h
@@ -175,7 +175,7 @@ enum notify_flag {
/** A timer has expired. */
NOTIFY_TIMER = (1 << 1),
- /** An interrupt. */
+ /** An interrupt request. */
NOTIFY_IRQ = (1 << 2),
};
diff --git a/include/kmi/tcb.h b/include/kmi/tcb.h
index 1209a79..b52f5e3 100644
--- a/include/kmi/tcb.h
+++ b/include/kmi/tcb.h
@@ -181,9 +181,6 @@ struct tcb {
* this id, might change in the future. */
id_t notify_id;
- /** Notifcation state of thread. */
- enum tcb_notify notify_state;
-
/** Currently waiting notifications. */
enum notify_flag notify_flags;
diff --git a/src/uapi/ipc.c b/src/uapi/ipc.c
index a020dc0..069ca59 100644
--- a/src/uapi/ipc.c
+++ b/src/uapi/ipc.c
@@ -148,19 +148,28 @@ static bool __enough_rpc_stack(struct tcb *t)
*/
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;
+
+ /* handle critical notifications with special care */
+ if (is_set(flags, NOTIFY_IRQ | NOTIFY_TIMER)) {
+ set_bits(flags, t->notify_flags & (NOTIFY_IRQ | NOTIFY_TIMER));
+ disable_irqs();
+ }
+
/* signal to whoever is receiving us that we're from the kernel
* ("pid 0"), and we are notifying the current thread */
vm_t s = enter_rpc(t,
- SYS_RET5(0, SYS_USER_NOTIFY,
- t->notify_flags, t->eid, t->tid),
+ SYS_RET5(0, code, flags, t->eid, t->tid),
IPC_REQ);
finalize_rpc(t, r, s);
- t->notify_state = NOTIFY_RUNNING;
- if (is_set(t->notify_flags, NOTIFY_IRQ | NOTIFY_TIMER))
- disable_irqs();
- t->notify_flags = 0;
+ clear_bits(t->notify_flags, flags);
ret_userspace_fast();
unreachable();
}
@@ -169,35 +178,31 @@ void notify(struct tcb *t, enum notify_flag flag)
{
set_bits(t->notify_flags, flag);
- if (t->notify_state == NOTIFY_RUNNING) {
- t->notify_state = NOTIFY_QUEUED;
+ if (!t->notify_flags)
return;
- }
-
- if (t == cur_tcb())
- __run_notify(t, t);
struct tcb *r = get_tcb(t->notify_id);
if (!r || !r->callback) {
error("notify callback dead\n");
- t->notify_state = NOTIFY_WAITING;
t->notify_flags = 0;
return;
}
- if (is_rpc(r)) {
- t->notify_state = NOTIFY_QUEUED;
+ /* signals are only run when thread is in root process, whereas
+ * interrupts are always run (if the resources allow it, that its */
+ if (!is_set(t->notify_flags, NOTIFY_IRQ | NOTIFY_TIMER) && is_rpc(t))
return;
- }
- if (unlikely(!__enough_rpc_stack(r))) {
- bug("not enough rpc stack in root process?");
- t->notify_state = NOTIFY_WAITING;
- t->notify_flags = 0;
+ /* we're either in the root process or we have a critical notification,
+ * check that there's enough rpc stack, otherwise wait and try again
+ * later */
+ if (unlikely(!__enough_rpc_stack(r)))
return;
- }
- if (running(r)) {
+ /* if someone else is running the thread we would like to send a
+ * notification to, do an ipi. Otherwise, either we're currently running
+ * it or the thread is idle, either is fine for __run_notify(). */
+ if (running(r) && r != cur_tcb()) {
send_ipi(r);
return;
}
@@ -237,24 +242,16 @@ static void leave_rpc(struct tcb *t, struct sys_ret a)
t->pid = ctx->pid;
t->eid = ctx->eid;
+ /* notification queued, try to run it */
+ if (t->notify_flags)
+ notify(t, 0);
+
if (is_rpc(t)) {
use_vmem(t->rpc.vmem);
return;
}
- if (t->notify_state != NOTIFY_QUEUED) {
- /* turn a potential NOTIFY_RUNNING into NOTIFY_WAITING */
- t->notify_state = NOTIFY_WAITING;
- use_vmem(t->proc.vmem);
- return;
- }
-
- /* notification queued, try to run it */
- notify(t, 0);
-
- /* we failed notifying the thread, shouldn't happen but just return
- * back to process normally */
- bug("failed notifying from ipc_resp\n");
+ /* notification didn't take, return back to process normally */
use_vmem(t->proc.vmem);
}
@@ -343,6 +340,7 @@ static void do_ipc(struct tcb *t,
SYSCALL_DEFINE5(ipc_req)(struct tcb *t, sys_arg_t pid,
sys_arg_t d0, sys_arg_t d1, sys_arg_t d2, sys_arg_t d3)
{
+ enable_irqs();
do_ipc(t, pid, d0, d1, d2, d3, IPC_REQ);
}
@@ -360,6 +358,7 @@ SYSCALL_DEFINE5(ipc_req)(struct tcb *t, sys_arg_t pid,
SYSCALL_DEFINE5(ipc_fwd)(struct tcb *t, sys_arg_t pid,
sys_arg_t d0, sys_arg_t d1, sys_arg_t d2, sys_arg_t d3)
{
+ enable_irqs();
do_ipc(t, pid, d0, d1, d2, d3, IPC_FWD);
}
@@ -378,6 +377,7 @@ SYSCALL_DEFINE5(ipc_kick)(struct tcb *t, sys_arg_t pid,
sys_arg_t d0, sys_arg_t d1, sys_arg_t d2,
sys_arg_t d3)
{
+ enable_irqs();
do_ipc(t, pid, d0, d1, d2, d3, IPC_KICK);
}
@@ -402,6 +402,7 @@ SYSCALL_DEFINE4(ipc_resp)(struct tcb *t, sys_arg_t d0, sys_arg_t d1,
/* inform requester who answered (pid) in the case of the request being
* kicked forward */
+ enable_irqs();
leave_rpc(t, SYS_RET6(OK, t->pid, d0, d1, d2, d3));
}
@@ -416,7 +417,6 @@ SYSCALL_DEFINE0(ipc_ghost)(struct tcb *t)
if (unlikely(!is_rpc(t)))
return_args1(t, ERR_MISC);
- /** @todo this should also enable interrupts when leaving kernel */
enable_irqs();
leave_rpc(t, get_args(t));
}
@@ -431,15 +431,7 @@ SYSCALL_DEFINE0(ipc_ghost)(struct tcb *t)
* @return \ref OK and 0.
*/
SYSCALL_DEFINE1(ipc_notify)(struct tcb *t, sys_arg_t tid){
- if (t->tid == tid) {
- set_args1(t, OK);
- notify(t, NOTIFY_SIGNAL);
- /* notify is guaranteed to run the current thread */
- unreachable();
- return;
- }
-
- if (!has_cap(t->caps, CAP_NOTIFY))
+ if (t->tid != tid && !has_cap(t->caps, CAP_NOTIFY))
return_args1(t, ERR_PERM);
struct tcb *r = get_tcb(tid);
@@ -449,5 +441,6 @@ SYSCALL_DEFINE1(ipc_notify)(struct tcb *t, sys_arg_t tid){
/* set args, if notify swaps us out we pick them up the next time this
* thread is scheduled */
set_args1(t, OK);
+ enable_irqs();
notify(r, NOTIFY_SIGNAL);
}
diff --git a/src/uapi/proc.c b/src/uapi/proc.c
index bb4b463..1b672ce 100644
--- a/src/uapi/proc.c
+++ b/src/uapi/proc.c
@@ -13,6 +13,8 @@
#include <kmi/notify.h>
#include <kmi/mem_regions.h>
+#include <arch/irq.h>
+
/**
* Create syscall handler.
*
@@ -190,17 +192,14 @@ SYSCALL_DEFINE1(swap)(struct tcb *t, sys_arg_t tid){
/* set return value for current thread */
set_args1(t, OK);
- /* not running anymore lol */
- if (t->notify_state == NOTIFY_RUNNING)
- t->notify_state = NOTIFY_WAITING;
+ /* if an irq handler is directly swapping to some other thread,
+ * interpret it as the thread being finished with its critical section */
+ enable_irqs();
/* handle possible queued notification */
- if (s->notify_state == NOTIFY_QUEUED)
+ if (s->notify_flags)
notify(s, 0);
- /* if an irq handler is directly swapping to some other thread,
- * interpret it as the thread being finished with its critical section */
- enable_irqs();
- /* get register state for new thread */
+ /* no notifications, so get register state for new thread */
return_args(s, get_args(s));
}