20#include "pedigree/kernel/Log.h"
21#include "pedigree/kernel/Metrics.h"
22#include "pedigree/kernel/Spinlock.h"
23#include "pedigree/kernel/panic.h"
24#include "pedigree/kernel/processor/Processor.h"
25#include "pedigree/kernel/processor/ProcessorInformation.h"
28#include "pedigree/kernel/debugger/commands/LocksCommand.h"
31Spinlock::Spinlock() =
default;
33Spinlock::Spinlock(
bool bLocked,
bool bAvoidTracking)
34 : m_Lock(bLocked), m_bAvoidTracking(bAvoidTracking) {}
44#if SPINLOCK_DIAGNOSTICS
45 ra =
reinterpret_cast<uintptr_t
>(__builtin_return_address(0));
51 if (!m_bAvoidTracking) {
52 g_LocksCommand.clearFatal();
54 panic(
"Lock checker disallowed spinlock acquisition");
61 m_bInterrupts = interrupts;
67#if SPINLOCK_DIAGNOSTICS
73 if (!m_bAvoidTracking) {
74 g_LocksCommand.clearFatal();
76 panic(
"Lock checker disallowed acquired spinlock");
80 Metrics::increment(Metrics::SpinlockAcquire);
88 const size_t owner = __atomic_load_n(&m_OwnedProcessor, __ATOMIC_RELAXED);
91 if (owner == processorId && recurse && m_Level &&
98 if (!m_bAvoidTracking) {
99 g_LocksCommand.clearFatal();
100 if (!g_LocksCommand.
checkState(
this, processorId))
101 panic(
"Lock checker rejected contended spinlock");
115 }
while (m_Lock.acquired() || !m_Lock.tryAcquire());
117 Metrics::increment(Metrics::SpinlockContended);
124 if (!m_bAvoidTracking) {
125 g_LocksCommand.clearFatal();
126 const size_t processorId = m_OwnedProcessor == ~size_t(0) ? ~0U : m_OwnedProcessor;
128 panic(
"Lock checker disallowed spinlock release");
135#if SPINLOCK_DIAGNOSTICS
137 badReleaseInterrupts();
138 if (
UNLIKELY(m_Magic != 0xdeadbaba))
146 if (m_Level && --m_Level)
150 __atomic_store_n(&m_OwnedProcessor, ~
size_t(0), __ATOMIC_RELAXED);
151#if SPINLOCK_DIAGNOSTICS
154 const uintptr_t acquiredAt = m_Ra;
156 if (
UNLIKELY(!m_Lock.releaseChecked())) {
157 deadlock(ra,
true, acquiredAt);
171 const bool interrupts = m_bInterrupts && m_Level <= 1;
173#if SPINLOCK_DIAGNOSTICS
174 ra =
reinterpret_cast<uintptr_t
>(__builtin_return_address(0));
184 __atomic_store_n(&m_OwnedProcessor, ~
size_t(0), __ATOMIC_RELAXED);
185#if SPINLOCK_DIAGNOSTICS
192 return &m_Lock.m_Value;
195void Spinlock::unlockForScheduler() {
200bool Spinlock::acquired() {
201 return m_Lock.acquired();
204bool Spinlock::interrupts()
const {
205 return m_bInterrupts;
208uintptr_t Spinlock::acquisitionAddress()
const {
209#if SPINLOCK_DIAGNOSTICS
216void Spinlock::badMagic(uintptr_t ra)
const {
217#if SPINLOCK_DIAGNOSTICS
218 WARNING(
" --> fail: sentinels: before=" <<
Hex << m_Sentinel <<
" after=" << m_MagicAlign);
219 FATAL_NOLOCK(
"Wrong magic in Spinlock [" <<
Hex << m_Magic <<
" should be 0xdeadbaba] [this="
220 <<
reinterpret_cast<uintptr_t
>(
this)
221 <<
"] return=" << ra);
223 panic(
"Corrupt spinlock");
226void Spinlock::badReleaseInterrupts()
const {
227 FATAL_NOLOCK(
"Spinlock: release() called with interrupts enabled.");
228 panic(
"Spinlock released with interrupts enabled");
231void Spinlock::deadlock(uintptr_t ra,
bool releasing, uintptr_t acquiredAt) {
233 const bool locked = m_Lock.acquired();
235 acquiredAt = acquisitionAddress();
237 ERROR_NOLOCK(
"Spinlock deadlocked in " << (releasing ?
"release" :
"acquire"));
238 ERROR_NOLOCK(
" -> my return address is " <<
Hex << ra);
239 ERROR_NOLOCK(
" -> return address of other locker is " <<
Hex << acquiredAt);
240 FATAL_NOLOCK(
"Spinlock has deadlocked, spinlock is " <<
Hex <<
reinterpret_cast<uintptr_t
>(
this)
241 <<
", locked=" << locked <<
".");
242 panic(
"Spinlock has deadlocked");
bool checkState(const Spinlock *pLock, size_t nCpu=~0U)
bool lockReleased(const Spinlock *pLock, size_t nCpu=~0U)
static bool getInterrupts()
static ProcessorInformation & information()
static void setInterrupts(bool bEnable)
volatile processor_register_t * deferredReleaseWord()
void unwind() ALWAYS_INLINE
void trackRelease(uintptr_t ra) const
bool acquire(bool recurse=false, bool safe=true)
bool acquireContended(bool recurse, bool safe, uintptr_t ra) NEVER_INLINE
void unlock(uintptr_t ra) ALWAYS_INLINE
void exit(uintptr_t ra=0)
void EXPORTED_PUBLIC panic(const char *msg) NORETURN