aboutsummaryrefslogtreecommitdiff
path: root/kapi
diff options
context:
space:
mode:
Diffstat (limited to 'kapi')
-rw-r--r--kapi/kapi/interrupts.hpp2
-rw-r--r--kapi/kapi/interrupts/irq_lock.hpp108
2 files changed, 110 insertions, 0 deletions
diff --git a/kapi/kapi/interrupts.hpp b/kapi/kapi/interrupts.hpp
index f9ff22f9..f5b992e2 100644
--- a/kapi/kapi/interrupts.hpp
+++ b/kapi/kapi/interrupts.hpp
@@ -1,5 +1,7 @@
#ifndef TEACHOS_KAPI_INTERRUPTS_HPP
#define TEACHOS_KAPI_INTERRUPTS_HPP
+
+#include <kapi/interrupts/irq_lock.hpp>
#include <kapi/interrupts/state.hpp>
#include <kstd/memory.hpp>
diff --git a/kapi/kapi/interrupts/irq_lock.hpp b/kapi/kapi/interrupts/irq_lock.hpp
new file mode 100644
index 00000000..1b6f6987
--- /dev/null
+++ b/kapi/kapi/interrupts/irq_lock.hpp
@@ -0,0 +1,108 @@
+#ifndef TEACHOS_KAPI_INTERRUPTS_IRQ_LOCK_HPP
+#define TEACHOS_KAPI_INTERRUPTS_IRQ_LOCK_HPP
+
+// IWYU pragma: private, include <kapi/interrupts.hpp>
+
+#include <kapi/interrupts/state.hpp>
+
+#include <kstd/mutex.hpp>
+
+namespace kapi::interrupts
+{
+
+ template<typename = void>
+ struct irq_lock;
+
+ //! @name Kernel-defined API
+ //! @{
+
+ //! A lock to temporarily disable IRQs.
+ template<>
+ struct irq_lock<void>
+ {
+ constexpr irq_lock() = default;
+ constexpr irq_lock(irq_lock const &) = delete;
+ constexpr irq_lock(irq_lock &&) = delete;
+
+ 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);
+ }
+
+ //! Restore the previously saved IRQ state.
+ auto unlock() -> void
+ {
+ enabled(m_old_irq_state);
+ }
+
+ //! Save the current IRQ state and disable further IRQs.
+ auto try_lock() -> bool
+ {
+ lock();
+ return true;
+ }
+
+ private:
+ bool m_old_irq_state{};
+ };
+
+ //! A lock to temporarily disable IRQs while also acquiring a further lock.
+ template<kstd::basic_lockable BasicLockable>
+ struct irq_lock<BasicLockable> : irq_lock<void>
+ {
+ using lockable_type = BasicLockable;
+
+ explicit irq_lock(BasicLockable & lockable)
+ : m_lockable{lockable}
+ {}
+
+ //! Save the current IRQ state, disable further IRQs, and lock this lock's lockable object.
+ auto lock() -> void
+ {
+ irq_lock<>::lock();
+ m_lockable.lock();
+ }
+
+ //! Unlock this lock's lockable objects and restore the previously saved IRQ state.
+ auto unlock() -> void
+ {
+ m_lockable.unlock();
+ irq_lock<>::unlock();
+ }
+
+ //! Save the current IRQ state, disable further IRQs, and attempt to lock this lock's lockable object.
+ //!
+ //! This function will restore the previous IRQ state if this lock's lockable object cannot be locked.
+ //!
+ //! @return @p true iff. this lock's lockable object could successfully be locked, @p false otherwise.
+ [[nodiscard]] auto try_lock() -> bool
+ requires(kstd::lockable<BasicLockable>)
+ {
+ irq_lock<>::lock();
+ if (m_lockable.try_lock())
+ {
+ return true;
+ }
+ irq_lock<>::unlock();
+ return false;
+ }
+
+ private:
+ lockable_type & m_lockable;
+ };
+
+ //! @}
+
+ irq_lock() -> irq_lock<void>;
+
+ template<kstd::basic_lockable Lockable>
+ irq_lock(Lockable &) -> irq_lock<Lockable>;
+
+} // namespace kapi::interrupts
+
+#endif \ No newline at end of file