aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--kapi/kapi/interrupts/irq_lock.hpp58
1 files changed, 53 insertions, 5 deletions
diff --git a/kapi/kapi/interrupts/irq_lock.hpp b/kapi/kapi/interrupts/irq_lock.hpp
index 1b6f6987..57c0ef7f 100644
--- a/kapi/kapi/interrupts/irq_lock.hpp
+++ b/kapi/kapi/interrupts/irq_lock.hpp
@@ -3,7 +3,9 @@
// IWYU pragma: private, include <kapi/interrupts.hpp>
+#include <kapi/cpu.hpp>
#include <kapi/interrupts/state.hpp>
+#include <kapi/system.hpp>
#include <kstd/mutex.hpp>
@@ -20,35 +22,76 @@ namespace kapi::interrupts
template<>
struct irq_lock<void>
{
- constexpr irq_lock() = default;
+ constexpr irq_lock()
+ : m_owner{kapi::cpu::current_id()}
+ {}
+
constexpr irq_lock(irq_lock const &) = delete;
constexpr irq_lock(irq_lock &&) = delete;
+ ~irq_lock()
+ {
+ assert_owner();
+ if (m_locked)
+ {
+ kapi::system::panic("[OS:INT] IRQ lock destroyed while it is still locked!");
+ }
+ };
+
constexpr auto operator=(irq_lock const &) = delete;
constexpr auto operator=(irq_lock &&) = delete;
//! Save the current IRQ state and disable further IRQs.
auto lock() -> void
{
- m_old_irq_state = enabled();
- enabled(false);
+ if (!try_lock())
+ {
+ kapi::system::panic("[OS:INT] IRQ lock reacquired while it is already held!");
+ }
}
//! Restore the previously saved IRQ state.
auto unlock() -> void
{
+ assert_owner();
+
+ if (!m_locked)
+ {
+ kapi::system::panic("[OS:INT] IRQ lock unlocked while it is not being held!");
+ }
+
enabled(m_old_irq_state);
+ m_locked = false;
}
//! Save the current IRQ state and disable further IRQs.
auto try_lock() -> bool
{
- lock();
+ assert_owner();
+ auto old_state = enabled();
+ enabled(false);
+ if (m_locked)
+ {
+ enabled(old_state);
+ return false;
+ }
+ m_locked = true;
+ m_old_irq_state = old_state;
return true;
}
private:
+ auto assert_owner() -> void
+ {
+ if (m_owner != kapi::cpu::current_id())
+ {
+ kapi::system::panic("[OS:INT] Tried to modify IRQ lock on a CPU that does not own it!");
+ }
+ }
+
+ bool m_locked{};
bool m_old_irq_state{};
+ kapi::cpu::id m_owner{};
};
//! A lock to temporarily disable IRQs while also acquiring a further lock.
@@ -83,11 +126,16 @@ namespace kapi::interrupts
[[nodiscard]] auto try_lock() -> bool
requires(kstd::lockable<BasicLockable>)
{
- irq_lock<>::lock();
+ if (!irq_lock<>::try_lock())
+ {
+ return false;
+ }
+
if (m_lockable.try_lock())
{
return true;
}
+
irq_lock<>::unlock();
return false;
}