[util] Add try_aquire to spinlock

Also added a scoped_trylock class that mirrors scoped_lock, but uses
try_aquire and has a scoped_lock::locked() accessor.
This commit is contained in:
Justin C. Miller
2022-01-15 17:51:55 -08:00
parent 19f9496889
commit 44d3918e4f
2 changed files with 42 additions and 1 deletions

View File

@@ -17,8 +17,10 @@ public:
{
bool blocked;
waiter *next;
char const *where;
};
bool try_acquire(waiter *w);
void acquire(waiter *w);
void release(waiter *w);
@@ -30,7 +32,10 @@ private:
class scoped_lock
{
public:
inline scoped_lock(spinlock &lock) : m_lock(lock) {
inline scoped_lock(
spinlock &lock,
const char *where = __builtin_FUNCTION()
) : m_lock(lock), m_waiter {false, nullptr, where} {
m_lock.acquire(&m_waiter);
}
@@ -43,4 +48,29 @@ private:
spinlock::waiter m_waiter;
};
/// Scoped lock that owns a spinlock::waiter and calls
/// spinlock::try_acquire
class scoped_trylock
{
public:
inline scoped_trylock(
spinlock &lock,
const char *where = __builtin_FUNCTION()
) : m_lock(lock), m_waiter {false, nullptr, where} {
m_locked = m_lock.try_acquire(&m_waiter);
}
inline ~scoped_trylock() {
if (m_locked)
m_lock.release(&m_waiter);
}
inline bool locked() const { return m_locked; }
private:
bool m_locked;
spinlock &m_lock;
spinlock::waiter m_waiter;
};
} // namespace util

View File

@@ -7,6 +7,17 @@ static constexpr int memorder = __ATOMIC_SEQ_CST;
spinlock::spinlock() : m_lock {nullptr} {}
spinlock::~spinlock() {}
bool
spinlock::try_acquire(waiter *w)
{
w->next = nullptr;
w->blocked = false;
// Point this lock at the waiter only if it's empty
waiter *expected = nullptr;
return __atomic_compare_exchange_n(&m_lock, &expected, w, false, memorder, memorder);
}
void
spinlock::acquire(waiter *w)
{