diff --git a/kernel/include/kernel/SpinLock.h b/kernel/include/kernel/SpinLock.h index 2eaef9ecaf..0c6388ddad 100644 --- a/kernel/include/kernel/SpinLock.h +++ b/kernel/include/kernel/SpinLock.h @@ -39,4 +39,24 @@ namespace Kernel SpinLock m_lock; }; -} \ No newline at end of file + class RecursivePrioritySpinLock + { + BAN_NON_COPYABLE(RecursivePrioritySpinLock); + BAN_NON_MOVABLE(RecursivePrioritySpinLock); + + public: + RecursivePrioritySpinLock() = default; + void lock(); + void unlock(); + bool is_locked() const; + + uint32_t lock_depth() const { return m_lock_depth; } + + private: + pid_t m_locker = -1; + uint32_t m_queue_length = 0; + uint32_t m_lock_depth = 0; + SpinLock m_lock; + }; + +} diff --git a/kernel/kernel/SpinLock.cpp b/kernel/kernel/SpinLock.cpp index f65b4fde67..f5eb66cfe2 100644 --- a/kernel/kernel/SpinLock.cpp +++ b/kernel/kernel/SpinLock.cpp @@ -80,4 +80,61 @@ namespace Kernel return m_locker != -1; } + void RecursivePrioritySpinLock::lock() + { + pid_t tid = Scheduler::current_tid(); + + bool has_priority = !Thread::current().is_userspace(); + + if (has_priority) + { + m_lock.lock(); + m_queue_length++; + m_lock.unlock(); + } + + while (true) + { + m_lock.lock(); + if (m_locker == tid) + { + m_lock_depth++; + break; + } + if (m_locker == -1 && (has_priority || m_queue_length == 0)) + { + m_locker = tid; + m_lock_depth = 1; + break; + } + m_lock.unlock(); + } + + m_lock.unlock(); + } + + void RecursivePrioritySpinLock::unlock() + { + m_lock.lock(); + + ASSERT(m_lock_depth > 0); + ASSERT(m_locker == Scheduler::current_tid()); + + bool has_priority = !Thread::current().is_userspace(); + if (has_priority) + m_queue_length--; + + m_lock_depth--; + + if (m_lock_depth == 0) + m_locker = -1; + + m_lock.unlock(); + } + + bool RecursivePrioritySpinLock::is_locked() const + { + return m_locker != -1; + } + } \ No newline at end of file