diff options
Diffstat (limited to 'kapi')
| -rw-r--r-- | kapi/kapi/interrupts.hpp | 2 | ||||
| -rw-r--r-- | kapi/kapi/interrupts/irq_lock.hpp | 108 |
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 |
