diff options
Diffstat (limited to 'na/kernel/sync/spinlock.cc')
| -rw-r--r-- | na/kernel/sync/spinlock.cc | 120 |
1 files changed, 0 insertions, 120 deletions
diff --git a/na/kernel/sync/spinlock.cc b/na/kernel/sync/spinlock.cc deleted file mode 100644 index f649fe7..0000000 --- a/na/kernel/sync/spinlock.cc +++ /dev/null @@ -1,120 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* Copyright (C) 2026 Richard Qin */ - -/* - * Spinlock Implementation - * - * TTAS (Test-and-Test-and-Set) spinlock with: - * - Acquire: __ATOMIC_ACQUIRE memory ordering - * - Release: __ATOMIC_RELEASE memory ordering - * - Automatic interrupt disable/enable via push_intr/pop_intr - * - Dead-lock and invalid-release detection via kernel_panic - * - * Reference: docs/specs/spinlock.md - */ - -#include "spinlock.h" -#include "cpu_state.h" -#include <arch/cpu.h> -#include <lume/klog.h> -#include <lume/task.h> - -// ============================================================ -// Per-CPU sync state (BSS zero-initialized) -// ============================================================ -namespace sync { - -CpuSyncState g_cpu_sync_states[kMaxCpus]; - -void push_intr() { - bool was_on = arch::cpu::intr_enabled(); - arch::cpu::intr_off(); - - auto& state = g_cpu_sync_states[arch::cpu::id()]; - if (state.lock_depth == 0) { - state.intr_was_on = was_on; - } - state.lock_depth++; -} - -void pop_intr() { - auto& state = g_cpu_sync_states[arch::cpu::id()]; - state.lock_depth--; - - if (state.lock_depth == 0 && state.intr_was_on) { - arch::cpu::intr_on(); - } -} - -} // namespace sync - -// ============================================================ -// Spinlock methods -// ============================================================ - -void Spinlock::init(const char* name) { - name_ = name; - locked_.store(0, __ATOMIC_RELAXED); - cpu_id_ = sync::kInvalidCpuId; -} - -void Spinlock::acquire() { -#ifdef DEBUG - // Optional: detect interrupt-state leakage - if (arch::cpu::intr_enabled()) { - auto& state = sync::g_cpu_sync_states[arch::cpu::id()]; - if (state.lock_depth > 0) { - kernel_panic("spinlock: interrupts enabled while holding lock"); - } - } -#endif - - // Step 1: disable interrupts, track nesting depth - sync::push_intr(); - - // Step 2: dead-lock detection (same CPU re-acquiring) - if (is_held_by_current_cpu()) { - kernel_panic("spinlock: double lock", name_); - } - - // Step 3: TTAS spin loop - while (true) { - // Outer: spin on local cache copy (no bus traffic) - while (locked_.load(__ATOMIC_RELAXED)) - ; - // Inner: attempt atomic exchange with acquire semantics - if (locked_.exchange(1, __ATOMIC_ACQUIRE) == 0) - break; - } - - // Step 4: record owner - cpu_id_ = arch::cpu::id(); - - // Step 5: bump preempt_count — prevents schedule() from preempting - TaskControlBlock* curr = current_task(); - if (curr) curr->preempt_count++; -} - -void Spinlock::release() { - // Step 1: verify caller is the holder - if (!is_held_by_current_cpu()) { - kernel_panic("spinlock: invalid release", name_); - } - - // Step 2: clear owner - cpu_id_ = sync::kInvalidCpuId; - - // Step 3: release the lock with release semantics - locked_.store(0, __ATOMIC_RELEASE); - - // Step 4: drop preempt_count - TaskControlBlock* curr = current_task(); - if (curr) curr->preempt_count--; - - // Step 5: restore interrupt state if this was the last lock - sync::pop_intr(); -} - -bool Spinlock::is_held_by_current_cpu() const { - return cpu_id_ == arch::cpu::id(); -} |
