From f97515bd7ea7dc439adfc089e6a737ad16a0283e Mon Sep 17 00:00:00 2001 From: apio Date: Sat, 17 Dec 2022 10:52:40 +0100 Subject: [PATCH] Kernel: Add Spinlock and LockedValue --- kernel/CMakeLists.txt | 1 + kernel/src/thread/Spinlock.cpp | 22 +++++++++ kernel/src/thread/Spinlock.h | 86 ++++++++++++++++++++++++++++++++++ 3 files changed, 109 insertions(+) create mode 100644 kernel/src/thread/Spinlock.cpp create mode 100644 kernel/src/thread/Spinlock.h diff --git a/kernel/CMakeLists.txt b/kernel/CMakeLists.txt index f4a7e678..89c601ee 100644 --- a/kernel/CMakeLists.txt +++ b/kernel/CMakeLists.txt @@ -12,6 +12,7 @@ set(SOURCES src/boot/Init.cpp src/arch/Serial.cpp src/arch/Timer.cpp + src/thread/Spinlock.cpp src/thread/Thread.cpp src/thread/Scheduler.cpp ) diff --git a/kernel/src/thread/Spinlock.cpp b/kernel/src/thread/Spinlock.cpp new file mode 100644 index 00000000..7c70e08f --- /dev/null +++ b/kernel/src/thread/Spinlock.cpp @@ -0,0 +1,22 @@ +#include "thread/Spinlock.h" +#include "Log.h" +#include "arch/CPU.h" + +void Spinlock::lock() +{ + int expected = -1; + while (!m_lock.compare_exchange_strong(expected, 0)) + { + expected = -1; + CPU::pause(); + } +} + +void Spinlock::unlock() +{ + int expected = 0; + if (!m_lock.compare_exchange_strong(expected, -1)) + { + kwarnln("Spinlock::unlock() called on an unlocked lock with value %d", expected); + } +} \ No newline at end of file diff --git a/kernel/src/thread/Spinlock.h b/kernel/src/thread/Spinlock.h new file mode 100644 index 00000000..984b6ce3 --- /dev/null +++ b/kernel/src/thread/Spinlock.h @@ -0,0 +1,86 @@ +#pragma once +#include + +class Spinlock +{ + public: + void lock(); + void unlock(); + + bool is_locked() const + { + return m_lock.load() != -1; + } + + // Call this before use if the Spinlock is a global variable. + void init() + { + m_lock = -1; + } + + private: + Atomic m_lock{-1}; +}; + +template class LockedValue +{ + struct LockedValueGuard + { + LockedValueGuard(LockedValue& value_ref) : m_value_ref(value_ref) + { + } + + ~LockedValueGuard() + { + m_value_ref.m_lock.unlock(); + } + + T& ref() + { + return m_value_ref.m_value; + } + + void set(const T& other) + { + ref() = other; + } + + T* operator->() + { + return &ref(); + } + + T& operator*() + { + return ref(); + } + + private: + LockedValue& m_value_ref; + }; + + public: + LockedValue() : m_value() + { + } + + LockedValue(T value) : m_value(value) + { + } + + // Call this before use if the LockedValue is a global variable. + void init() + { + m_lock.init(); + } + + LockedValueGuard lock() + { + m_lock.lock(); + return {*this}; + } + + private: + T m_value; + Spinlock m_lock; +}; \ No newline at end of file