[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:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user