summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIan Moffett <ian@osmora.org>2025-12-22 17:21:18 -0500
committerIan Moffett <ian@osmora.org>2025-12-22 17:25:02 -0500
commit7e1c513582fd05bd85f8f4dfa73e374f3ff351ec (patch)
treed52fc7d57a19e18947433a799d2fdc7d789c1e40
parent9116998d45645d24237bd92c45307f7d76f28b59 (diff)
mos: kern: Add spinlock sources
Signed-off-by: Ian Moffett <ian@osmora.org>
-rw-r--r--mos/sys/inc/kern/spinlock.h53
-rw-r--r--mos/sys/kern/kern_spinlock.c72
2 files changed, 125 insertions, 0 deletions
diff --git a/mos/sys/inc/kern/spinlock.h b/mos/sys/inc/kern/spinlock.h
new file mode 100644
index 0000000..3168a1b
--- /dev/null
+++ b/mos/sys/inc/kern/spinlock.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2025, Ian Moffett.
+ * Provided under the BSD-3 clause.
+ */
+
+#ifndef _KERN_SPINLOCK_H_
+#define _KERN_SPINLOCK_H_ 1
+
+#include <sdk/types.h>
+#include <sdk/status.h>
+#include <sdk/param.h>
+
+/* Parameters */
+#define SPINLOCK_NAMELEN 16
+
+/* Flags */
+#define SPINLOCK_IRQMUT BIT(0) /* Mutate IRQ state */
+
+/*
+ * Represents a spinlock
+ *
+ * @name: Spinlock name
+ * @lock: Actual lock
+ */
+typedef struct {
+ char name[SPINLOCK_NAMELEN];
+ USIZE lock;
+} SPINLOCK;
+
+/*
+ * Initialize a spinlock descriptor
+ *
+ * @name: Name of spinlock
+ * @res: Result is written here
+ */
+MOS_STATUS spinlock_init(const char *name, SPINLOCK *res);
+
+/*
+ * Acquire a spinlock
+ *
+ * @lock: Lock to acquire
+ * @flags: Optional flags
+ */
+void spinlock_acquire(SPINLOCK *lock, USHORT flags);
+
+/*
+ * Release a spinlock
+ *
+ * @lock: Lock to release
+ */
+void spinlock_release(SPINLOCK *lock);
+
+#endif /* !_KERN_SPINLOCK_H_ */
diff --git a/mos/sys/kern/kern_spinlock.c b/mos/sys/kern/kern_spinlock.c
new file mode 100644
index 0000000..aaa80de
--- /dev/null
+++ b/mos/sys/kern/kern_spinlock.c
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2025, Ian Moffett.
+ * Provided under the BSD-3 clause.
+ */
+
+#include <sdk/types.h>
+#include <sdk/status.h>
+#include <sdk/string.h>
+#include <mu/cpu.h>
+#include <kern/spinlock.h>
+
+MOS_STATUS
+spinlock_init(const char *name, SPINLOCK *res)
+{
+ USIZE name_len;
+
+ if (name == NULL || res == NULL) {
+ return STATUS_INVALID_ARG;
+ }
+
+ name_len = strlen(name);
+ if (name_len >= SPINLOCK_NAMELEN - 1) {
+ return STATUS_NAME_TOO_LONG;
+ }
+
+ memcpy(res->name, name, name_len);
+ res->lock = 0;
+ return STATUS_SUCCESS;
+}
+
+void
+spinlock_acquire(SPINLOCK *lock, USHORT flags)
+{
+ BOOL irq_state = false;
+
+ if (lock == NULL) {
+ return;
+ }
+
+ /*
+ * Usually this should be the default but this kind of thing should
+ * be somewhat deterministic. If we are to mutate, mask the interrupts.
+ */
+ if (ISSET(flags, SPINLOCK_IRQMUT)) {
+ irq_state = mu_irq_state();
+ mu_irq_setmask(true);
+ }
+
+ /*
+ * Now we'll spin. And no, we will not put ourselves to sleep
+ * here. This needs to be invoked early on before there even
+ * is such thing as a process context.
+ */
+ while (mu_cpu_aswap(&lock->lock, 1)) {
+ mu_cpu_pause();
+ }
+
+ /* Restore the state if we've mutated it */
+ if (ISSET(flags, SPINLOCK_IRQMUT) && irq_state) {
+ mu_irq_setmask(false);
+ }
+}
+
+void
+spinlock_release(SPINLOCK *lock)
+{
+ if (lock == NULL) {
+ return;
+ }
+
+ mu_cpu_aswap(&lock->lock, 0);
+}