aboutsummaryrefslogtreecommitdiff
path: root/common
diff options
context:
space:
mode:
Diffstat (limited to 'common')
-rw-r--r--common/dispatch.c12
-rw-r--r--common/ipi.c32
-rw-r--r--common/tcb.c16
-rw-r--r--common/uapi/dispatch.c9
-rw-r--r--common/uapi/ipc.c42
5 files changed, 77 insertions, 34 deletions
diff --git a/common/dispatch.c b/common/dispatch.c
new file mode 100644
index 0000000..1325d62
--- /dev/null
+++ b/common/dispatch.c
@@ -0,0 +1,12 @@
+#include <apos/uapi.h>
+#include <apos/ipi.h>
+
+struct sys_ret dispatch(sys_arg_t a, sys_arg_t b, sys_arg_t c,
+ sys_arg_t d, sys_arg_t e, sys_arg_t f)
+{
+ struct tcb *t = cur_tcb();
+ if (clear_ipi(t))
+ return handle_ipi(t);
+
+ return handle_syscall(t, a, b, c, d, e, f);
+}
diff --git a/common/ipi.c b/common/ipi.c
new file mode 100644
index 0000000..32f1432
--- /dev/null
+++ b/common/ipi.c
@@ -0,0 +1,32 @@
+#include <apos/ipi.h>
+#include <arch/cpu.h>
+
+#include <arch/proc.h>
+
+/**
+ * @file ipi.c
+ *
+ * IPI function implementations.
+ */
+
+bool clear_ipi(struct tcb *t)
+{
+ bool r = t->ipi;
+ t->ipi = false;
+ return r;
+}
+
+void send_ipi(struct tcb *t)
+{
+ t->ipi = true;
+ cpu_send_ipi(t->cpu_id);
+}
+
+struct sys_ret handle_ipi(struct tcb *t)
+{
+ adjust_ipi(t);
+
+ /** @todo use rpc stack */
+ set_return(t, t->callback);
+ return get_args(t);
+}
diff --git a/common/tcb.c b/common/tcb.c
index 9000941..417ca45 100644
--- a/common/tcb.c
+++ b/common/tcb.c
@@ -36,7 +36,7 @@ static struct tcb **tcbs;
* \todo If we ever support systems with massive amounts of cpus, this should probably
* be allocated at runtime.
*/
-static struct tcb *cpu_tcb[MAX_CPUS] = { 0 };
+static struct tcb *__cpu_tcb[MAX_CPUS] = { 0 };
void init_tcbs()
{
@@ -294,7 +294,12 @@ DEFINE_DETACH(detach_proc, proc);
/* weak to allow optimisation on risc-v, but provide fallback for future */
__weak struct tcb *cur_tcb()
{
- return cpu_tcb[cpu_id()];
+ return cpu_tcb(cpu_id());
+}
+
+struct tcb *cpu_tcb(id_t cpu_id)
+{
+ return __cpu_tcb[cpu_id];
}
struct tcb *cur_proc()
@@ -313,7 +318,7 @@ void use_tcb(struct tcb *t)
{
cpu_assign(t);
- cpu_tcb[t->cpu_id] = t;
+ __cpu_tcb[t->cpu_id] = t;
use_vmem(t->proc.vmem);
}
@@ -355,3 +360,8 @@ void set_return(struct tcb *t, vm_t v)
{
t->exec = v;
}
+
+bool running(struct tcb *t)
+{
+ return cpu_tcb(t->cpu_id) == t;
+}
diff --git a/common/uapi/dispatch.c b/common/uapi/dispatch.c
index 27cc001..2cf19fb 100644
--- a/common/uapi/dispatch.c
+++ b/common/uapi/dispatch.c
@@ -10,6 +10,8 @@
#include <apos/debug.h>
#include <apos/uapi.h>
+#include <arch/proc.h>
+
/** Syscall number to syscall handler conversion. */
static const sys_t syscall_table[] = {
/* noop */
@@ -79,10 +81,11 @@ SYSCALL_DEFINE1(putch)(sys_arg_t a){
return SYS_RET1(OK);
}
-struct sys_ret syscall_dispatch(sys_arg_t syscall, sys_arg_t a, sys_arg_t b,
- sys_arg_t c, sys_arg_t d, sys_arg_t e)
+struct sys_ret handle_syscall(struct tcb *t,
+ sys_arg_t syscall, sys_arg_t a, sys_arg_t b,
+ sys_arg_t c, sys_arg_t d, sys_arg_t e)
{
- struct tcb *t = cur_tcb();
+ adjust_syscall(t);
size_t sc = syscall;
if (sc >= ARRAY_SIZE(syscall_table)) {
diff --git a/common/uapi/ipc.c b/common/uapi/ipc.c
index 34f707a..cb53ee3 100644
--- a/common/uapi/ipc.c
+++ b/common/uapi/ipc.c
@@ -8,6 +8,7 @@
#include <apos/uapi.h>
#include <apos/tcb.h>
+#include <apos/ipi.h>
/**
* IPC server notification syscall handler.
@@ -114,36 +115,21 @@ SYSCALL_DEFINE4(ipc_resp)(sys_arg_t d0, sys_arg_t d1, sys_arg_t d2,
* \todo Implement.
*
* @param tid Thread ID to notify.
- * @param swap Whether to swap immediately if possible.
* @return \ref OK and 0.
*/
-SYSCALL_DEFINE2(ipc_notify)(sys_arg_t tid, sys_arg_t swap){
- /** \todo masquerade as kernel call, set from to 0 and set us as
- * notify type, no arguments as that would require too much state
- * handling for my liking. Instead, a server and a client have to agree
- * on some rpc API, and ipc_notify is just used to asynchronously inform
- * the client that it should check the status of its async operations.
- * Arguably slower than directly telling the client which operation was
- * finished, but this would require the kernel to keep track of a notify
- * stack. While not impossible, probably too complex. */
+SYSCALL_DEFINE1(ipc_notify)(sys_arg_t tid){
+ struct tcb *t = get_tcb(tid);
+ if (t->notify_state == NOTIFY_QUEUED)
+ return SYS_RET1(OK);
+
+ if (t->notify_state == NOTIFY_RUNNING) {
+ t->notify_state = NOTIFY_QUEUED;
+ return SYS_RET1(OK);
+ }
+
+ t->notify_state = NOTIFY_QUEUED;
+ if (running(t))
+ send_ipi(t);
- /* Something like
- *
- * struct tcb *t = get_tcb(tid);
- * if (t->notify_state == NOTIFY_QUEUED)
- * return;
- *
- * if (t->notify_state == NOTIFY_RUNNING) {
- * t->notify = NOTIFY_QUEUED;
- * return;
- * }
- *
- * t->notify_state = NOTIFY_QUEUED;
- * if (swap)
- * do_swap(); // clears t->notify when swapped to
- * // if already running in base state, interrupt,
- * otherwise wait for return from rpc. If not running,
- * just queue the interrupt.
- */
return SYS_RET1(OK);
}