mirror of
https://github.com/justinian/jsix.git
synced 2025-12-10 00:14:32 -08:00
[kutil] Update spinlock to an MCS-style lock
Update the existing but unused spinlock class to an MCS-style queue spinlock. This is probably still a WIP but I expect it to see more use with SMP getting further integrated.
This commit is contained in:
@@ -114,6 +114,7 @@ modules:
|
|||||||
- src/libraries/kutil/logger.cpp
|
- src/libraries/kutil/logger.cpp
|
||||||
- src/libraries/kutil/memory.cpp
|
- src/libraries/kutil/memory.cpp
|
||||||
- src/libraries/kutil/printf.c
|
- src/libraries/kutil/printf.c
|
||||||
|
- src/libraries/kutil/spinlock.cpp
|
||||||
|
|
||||||
cpu:
|
cpu:
|
||||||
kind: lib
|
kind: lib
|
||||||
|
|||||||
@@ -1,19 +1,20 @@
|
|||||||
|
/// \file spinlock.h
|
||||||
|
/// Spinlock types and related defintions
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <atomic>
|
|
||||||
|
|
||||||
namespace kutil {
|
namespace kutil {
|
||||||
|
namespace spinlock {
|
||||||
|
|
||||||
|
/// An MCS based spinlock node
|
||||||
class spinlock
|
struct node
|
||||||
{
|
{
|
||||||
public:
|
bool locked;
|
||||||
spinlock() : m_lock(false) {}
|
node *next;
|
||||||
|
|
||||||
inline void enter() { while (!m_lock.exchange(true)); }
|
|
||||||
inline void leave() { m_lock.store(false); }
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::atomic<bool> m_lock;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void aquire(node *lock, node *waiter);
|
||||||
|
void release(node *lock, node *waiter);
|
||||||
|
|
||||||
|
} // namespace spinlock
|
||||||
} // namespace kutil
|
} // namespace kutil
|
||||||
|
|||||||
48
src/libraries/kutil/spinlock.cpp
Normal file
48
src/libraries/kutil/spinlock.cpp
Normal file
@@ -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
|
||||||
Reference in New Issue
Block a user