diff options
| author | Kimplul <kimi.h.kuparinen@gmail.com> | 2024-07-02 21:40:10 +0300 |
|---|---|---|
| committer | Kimplul <kimi.h.kuparinen@gmail.com> | 2024-07-02 21:40:10 +0300 |
| commit | 8a3452098267e1af127d6c4f1836a9d82cd23f38 (patch) | |
| tree | c9fad842a8903f64a57027b66ef54bba0dee2928 | |
| parent | 7ad9c01dad7b1b46eced8290b8b991383d648188 (diff) | |
| download | kmi-8a3452098267e1af127d6c4f1836a9d82cd23f38.tar.gz kmi-8a3452098267e1af127d6c4f1836a9d82cd23f38.zip | |
more complete interrupt handling outline
+ Still largely untested, should really try to come up with a proper
testsuite, at the moment it's mostly me trying things out in the (as
of yet unreleased) kmx repo
| -rw-r--r-- | arch/riscv64/conf/init.c | 8 | ||||
| -rw-r--r-- | arch/riscv64/kernel/csr.h | 2 | ||||
| -rw-r--r-- | arch/riscv64/kernel/irq.c | 8 | ||||
| -rw-r--r-- | include/kmi/caps.h | 4 | ||||
| -rw-r--r-- | include/kmi/ipi.h | 8 | ||||
| -rw-r--r-- | include/kmi/list.h | 156 | ||||
| -rw-r--r-- | include/kmi/notify.h | 30 | ||||
| -rw-r--r-- | include/kmi/queue.h | 56 | ||||
| -rw-r--r-- | include/kmi/syscalls.h | 16 | ||||
| -rw-r--r-- | include/kmi/tcb.h | 17 | ||||
| -rw-r--r-- | include/kmi/timer.h | 1 | ||||
| -rw-r--r-- | include/kmi/uapi.h | 8 | ||||
| -rw-r--r-- | src/ipi.c | 26 | ||||
| -rw-r--r-- | src/irq.c | 6 | ||||
| -rw-r--r-- | src/proc.c | 3 | ||||
| -rw-r--r-- | src/timer.c | 2 | ||||
| -rw-r--r-- | src/uapi/dispatch.c | 3 | ||||
| -rw-r--r-- | src/uapi/ipc.c | 114 | ||||
| -rw-r--r-- | src/uapi/irq.c | 12 | ||||
| -rw-r--r-- | src/uapi/proc.c | 9 |
20 files changed, 411 insertions, 78 deletions
diff --git a/arch/riscv64/conf/init.c b/arch/riscv64/conf/init.c index 80bb68a..010267e 100644 --- a/arch/riscv64/conf/init.c +++ b/arch/riscv64/conf/init.c @@ -36,7 +36,8 @@ char *strcpy(char * restrict dst, const char * restrict src) } static inline struct sys_ret ecall(size_t n, - sys_arg_t arg0, sys_arg_t arg1, sys_arg_t arg2, sys_arg_t arg3, + sys_arg_t arg0, sys_arg_t arg1, + sys_arg_t arg2, sys_arg_t arg3, sys_arg_t arg4, sys_arg_t arg5) { /* here a static assert of n <= 6 && n >= 1 would be ideal */ @@ -186,8 +187,9 @@ static void sys_ipc_server(void *f) } static inline struct sys_ret sys_ipc_req(sys_arg_t pid, - sys_arg_t d0, sys_arg_t d1, sys_arg_t d2, - sys_arg_t d3) + sys_arg_t d0, sys_arg_t d1, + sys_arg_t d2, + sys_arg_t d3) { struct sys_ret r = ecall6(SYS_IPC_REQ, pid, d0, d1, d2, d3); diff --git a/arch/riscv64/kernel/csr.h b/arch/riscv64/kernel/csr.h index bc48464..9b7b78a 100644 --- a/arch/riscv64/kernel/csr.h +++ b/arch/riscv64/kernel/csr.h @@ -40,8 +40,6 @@ /** Address of \c sstatus CSR. */ #define CSR_SSTATUS 0x100 -#define SR_SPIE 0b10 - /** Address of \c sie CSR. */ #define CSR_SIE 0x104 diff --git a/arch/riscv64/kernel/irq.c b/arch/riscv64/kernel/irq.c index 2ef15cc..0c129b9 100644 --- a/arch/riscv64/kernel/irq.c +++ b/arch/riscv64/kernel/irq.c @@ -38,16 +38,18 @@ stat_t deactivate_irq(irq_t id) return OK; } +/** Bit pattern representing supervisor external, timer and software irqs. */ +#define SR_IRQS (1 << 9) | (1 << 5) | (1 << 3) + /* very simple for now */ void enable_irqs() { - /* should be supervisor external interrupt */ - csr_set(CSR_SIE, 1 << 9); + csr_set(CSR_SIE, SR_IRQS); } void disable_irqs() { - csr_clear(CSR_SIE, 1 << 9); + csr_clear(CSR_SIE, SR_IRQS); } irq_t get_irq() diff --git a/include/kmi/caps.h b/include/kmi/caps.h index 8af9293..158845d 100644 --- a/include/kmi/caps.h +++ b/include/kmi/caps.h @@ -27,7 +27,7 @@ enum { CAP_PROC = (1 << 1), /** Thread is allowed to force notification in other thread. */ - CAP_CALL = (1 << 2), + CAP_NOTIFY = (1 << 2), /** Thread is allowed to shut down system. */ CAP_POWER = (1 << 3), @@ -39,7 +39,7 @@ enum { CAP_IRQ = (1 << 5), /** Thread is allowed to request notification handler. */ - CAP_NOTIFICATION = (1 << 6), + CAP_SIGNAL = (1 << 6), }; /** diff --git a/include/kmi/ipi.h b/include/kmi/ipi.h index 72b54b9..7a0760a 100644 --- a/include/kmi/ipi.h +++ b/include/kmi/ipi.h @@ -15,14 +15,6 @@ #include <kmi/tcb.h> /** - * Clear potential IPI in \p t, and return its value. - * - * @param t \ref tcb to clear possible IPI status of. - * @return \ref true if \p was interrupted by IPI, \ref false otherwise. - */ -bool clear_ipi(struct tcb *t); - -/** * Send IPI to \p t. Assumes \c running(t). * * @param t \ref tcb to send IPI to. diff --git a/include/kmi/list.h b/include/kmi/list.h new file mode 100644 index 0000000..07cddd1 --- /dev/null +++ b/include/kmi/list.h @@ -0,0 +1,156 @@ +/* SPDX-License-Identifier: copyleft-next-0.3.1 */ +/* Copyright 2024, Kim Kuparinen < kimi.h.kuparinen@gmail.com > */ + +#ifndef KMI_LIST_H +#define KMI_LIST_H + +/** + * @file list.h + * + * Relatively simple intrusive doubly-linked list implementation, + * more or less directly lifted from Linux. In Linux, the implementation also + * includes some circular features that I dropped because I don't really need + * them at the moment, but can just be copy-pasted back in (I think? Not a + * license lawyer) + * + * https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/linux/list.h + */ + +/** An entry in a list. Generally there's a head somewhere that is more like + * just 'metadata' about the list. */ +struct list_head { + /** Previous entry. */ + struct list_head *next; + + /** Next entry. */ + struct list_head *prev; +}; + +/** + * Initialized a static list. + * + * @param name Name of list we're initializing, important because an empty list + * should just point to itself. + */ +#define INIT_LIST(name) {.next = &(name), .prev = &(name)} + +/** + * Add \p new between \p prev and \p next. + * + * @param new New entry to add to list. + * @param prev Previous entry. + * @param next Next entry. + */ +static inline void __list_add(struct list_head *new, struct list_head *prev, + struct list_head *next) +{ + next->prev = new; + new->next = next; + new->prev = prev; + prev->next = new; +} + +/** + * Add an entry to the front of the list. + * + * @param new Entry to add. + * @param head Head of list. + */ +static inline void list_add(struct list_head *new, struct list_head *head) +{ + __list_add(new, head, head->next); +} + +/** + * Add an entry to the back of the list. + * + * @param new Entry to add. + * @param head Head of list. + */ +static inline void list_add_tail(struct list_head *new, struct list_head *head) +{ + __list_add(new, head->prev, head); +} + +/** + * Link \p prev to be directly behind \p next and vice versa. + * + * @param prev Previous entry. + * @param next Next entry. + */ +static inline void __list_link(struct list_head *prev, struct list_head *next) +{ + next->prev = prev; + prev->next = next; +} + +/** + * Delete an entry from a list by linking the previous and next nodes together. + * + * @param entry Entry to delete from list. Whatever list that is, doesn't + * matter. + */ +static inline void __list_del_entry(struct list_head *entry) +{ + __list_link(entry->next, entry->prev); +} + +/** + * Delete an entry from a list. Sets next and prev pointers to be NULL. + * + * @param entry Entry to delete from list. + */ +static inline void list_del(struct list_head *entry) +{ + __list_del_entry(entry); + entry->next = NULL; + entry->prev = NULL; +} + +/** + * Check if entry is part of some list. + * + * @param entry Entry whose list occupancy should be checked. + * @return \ref true if entry is in some list, \ref false otherwise. + */ +static inline bool in_list(struct list_head *entry) +{ + return entry->next != NULL; +} + +/** + * Check if list is empty. + * + * @param head Head of list. + * @return \ref true if list is empty, \ref false otherwise. + */ +static inline bool list_empty(struct list_head *head) +{ + return head->next == head; +} + +/** + * @param head Head of list. + * @return First entry in list or NULL if empty. + */ +static inline struct list_head *list_front(struct list_head *head) +{ + if (list_empty(head)) + return NULL; + + return head->next; +} + +/** + * @param head Head of list. + * @return First entry in list or NULL if empty. + */ +static inline struct list_head *list_back(struct list_head *head) +{ + if (list_empty(head)) + return NULL; + + return head->prev; +} + +#endif /* KMI_LIST_H */ diff --git a/include/kmi/notify.h b/include/kmi/notify.h index 0a17654..554758c 100644 --- a/include/kmi/notify.h +++ b/include/kmi/notify.h @@ -1,9 +1,35 @@ +/* SPDX-License-Identifier: copyleft-next-0.3.1 */ +/* Copyright 2024, Kim Kuparinen < kimi.h.kuparinen@gmail.com > */ + #ifndef KMI_NOTIFY_H #define KMI_NOTIFY_H +/** + * @file notify.h + * + * Notification handling stuff. + */ + +#include <kmi/syscalls.h> #include <kmi/tcb.h> -/* Implemented in ipc.c */ -void notify(struct tcb *t); +/** + * Try to send a notification to a thread. Sets up a new rpc call, should be + * returned from with \ref ipc_ghost() to restore register state. + * + * If the thread is idle, immediately swap to it. + * + * If the thread is doing an rpc, queue the notification to be executed when the + * thread returns to the parent process. + * + * If the thread is currently executing on another core, send an ipi to + * the core to switch threads. + * + * Implemented in uapi/ipc.c. + * + * @param t Thread to send notification to. + * @param flag Which type of notification to send. + */ +void notify(struct tcb *t, enum notify_flag flag); #endif /* KMI_NOTIFY_H */ diff --git a/include/kmi/queue.h b/include/kmi/queue.h new file mode 100644 index 0000000..534318a --- /dev/null +++ b/include/kmi/queue.h @@ -0,0 +1,56 @@ +/* SPDX-License-Identifier: copyleft-next-0.3.1 */ +/* Copyright 2024, Kim Kuparinen < kimi.h.kuparinen@gmail.com > */ + +#ifndef KMI_QUEUE_H +#define KMI_QUEUE_H + +/** + * @file queue.h + * + * Wrapper around lists to make things a bit more readable. + */ + +#include <kmi/list.h> + +/** A queue. */ +struct queue_head { + /** A queue is pretty much just a list. */ + struct list_head l; +}; + +/** Initialize static queue. */ +#define INIT_QUEUE(name) {.l = INIT_LIST((name).l)} + +/** + * Push an entry to the back of the queue. + * If \p new already exists in some queue, nothing is done. + * + * @param new Entry to push. + * @param head Head of queue. + */ +static inline void queue_push(struct queue_head *new, struct queue_head *head) +{ + /* if new is already in list, don't change its relative positioning */ + if (in_list(&new->l)) + return; + + list_add_tail(&new->l, &head->l); +} + +/** + * Pop an entry from the front of the queue. + * + * @param head Head of queue. + * @return Front of queue or NULL if empty. + */ +static inline struct queue_head *queue_pop(struct queue_head *head) +{ + struct list_head *e = list_front(&head->l); + if (!e) + return NULL; + + list_del(e); + return container_of(e, struct queue_head, l); +} + +#endif /* QUEUE_H */ diff --git a/include/kmi/syscalls.h b/include/kmi/syscalls.h index 23fc799..92ea264 100644 --- a/include/kmi/syscalls.h +++ b/include/kmi/syscalls.h @@ -159,10 +159,26 @@ enum sys_code { SYS_NUM, }; +/** Operation codes for reverse requests, i.e. where the kernel wants userspace + * to do something. */ enum sys_user { + /** Thread has received one or several notifications, please handle + * them. */ SYS_USER_NOTIFY, }; +/** Which notifications have arrived. */ +enum notify_flag { + /** A signal (\ref ipc_notify()). */ + NOTIFY_SIGNAL = (1 << 0), + + /** A timer has expired. */ + NOTIFY_TIMER = (1 << 1), + + /** An interrupt. */ + NOTIFY_IRQ = (1 << 2), +}; + /* function declarations should be somewhere else, this file could be used in * userspace applications as well */ diff --git a/include/kmi/tcb.h b/include/kmi/tcb.h index 999b6a8..1209a79 100644 --- a/include/kmi/tcb.h +++ b/include/kmi/tcb.h @@ -13,9 +13,11 @@ struct tcb; #include <kmi/mem_regions.h> +#include <kmi/syscalls.h> #include <kmi/atomic.h> -#include <kmi/caps.h> +#include <kmi/queue.h> #include <kmi/types.h> +#include <kmi/caps.h> #include <arch/tcb.h> /* arch-specific data */ /** @@ -135,9 +137,6 @@ struct tcb { */ struct tcb_ctx server; - /** Notifcation state of thread. */ - enum tcb_notify notify_state; - /** * Effective process ID. * @@ -182,11 +181,17 @@ 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; + /** Capabilities of thread. */ capflags_t caps; - /** Whether thread has gotten an IPI */ - bool ipi; + /** Queue that connects together threads waiting for an ipi */ + struct queue_head ipi_queue; /** Whether thread is dead. If thread is process, then corresponds to * whole process. */ diff --git a/include/kmi/timer.h b/include/kmi/timer.h index 7c16f36..4493699 100644 --- a/include/kmi/timer.h +++ b/include/kmi/timer.h @@ -133,6 +133,7 @@ static inline ticks_t secs_to_ticks(tunit_t secs) return msecs_to_ticks(secs * 1000); } +/** Callback for timer IRQs. */ void handle_timer(); #endif /* KMI_TIMER_H */ diff --git a/include/kmi/uapi.h b/include/kmi/uapi.h index 1631500..00fb45a 100644 --- a/include/kmi/uapi.h +++ b/include/kmi/uapi.h @@ -561,8 +561,14 @@ SYSCALL_DECLARE4(ipc_resp, d0, d1, d2, d3); * returning from interrupt handlers, like notifications, timers or external * devices. * - * @param r Current tcb. + * @param t Current tcb. + * @param a Unused. + * @param b Unused. + * @param c Unused. + * @param d Unused. + * @param e Unused. * + * Return OK. */ SYSCALL_DECLARE0(ipc_ghost); @@ -2,27 +2,27 @@ /* Copyright 2023 Kim Kuparinen < kimi.h.kuparinen@gmail.com > */ #include <kmi/notify.h> +#include <kmi/queue.h> #include <kmi/ipi.h> #include <arch/proc.h> #include <arch/cpu.h> +/** List for keeping track of which threads have an ipi queued. */ +static struct queue_head fifo = INIT_QUEUE(fifo); + /** * @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; + /** @todo this should probably have a spinlock guard */ + /** @todo killing a thread should make sure it gets removed from ipi + * queue */ + queue_push(&fifo, &t->ipi_queue); cpu_send_ipi(t->cpu_id); } @@ -31,9 +31,11 @@ void handle_ipi() struct tcb *t = cur_tcb(); adjust_ipi(t); - /** @todo how do we get the target thread? What if multiple threads send - * ipis at the same time? */ - struct tcb *r = NULL; - notify(r); + struct queue_head *q = queue_pop(&fifo); + if (!q) + return; + + struct tcb *r = container_of(q, struct tcb, ipi_queue); + notify(r, 0); /* notify didn't take for whatever reason so return whence we came from */ } @@ -67,12 +67,12 @@ void handle_irq() struct tcb *t = get_tcb(tid); if (!t) { error("tcb %llu dead at irq %llu\n", - (unsigned long long)tid, - (unsigned long long)id); + (unsigned long long)tid, + (unsigned long long)id); return; } disable_irqs(); - notify(t); + notify(t, NOTIFY_IRQ); error("misc error when trying to notify irq"); } @@ -46,7 +46,8 @@ stat_t init_proc(void *fdt) use_tcb(t); /* init process has all capabilities */ - set_caps(t->caps, 0, CAP_CAPS | CAP_PROC | CAP_CALL | CAP_POWER); + set_caps(t->caps, 0, + CAP_CAPS | CAP_PROC | CAP_SIGNAL | CAP_POWER | CAP_NOTIFY); t->notify_id = t->tid; diff --git a/src/timer.c b/src/timer.c index 5af03e8..2607584 100644 --- a/src/timer.c +++ b/src/timer.c @@ -204,5 +204,5 @@ void handle_timer() if (!r) return; - notify(r); + notify(r, NOTIFY_TIMER); } diff --git a/src/uapi/dispatch.c b/src/uapi/dispatch.c index a7f0322..f0ff724 100644 --- a/src/uapi/dispatch.c +++ b/src/uapi/dispatch.c @@ -56,7 +56,8 @@ 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_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; diff --git a/src/uapi/ipc.c b/src/uapi/ipc.c index 8df0e3f..a020dc0 100644 --- a/src/uapi/ipc.c +++ b/src/uapi/ipc.c @@ -6,6 +6,7 @@ * Interprocess communication syscall implementations. */ +#include <kmi/debug.h> #include <kmi/uapi.h> #include <kmi/tcb.h> #include <kmi/ipi.h> @@ -127,7 +128,7 @@ static vm_t enter_rpc(struct tcb *t, struct sys_ret a, * @return \c true if there's enough stack left to safely do migration, * \c false otherwise. */ -static bool enough_rpc_stack(struct tcb *t) +static bool __enough_rpc_stack(struct tcb *t) { /* get top of call stack */ vm_t top = rpc_position(t); @@ -137,27 +138,71 @@ static bool enough_rpc_stack(struct tcb *t) return top - BASE_PAGE_SIZE - __rpc_stack_size >= RPC_STACK_BASE; } -void notify(struct tcb *t) +/** + * Actually run notification handler, no ifs or buts. + * + * @param t Previous thread. + * @param r Next thread. + * + * \p t and \p r may be the same thread. + */ +static __noreturn void __run_notify(struct tcb *t, struct tcb *r) { - /* some duplication from do_ipc, but not too bad I guess */ - struct tcb *notify = get_tcb(t->notify_id); - if (!notify || !notify->callback) { + /* 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), + 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; + ret_userspace_fast(); + unreachable(); +} + +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; + 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 (unlikely(!enough_rpc_stack(t))) { + if (is_rpc(r)) { + t->notify_state = NOTIFY_QUEUED; + return; + } + + if (unlikely(!__enough_rpc_stack(r))) { + bug("not enough rpc stack in root process?"); t->notify_state = NOTIFY_WAITING; + t->notify_flags = 0; 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(); + if (running(r)) { + send_ipi(r); + return; + } + + __run_notify(t, r); } /** @@ -204,10 +249,12 @@ static void leave_rpc(struct tcb *t, struct sys_ret a) return; } - notify(t); + /* notification queued, try to run it */ + notify(t, 0); - /* we failed in notifying the thread, so just return back to the - * process normally */ + /* we failed notifying the thread, shouldn't happen but just return + * back to process normally */ + bug("failed notifying from ipc_resp\n"); use_vmem(t->proc.vmem); } @@ -251,7 +298,7 @@ static void do_ipc(struct tcb *t, sys_arg_t d3, enum ipc_kind kind) { - if (unlikely(!enough_rpc_stack(t))) + if (unlikely(!__enough_rpc_stack(t))) return_args1(t, ERR_OOMEM); vm_t s = enter_rpc(t, SYS_RET6(t->eid, t->tid, d0, d1, d2, d3), kind); @@ -358,6 +405,12 @@ 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)); } +/** + * Ghost return, resetting register state. + * + * @param t Current tcb. + * @return The previous registers of thread. + */ SYSCALL_DEFINE0(ipc_ghost)(struct tcb *t) { if (unlikely(!is_rpc(t))) @@ -379,25 +432,22 @@ SYSCALL_DEFINE0(ipc_ghost)(struct tcb *t) */ SYSCALL_DEFINE1(ipc_notify)(struct tcb *t, sys_arg_t tid){ if (t->tid == tid) { - /** @todo notify self */ + set_args1(t, OK); + notify(t, NOTIFY_SIGNAL); + /* notify is guaranteed to run the current thread */ + unreachable(); + return; } - if (!has_cap(t->caps, CAP_CALL)) + if (!has_cap(t->caps, CAP_NOTIFY)) return_args1(t, ERR_PERM); struct tcb *r = get_tcb(tid); - if (r->notify_state == NOTIFY_QUEUED) - return_args1(t, OK); + if (!r) + return_args1(t, ERR_INVAL); - if (r->notify_state == NOTIFY_RUNNING) { - t->notify_state = NOTIFY_QUEUED; - return_args1(t, OK); - } - - r->notify_state = NOTIFY_QUEUED; - /* only interrupt if thread is in owning process */ - if (running(r) && r->rid == r->pid) - send_ipi(r); - - return_args1(t, OK); + /* set args, if notify swaps us out we pick them up the next time this + * thread is scheduled */ + set_args1(t, OK); + notify(r, NOTIFY_SIGNAL); } diff --git a/src/uapi/irq.c b/src/uapi/irq.c index 9bd8ec1..29da614 100644 --- a/src/uapi/irq.c +++ b/src/uapi/irq.c @@ -13,6 +13,7 @@ * Actual IRQ handling request syscall handler. * * @param t Current tcb. + * @param id Which IRQ number to register. * * @return OK on success, non-zero otherwise. */ @@ -27,9 +28,18 @@ SYSCALL_DEFINE1(irq_req)(struct tcb *t, sys_arg_t id) return_args1(t, register_irq(t, id)); } +/** + * Actual notification handler setter. + * + * @param t Current tcb. + * @param tid Thread whose handler to set. + * @param pid Process that is willing to handle notifications for the thread. + * + * @return OK on success, non-zero otherwise. + */ SYSCALL_DEFINE2(req_notification)(struct tcb *t, sys_arg_t tid, sys_arg_t pid) { - if (!has_cap(t->caps, CAP_NOTIFICATION)) + if (!has_cap(t->caps, CAP_SIGNAL)) return_args1(t, ERR_PERM); struct tcb *r = get_tcb(tid); diff --git a/src/uapi/proc.c b/src/uapi/proc.c index 153b183..e87a2ec 100644 --- a/src/uapi/proc.c +++ b/src/uapi/proc.c @@ -10,6 +10,7 @@ #include <kmi/uapi.h> #include <kmi/proc.h> #include <kmi/bits.h> +#include <kmi/notify.h> #include <kmi/mem_regions.h> /** @@ -186,6 +187,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; + + /* handle possible queued notification */ + if (s->notify_state == NOTIFY_QUEUED) + notify(s, 0); + /* get register state for new thread */ return_args(s, get_args(s)); } |
