diff --git a/src/libraries/util/include/util/spinlock.h b/src/libraries/util/include/util/spinlock.h index d9fc2d4..f22b19d 100644 --- a/src/libraries/util/include/util/spinlock.h +++ b/src/libraries/util/include/util/spinlock.h @@ -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 diff --git a/src/libraries/util/spinlock.cpp b/src/libraries/util/spinlock.cpp index 4b62c25..5b54029 100644 --- a/src/libraries/util/spinlock.cpp +++ b/src/libraries/util/spinlock.cpp @@ -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) {