aboutsummaryrefslogtreecommitdiff
path: root/src/core/hle/kernel/k_spin_lock.cpp
diff options
context:
space:
mode:
authorTakoroka <137927095+Takoroka@users.noreply.github.com>2026-10-29 03:39:52 -0400
committerTakoroka <137927095+Takoroka@users.noreply.github.com>2026-10-29 03:39:52 -0400
commite17fd9cef116a088f080ca502951e500864a58b6 (patch)
treee7ff65f614622515d6a2e4263521909eea89a5d8 /src/core/hle/kernel/k_spin_lock.cpp
parentea6c1193fbfa95e586bb6d129dc684163a12cb3e (diff)
parent80c79333fe6fd28a31b65b997f1cbf2987711c91 (diff)
Merge Switch 2 work from local Eden (nx2 at b0dd3fe)
Diffstat (limited to 'src/core/hle/kernel/k_spin_lock.cpp')
-rw-r--r--src/core/hle/kernel/k_spin_lock.cpp48
1 files changed, 45 insertions, 3 deletions
diff --git a/src/core/hle/kernel/k_spin_lock.cpp b/src/core/hle/kernel/k_spin_lock.cpp
index 8525320374..107d6f1aa3 100644
--- a/src/core/hle/kernel/k_spin_lock.cpp
+++ b/src/core/hle/kernel/k_spin_lock.cpp
@@ -3,18 +3,60 @@
#include "core/hle/kernel/k_spin_lock.h"
+#if defined(_M_X64) || defined(_M_IX86) || defined(__x86_64__) || defined(__i386__)
+#include <immintrin.h>
+#endif
+
namespace Kernel {
+namespace {
+
+// Spins of about 30-140 cycles each before a contended Lock sleeps (a few microseconds).
+constexpr int SpinCount = 128;
+
+void Pause() {
+#if defined(_M_X64) || defined(_M_IX86) || defined(__x86_64__) || defined(__i386__)
+ _mm_pause();
+#elif defined(__aarch64__)
+ asm volatile("yield");
+#endif
+}
+
+} // Anonymous namespace
+
void KSpinLock::Lock() {
- m_lock.lock();
+ u32 expected = 0;
+ if (m_state.compare_exchange_strong(expected, 1, std::memory_order_acquire,
+ std::memory_order_relaxed)) {
+ return;
+ }
+ for (int spin = 0; spin < SpinCount; ++spin) {
+ Pause();
+ if (m_state.load(std::memory_order_relaxed) == 0) {
+ expected = 0;
+ if (m_state.compare_exchange_weak(expected, 1, std::memory_order_acquire,
+ std::memory_order_relaxed)) {
+ return;
+ }
+ }
+ }
+ // Mark the lock contended and sleep until it is released; taken this way it stays marked,
+ // so its Unlock wakes the next sleeper.
+ while (m_state.exchange(2, std::memory_order_acquire) != 0) {
+ m_state.wait(2, std::memory_order_relaxed);
+ }
}
void KSpinLock::Unlock() {
- m_lock.unlock();
+ if (m_state.exchange(0, std::memory_order_release) == 2) {
+ m_state.notify_one();
+ }
}
bool KSpinLock::TryLock() {
- return m_lock.try_lock();
+ u32 expected = 0;
+ return m_state.compare_exchange_strong(expected, 1, std::memory_order_acquire,
+ std::memory_order_relaxed);
}
} // namespace Kernel