diff options
| author | Richard Qin <richard.qin.x@gmail.com> | 2026-07-10 11:31:46 +0800 |
|---|---|---|
| committer | Richard Qin <richard.qin.x@gmail.com> | 2026-07-10 11:31:46 +0800 |
| commit | e90b72ec3082588b296956730bd2930cf8d5d671 (patch) | |
| tree | 36ff6916af9b4176ea5a9662219d11e721f0b691 /lume-legacy/src/kernel/spinlock.cc | |
| parent | 1767d390fbf3d0c65389de46caf0b6d43ef3b6ad (diff) | |
| download | lume-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.cc | 199 |
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 |
