diff --git a/modules.yaml b/modules.yaml index e3d59ca..c7430f0 100644 --- a/modules.yaml +++ b/modules.yaml @@ -114,6 +114,7 @@ modules: - src/libraries/kutil/logger.cpp - src/libraries/kutil/memory.cpp - src/libraries/kutil/printf.c + - src/libraries/kutil/spinlock.cpp cpu: kind: lib diff --git a/src/libraries/kutil/include/kutil/spinlock.h b/src/libraries/kutil/include/kutil/spinlock.h index eb144af..a41e35e 100644 --- a/src/libraries/kutil/include/kutil/spinlock.h +++ b/src/libraries/kutil/include/kutil/spinlock.h @@ -1,19 +1,20 @@ +/// \file spinlock.h +/// Spinlock types and related defintions + #pragma once -#include namespace kutil { +namespace spinlock { - -class spinlock +/// An MCS based spinlock node +struct node { -public: - spinlock() : m_lock(false) {} - - inline void enter() { while (!m_lock.exchange(true)); } - inline void leave() { m_lock.store(false); } - -private: - std::atomic m_lock; + bool locked; + node *next; }; +void aquire(node *lock, node *waiter); +void release(node *lock, node *waiter); + +} // namespace spinlock } // namespace kutil diff --git a/src/libraries/kutil/spinlock.cpp b/src/libraries/kutil/spinlock.cpp new file mode 100644 index 0000000..b6daba9 --- /dev/null +++ b/src/libraries/kutil/spinlock.cpp @@ -0,0 +1,48 @@ +#include "kutil/spinlock.h" + +namespace kutil { +namespace spinlock { + +static constexpr int memorder = __ATOMIC_SEQ_CST; + +void +aquire(node * &lock, node *waiter) +{ + waiter->next = nullptr; + waiter->locked = true; + + // Point the lock at this waiter + node *prev = __atomic_exchange_n(&lock, waiter, memorder); + if (prev) { + // If there was a previous waiter, wait for them to + // unblock us + prev->next = waiter; + while (waiter->locked) { + asm ("pause"); + } + } else { + waiter->locked = false; + } +} + +void +release(node * &lock, node *waiter) +{ + if (!waiter->next) { + // If we're still the last waiter, we're done + if(__atomic_compare_exchange_n(&lock, &waiter, nullptr, false, memorder, memorder)) + return; + } + + // Wait for the subseqent waiter to tell us who they are + while (!waiter->next) { + asm ("pause"); + } + + // Unblock the subseqent waiter + waiter->next->locked = false; +} + + +} // namespace spinlock +} // namespace kutil