aboutsummaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
Diffstat (limited to 'include')
-rw-r--r--include/kmi/caps.h4
-rw-r--r--include/kmi/ipi.h8
-rw-r--r--include/kmi/list.h156
-rw-r--r--include/kmi/notify.h30
-rw-r--r--include/kmi/queue.h56
-rw-r--r--include/kmi/syscalls.h16
-rw-r--r--include/kmi/tcb.h17
-rw-r--r--include/kmi/timer.h1
-rw-r--r--include/kmi/uapi.h8
9 files changed, 277 insertions, 19 deletions
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);