summaryrefslogtreecommitdiff
path: root/lume-legacy/src/kernel/spinlock.cc
diff options
context:
space:
mode:
authorRichard Qin <richard.qin.x@gmail.com>2026-07-10 11:31:46 +0800
committerRichard Qin <richard.qin.x@gmail.com>2026-07-10 11:31:46 +0800
commite90b72ec3082588b296956730bd2930cf8d5d671 (patch)
tree36ff6916af9b4176ea5a9662219d11e721f0b691 /lume-legacy/src/kernel/spinlock.cc
parent1767d390fbf3d0c65389de46caf0b6d43ef3b6ad (diff)
downloadlume-e90b72ec3082588b296956730bd2930cf8d5d671.tar.gz
lume-e90b72ec3082588b296956730bd2930cf8d5d671.tar.xz
refactor: promote new architecture to repository root
Archive the deprecated implementation under lume-legacy, make the new kernel the default root-level build, and update repository entry points without changing kernel behavior.
Diffstat (limited to 'lume-legacy/src/kernel/spinlock.cc')
-rw-r--r--lume-legacy/src/kernel/spinlock.cc199
1 files changed, 199 insertions, 0 deletions
diff --git a/lume-legacy/src/kernel/spinlock.cc b/lume-legacy/src/kernel/spinlock.cc
new file mode 100644
index 0000000..aadce21
--- /dev/null
+++ b/lume-legacy/src/kernel/spinlock.cc
@@ -0,0 +1,199 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2026 Richard QIn
+ */
+#include "kernel/spinlock.h"
+#include "kernel/riscv.h"
+#include "kernel/cpu.h"
+#include "kernel/proc_def.h"
+#include "drivers/uart.h"
+
+extern struct cpu cpus[];
+
+namespace ProcManager
+{
+ void sleep(void *chan, Spinlock *lk);
+ void wakeup(void *chan);
+}
+
+// Interrupt Depth Management
+void push_off(void);
+void pop_off(void);
+
+// // Get the pointer of the current CPU
+// // Depends on r_tp() in riscv.h to read the tp register
+// struct cpu *mycpu()
+// {
+// int id = r_tp();
+// return &cpus[id];
+// }
+
+// Get the current process
+// Must be called with interrupts disabled, or read atomically in a safe manner
+struct Proc *myproc()
+{
+ push_off();
+ struct cpu *c = mycpu();
+ struct Proc *p = c->proc;
+ pop_off();
+ return p;
+}
+
+// Spinlock Implementation
+
+void Spinlock::init(const char *lock_name)
+{
+ name = lock_name;
+ locked = 0;
+ cpu = nullptr;
+}
+
+void Spinlock::acquire()
+{
+ push_off(); // Disable interrupts: prevent deadlocks (interrupt handler requests a lock that is already held)
+
+ if (holding())
+ {
+ Drivers::uart_puts("panic: recursive acquire ");
+ Drivers::uart_puts(name);
+ Drivers::uart_puts("\n");
+ while (1)
+ ;
+ }
+
+ // Atomic Exchange
+ // __ATOMIC_ACQUIRE: Ensures that reads and writes after the acquire are not reordered before the acquire
+ while (__atomic_exchange_n(&locked, 1, __ATOMIC_ACQUIRE))
+ {
+ // Busy-wait (Spinning)
+ // Optimization: Read-only, no writes, reducing cache coherence traffic
+ while (__atomic_load_n(&locked, __ATOMIC_RELAXED) == 1)
+ {
+ asm volatile("nop"); // RISC-V indicates that the CPU is in a spin state
+ }
+ }
+
+ // Record holder
+ cpu = mycpu();
+}
+
+void Spinlock::release()
+{
+ if (!holding())
+ {
+ Drivers::uart_puts("panic: release not holding\n");
+ while (1)
+ ;
+ }
+
+ cpu = nullptr;
+
+ // Atomic Store
+ // __ATOMIC_RELEASE: Ensures all reads and writes before the Release are completed
+ __atomic_store_n(&locked, 0, __ATOMIC_RELEASE);
+
+ pop_off();
+}
+
+// Check if the current CPU holds the lock
+bool Spinlock::holding()
+{
+ // Interrupt checks must be disabled, otherwise a process switch may occur causing CPU fluctuations.
+ int r;
+ push_off();
+ r = (locked && cpu == mycpu());
+ pop_off();
+ return r;
+}
+
+
+// Mutex Implementation (Sleep Locks)
+
+void Mutex::init(const char *lock_name)
+{
+ name = lock_name;
+ locked = 0;
+ pid = 0;
+ lk.init("mutex_internal");
+}
+
+void Mutex::acquire()
+{
+ lk.acquire(); // Acquire the internal lock to protect the locked field
+
+ while (locked)
+ {
+ // Lock is held, preparing to sleep
+ // Atomicity contract of sleep():
+ // 1. Mark the current process as SLEEPING
+ // 2. Release lk (so others can operate on locked)
+ // 3. Switch CPU (context switch)
+ // 4. After being woken up, reacquire the lk lock and return
+ ProcManager::sleep(this, &lk);
+ }
+
+ locked = 1;
+ pid = myproc()->pid;
+
+ lk.release();
+}
+
+void Mutex::release()
+{
+ lk.acquire();
+
+ locked = 0;
+ pid = 0;
+
+ // Wake up all processes sleeping on this lock (chan = this)
+ ProcManager::wakeup(this);
+
+ lk.release();
+}
+
+bool Mutex::holding()
+{
+ lk.acquire(); // Must use a lock when reading to prevent race conditions.
+ bool r = locked && (pid == myproc()->pid);
+ lk.release();
+ return r;
+}
+
+// Interrupt Depth Management
+
+void push_off(void)
+{
+ int old = intr_get();
+ intr_off();
+
+ struct cpu *c = mycpu();
+
+ if (c->noff == 0)
+ c->intena = old;
+
+ c->noff += 1;
+}
+
+void pop_off(void)
+{
+ struct cpu *c = mycpu();
+
+ if (intr_get())
+ {
+ Drivers::uart_puts("panic: pop_off - interruptible\n");
+ while (1)
+ ;
+ }
+ if (c->noff < 1)
+ {
+ Drivers::uart_puts("panic: pop_off count\n");
+ while (1)
+ ;
+ }
+
+ c->noff -= 1;
+
+ // An interrupt is only truly enabled when the nesting level returns to zero and the outermost layer allows interrupts.
+ if (c->noff == 0 && c->intena)
+ intr_on();
+} \ No newline at end of file