mirror of
https://github.com/justinian/jsix.git
synced 2025-12-10 08:24:32 -08:00
[kutil] Fix spinlock release during contention
Spinlock release uses __atomic_compare_exchange_n, which overwrites the `desired` parameter with the actual value when the compare fails. This was causing releases to always spin when there was lock contention.
This commit is contained in:
@@ -15,7 +15,7 @@ public:
|
|||||||
/// A node in the wait queue.
|
/// A node in the wait queue.
|
||||||
struct waiter
|
struct waiter
|
||||||
{
|
{
|
||||||
bool locked;
|
bool blocked;
|
||||||
waiter *next;
|
waiter *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ void
|
|||||||
spinlock::acquire(waiter *w)
|
spinlock::acquire(waiter *w)
|
||||||
{
|
{
|
||||||
w->next = nullptr;
|
w->next = nullptr;
|
||||||
w->locked = true;
|
w->blocked = true;
|
||||||
|
|
||||||
// Point the lock at this waiter
|
// Point the lock at this waiter
|
||||||
waiter *prev = __atomic_exchange_n(&m_lock, w, memorder);
|
waiter *prev = __atomic_exchange_n(&m_lock, w, memorder);
|
||||||
@@ -19,30 +19,27 @@ spinlock::acquire(waiter *w)
|
|||||||
// If there was a previous waiter, wait for them to
|
// If there was a previous waiter, wait for them to
|
||||||
// unblock us
|
// unblock us
|
||||||
prev->next = w;
|
prev->next = w;
|
||||||
while (w->locked) {
|
while (w->blocked)
|
||||||
asm ("pause");
|
asm ("pause");
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
w->locked = false;
|
w->blocked = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
spinlock::release(waiter *w)
|
spinlock::release(waiter *w)
|
||||||
{
|
{
|
||||||
if (!w->next) {
|
|
||||||
// If we're still the last waiter, we're done
|
// If we're still the last waiter, we're done
|
||||||
if(__atomic_compare_exchange_n(&m_lock, &w, nullptr, false, memorder, memorder))
|
waiter *expected = w;
|
||||||
|
if(__atomic_compare_exchange_n(&m_lock, &expected, nullptr, false, memorder, memorder))
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
// Wait for the subseqent waiter to tell us who they are
|
// Wait for the subseqent waiter to tell us who they are
|
||||||
while (!w->next) {
|
while (!w->next)
|
||||||
asm ("pause");
|
asm ("pause");
|
||||||
}
|
|
||||||
|
|
||||||
// Unblock the subseqent waiter
|
// Unblock the subseqent waiter
|
||||||
w->next->locked = false;
|
w->next->blocked = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user