diff options
| author | Kimplul <kimi.h.kuparinen@gmail.com> | 2024-07-01 23:34:57 +0300 |
|---|---|---|
| committer | Kimplul <kimi.h.kuparinen@gmail.com> | 2024-07-01 23:34:57 +0300 |
| commit | 7ad9c01dad7b1b46eced8290b8b991383d648188 (patch) | |
| tree | cd528648af552974b90117efef431659ef5f0cc6 /src/uapi | |
| parent | 9ff67d879b4695e0c9910b7276f3959c005c7b19 (diff) | |
| download | kmi-7ad9c01dad7b1b46eced8290b8b991383d648188.tar.gz kmi-7ad9c01dad7b1b46eced8290b8b991383d648188.zip | |
expand notifications into interrupt handlers
+ Terminology is still a bit poor, and will still have to write
documentation + implement ipis properly
Diffstat (limited to 'src/uapi')
| -rw-r--r-- | src/uapi/dispatch.c | 2 | ||||
| -rw-r--r-- | src/uapi/ipc.c | 89 | ||||
| -rw-r--r-- | src/uapi/irq.c | 14 | ||||
| -rw-r--r-- | src/uapi/proc.c | 3 |
4 files changed, 89 insertions, 19 deletions
diff --git a/src/uapi/dispatch.c b/src/uapi/dispatch.c index f160091..a7f0322 100644 --- a/src/uapi/dispatch.c +++ b/src/uapi/dispatch.c @@ -56,6 +56,7 @@ void handle_syscall(sys_arg_t syscall, sys_arg_t a, sys_arg_t b, case SYS_FREE_MEM: sys_free_mem(t, a, b, c, d, e); break; case SYS_TIMEBASE: sys_timebase(t, a, b, c, d, e); break; case SYS_TICKS: sys_ticks(t, a, b, c, d, e); break; + case SYS_REQ_NOTIFICATION: sys_req_notification(t, a, b, c, d, e); break; case SYS_REQ_REL_TIMER: sys_req_rel_timer(t, a, b, c, d, e); break; case SYS_REQ_ABS_TIMER: sys_req_abs_timer(t, a, b, c, d, e); break; case SYS_IPC_SERVER: sys_ipc_server(t, a, b, c, d, e); break; @@ -63,6 +64,7 @@ void handle_syscall(sys_arg_t syscall, sys_arg_t a, sys_arg_t b, case SYS_IPC_FWD: sys_ipc_fwd(t, a, b, c, d, e); break; case SYS_IPC_KICK: sys_ipc_kick(t, a, b, c, d, e); break; case SYS_IPC_RESP: sys_ipc_resp(t, a, b, c, d, e); break; + case SYS_IPC_GHOST: sys_ipc_ghost(t, a, b, c, d, e); break; case SYS_IPC_NOTIFY: sys_ipc_notify(t, a, b, c, d, e); break; case SYS_CREATE: sys_create(t, a, b, c, d, e); break; case SYS_FORK: sys_fork(t, a, b, c, d, e); break; diff --git a/src/uapi/ipc.c b/src/uapi/ipc.c index bc836fc..8df0e3f 100644 --- a/src/uapi/ipc.c +++ b/src/uapi/ipc.c @@ -9,6 +9,7 @@ #include <kmi/uapi.h> #include <kmi/tcb.h> #include <kmi/ipi.h> +#include <kmi/irq.h> #include <kmi/conf.h> /** Structure for maintaining the required context data for an rpc call. */ @@ -120,7 +121,48 @@ static vm_t enter_rpc(struct tcb *t, struct sys_ret a, } /** + * Check that there's enough stack left for an rpc invocation. + * + * @param t Thread whose migration to check. + * @return \c true if there's enough stack left to safely do migration, + * \c false otherwise. + */ +static bool enough_rpc_stack(struct tcb *t) +{ + /* get top of call stack */ + vm_t top = rpc_position(t); + + /* if we can still fit an rpc stack into the call stack, we can safely + * do the migration. */ + return top - BASE_PAGE_SIZE - __rpc_stack_size >= RPC_STACK_BASE; +} + +void notify(struct tcb *t) +{ + /* some duplication from do_ipc, but not too bad I guess */ + struct tcb *notify = get_tcb(t->notify_id); + if (!notify || !notify->callback) { + t->notify_state = NOTIFY_WAITING; + return; + } + + if (unlikely(!enough_rpc_stack(t))) { + t->notify_state = NOTIFY_WAITING; + return; + } + + /* 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_RET4(0, SYS_USER_NOTIFY, t->eid, t->tid), IPC_REQ); + finalize_rpc(t, notify, s); + t->notify_state = NOTIFY_RUNNING; + ret_userspace_fast(); + unreachable(); +} + +/** * Jump back to process where rpc came from, assuming such a thing exists. + * If we're queued for a notification, jump to it instead. * * @param t Thread to do return migration on. * @param a Arguments to pass along. @@ -150,27 +192,23 @@ static void leave_rpc(struct tcb *t, struct sys_ret a) t->pid = ctx->pid; t->eid = ctx->eid; - if (is_rpc(t)) + if (is_rpc(t)) { use_vmem(t->rpc.vmem); - else + 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; + } -/** - * Check that there's enough stack left for an rpc invocation. - * - * @param t Thread whose migration to check. - * @return \c true if there's enough stack left to safely do migration, - * \c false otherwise. - */ -static bool enough_rpc_stack(struct tcb *t) -{ - /* get top of call stack */ - vm_t top = rpc_position(t); + notify(t); - /* if we can still fit an rpc stack into the call stack, we can safely - * do the migration. */ - return top - BASE_PAGE_SIZE - __rpc_stack_size >= RPC_STACK_BASE; + /* we failed in notifying the thread, so just return back to the + * process normally */ + use_vmem(t->proc.vmem); } /** @@ -320,6 +358,16 @@ SYSCALL_DEFINE4(ipc_resp)(struct tcb *t, sys_arg_t d0, sys_arg_t d1, leave_rpc(t, SYS_RET6(OK, t->pid, d0, d1, d2, d3)); } +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)); +} + /** * Notify syscall handler. * @@ -330,6 +378,10 @@ SYSCALL_DEFINE4(ipc_resp)(struct tcb *t, sys_arg_t d0, sys_arg_t d1, * @return \ref OK and 0. */ SYSCALL_DEFINE1(ipc_notify)(struct tcb *t, sys_arg_t tid){ + if (t->tid == tid) { + /** @todo notify self */ + } + if (!has_cap(t->caps, CAP_CALL)) return_args1(t, ERR_PERM); @@ -343,7 +395,8 @@ SYSCALL_DEFINE1(ipc_notify)(struct tcb *t, sys_arg_t tid){ } r->notify_state = NOTIFY_QUEUED; - if (running(r)) + /* only interrupt if thread is in owning process */ + if (running(r) && r->rid == r->pid) send_ipi(r); return_args1(t, OK); diff --git a/src/uapi/irq.c b/src/uapi/irq.c index 6687826..9bd8ec1 100644 --- a/src/uapi/irq.c +++ b/src/uapi/irq.c @@ -13,7 +13,6 @@ * Actual IRQ handling request syscall handler. * * @param t Current tcb. - * @param id IRQ id to request to handle. * * @return OK on success, non-zero otherwise. */ @@ -27,3 +26,16 @@ SYSCALL_DEFINE1(irq_req)(struct tcb *t, sys_arg_t id) return_args1(t, register_irq(t, id)); } + +SYSCALL_DEFINE2(req_notification)(struct tcb *t, sys_arg_t tid, sys_arg_t pid) +{ + if (!has_cap(t->caps, CAP_NOTIFICATION)) + return_args1(t, ERR_PERM); + + struct tcb *r = get_tcb(tid); + if (!r) + return_args1(t, ERR_INVAL); + + t->notify_id = pid; + return_args1(t, OK); +} diff --git a/src/uapi/proc.c b/src/uapi/proc.c index e7fa49d..153b183 100644 --- a/src/uapi/proc.c +++ b/src/uapi/proc.c @@ -37,6 +37,7 @@ SYSCALL_DEFINE5(create)(struct tcb *t, sys_arg_t func, set_args5(c, c->tid, d0, d1, d2, d3); set_return(c, func); + c->notify_id = t->notify_id; return_args2(t, OK, c->tid); } @@ -70,6 +71,7 @@ SYSCALL_DEFINE0(fork)(struct tcb *t) * parent ID as third return value */ set_args3(n, OK, 0, get_eproc(t)->pid); + n->notify_id = c->notify_id; return_args2(t, OK, n->pid); } @@ -132,6 +134,7 @@ SYSCALL_DEFINE2(spawn)(struct tcb *t, sys_arg_t bin, sys_arg_t interp) if (!n) return_args1(t, ERR_OOMEM); + n->notify_id = c->notify_id; return_args2(t, prepare_proc(n, bin, interp), n->pid); } |
