2022-12-17 09:52:40 +00:00
|
|
|
#pragma once
|
2023-01-09 16:59:52 +00:00
|
|
|
#include "Log.h"
|
|
|
|
#include "arch/CPU.h"
|
2022-12-17 09:52:40 +00:00
|
|
|
#include <luna/Atomic.h>
|
2022-12-18 19:37:26 +00:00
|
|
|
#include <luna/Option.h>
|
2022-12-17 09:52:40 +00:00
|
|
|
|
|
|
|
class Spinlock
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
void lock();
|
|
|
|
void unlock();
|
|
|
|
|
2022-12-18 19:37:26 +00:00
|
|
|
bool try_lock();
|
|
|
|
|
2022-12-17 09:52:40 +00:00
|
|
|
bool is_locked() const
|
|
|
|
{
|
2022-12-18 19:36:15 +00:00
|
|
|
return m_lock.load() != 0;
|
2022-12-17 09:52:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
2022-12-21 19:22:44 +00:00
|
|
|
Atomic<int> m_lock { 0 };
|
2022-12-17 09:52:40 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
template <typename T> class LockedValue
|
|
|
|
{
|
|
|
|
struct LockedValueGuard
|
|
|
|
{
|
2022-12-18 19:37:26 +00:00
|
|
|
LockedValueGuard(LockedValue& value_ref) : m_value_ref(&value_ref)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
LockedValueGuard(const LockedValueGuard& other) = delete;
|
|
|
|
LockedValueGuard(LockedValueGuard&& other)
|
2022-12-17 09:52:40 +00:00
|
|
|
{
|
2022-12-18 19:37:26 +00:00
|
|
|
m_value_ref = other.m_value_ref;
|
|
|
|
other.m_value_ref = nullptr;
|
2022-12-17 09:52:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
~LockedValueGuard()
|
|
|
|
{
|
2022-12-18 19:37:26 +00:00
|
|
|
if (m_value_ref) m_value_ref->m_lock.unlock();
|
2022-12-17 09:52:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
T& ref()
|
|
|
|
{
|
2022-12-18 19:37:26 +00:00
|
|
|
expect(m_value_ref, "LockedValueGuard::ref() called on a moved LockedValueGuard");
|
|
|
|
return m_value_ref->m_value;
|
2022-12-17 09:52:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void set(const T& other)
|
|
|
|
{
|
|
|
|
ref() = other;
|
|
|
|
}
|
|
|
|
|
|
|
|
T* operator->()
|
|
|
|
{
|
|
|
|
return &ref();
|
|
|
|
}
|
|
|
|
|
|
|
|
T& operator*()
|
|
|
|
{
|
|
|
|
return ref();
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
2022-12-18 19:37:26 +00:00
|
|
|
LockedValue* m_value_ref;
|
2022-12-17 09:52:40 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
public:
|
|
|
|
LockedValue() : m_value()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
LockedValue(T value) : m_value(value)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2023-01-09 16:59:52 +00:00
|
|
|
#ifndef LOCKED_VALUE_DEBUG
|
2022-12-17 09:52:40 +00:00
|
|
|
LockedValueGuard lock()
|
|
|
|
{
|
|
|
|
m_lock.lock();
|
2022-12-21 19:22:44 +00:00
|
|
|
return { *this };
|
2022-12-17 09:52:40 +00:00
|
|
|
}
|
2023-01-09 16:59:52 +00:00
|
|
|
#else
|
|
|
|
LockedValueGuard lock()
|
|
|
|
{
|
|
|
|
if (m_lock.try_lock()) { return { *this }; }
|
|
|
|
|
|
|
|
kwarnln("Spinning on a locked LockedValue. This might lead to a deadlock...");
|
|
|
|
|
|
|
|
CPU::print_stack_trace();
|
|
|
|
|
|
|
|
m_lock.lock();
|
|
|
|
return { *this };
|
|
|
|
}
|
|
|
|
#endif
|
2022-12-17 09:52:40 +00:00
|
|
|
|
2022-12-18 19:37:26 +00:00
|
|
|
Option<LockedValueGuard> try_lock()
|
|
|
|
{
|
2022-12-21 19:22:44 +00:00
|
|
|
if (m_lock.try_lock()) { return { *this }; }
|
2022-12-18 19:37:26 +00:00
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
2022-12-17 09:52:40 +00:00
|
|
|
private:
|
|
|
|
T m_value;
|
|
|
|
Spinlock m_lock;
|
2023-01-02 12:07:29 +00:00
|
|
|
};
|