[kernel] Add spinlocks to vm_space, frame_allocator

Also updated spinlock interface to be an object, and added a scoped lock
object that uses it as well.
This commit is contained in:
Justin C. Miller
2021-02-10 23:57:51 -08:00
parent 793bba95b5
commit 8c0d52d0fe
7 changed files with 68 additions and 29 deletions

View File

@@ -4,17 +4,43 @@
#pragma once
namespace kutil {
namespace spinlock {
/// An MCS based spinlock node
struct node
/// An MCS based spinlock
class spinlock
{
bool locked;
node *next;
public:
spinlock();
~spinlock();
/// A node in the wait queue.
struct waiter
{
bool locked;
waiter *next;
};
void acquire(waiter *w);
void release(waiter *w);
private:
waiter *m_lock;
};
void aquire(node *lock, node *waiter);
void release(node *lock, node *waiter);
/// Scoped lock that owns a spinlock::waiter
class scoped_lock
{
public:
inline scoped_lock(spinlock &lock) : m_lock(lock) {
m_lock.acquire(&m_waiter);
}
inline ~scoped_lock() {
m_lock.release(&m_waiter);
}
private:
spinlock &m_lock;
spinlock::waiter m_waiter;
};
} // namespace spinlock
} // namespace kutil

View File

@@ -1,48 +1,49 @@
#include "kutil/spinlock.h"
namespace kutil {
namespace spinlock {
static constexpr int memorder = __ATOMIC_SEQ_CST;
spinlock::spinlock() : m_lock {nullptr} {}
spinlock::~spinlock() {}
void
aquire(node * &lock, node *waiter)
spinlock::acquire(waiter *w)
{
waiter->next = nullptr;
waiter->locked = true;
w->next = nullptr;
w->locked = true;
// Point the lock at this waiter
node *prev = __atomic_exchange_n(&lock, waiter, memorder);
waiter *prev = __atomic_exchange_n(&m_lock, w, memorder);
if (prev) {
// If there was a previous waiter, wait for them to
// unblock us
prev->next = waiter;
while (waiter->locked) {
prev->next = w;
while (w->locked) {
asm ("pause");
}
} else {
waiter->locked = false;
w->locked = false;
}
}
void
release(node * &lock, node *waiter)
spinlock::release(waiter *w)
{
if (!waiter->next) {
if (!w->next) {
// If we're still the last waiter, we're done
if(__atomic_compare_exchange_n(&lock, &waiter, nullptr, false, memorder, memorder))
if(__atomic_compare_exchange_n(&m_lock, &w, nullptr, false, memorder, memorder))
return;
}
// Wait for the subseqent waiter to tell us who they are
while (!waiter->next) {
while (!w->next) {
asm ("pause");
}
// Unblock the subseqent waiter
waiter->next->locked = false;
w->next->locked = false;
}
} // namespace spinlock
} // namespace kutil