#include #include #include #include SCENARIO("irq_lock semantics", "[kapi][interrupts]") { GIVEN("a simple irq_lock") { auto lock = kapi::interrupts::irq_lock{}; AND_GIVEN("IRQs are currently disabled") { kapi::interrupts::enabled(false); REQUIRE_FALSE(kapi::interrupts::enabled()); WHEN("locking the irq_lock") { lock.lock(); THEN("IRQs are still disabled") { REQUIRE_FALSE(kapi::interrupts::enabled()); AND_WHEN("unlocking the irq_lock") { lock.unlock(); THEN("IRQs are still disabled") { REQUIRE_FALSE(kapi::interrupts::enabled()); } } } THEN("the irq_lock is locked") { REQUIRE_FALSE(lock.try_lock()); lock.unlock(); } } THEN("the irq_lock can be locked") { REQUIRE(lock.try_lock()); lock.unlock(); } } AND_GIVEN("IRQs are currently enabled") { kapi::interrupts::enabled(true); REQUIRE(kapi::interrupts::enabled()); WHEN("locking the irq_lock") { lock.lock(); THEN("IRQs are disabled") { REQUIRE_FALSE(kapi::interrupts::enabled()); AND_WHEN("unlocking the irq_lock") { lock.unlock(); THEN("IRQs are enabled again") { REQUIRE(kapi::interrupts::enabled()); } } } } } } GIVEN("a wrapping irq_lock") { auto mutex = kapi::tracked_mutex{}; auto lock = kapi::interrupts::irq_lock{mutex}; AND_GIVEN("IRQs are currently disabled") { kapi::interrupts::enabled(false); REQUIRE_FALSE(kapi::interrupts::enabled()); WHEN("locking the irq_lock") { lock.lock(); THEN("IRQs are still disabled") { REQUIRE_FALSE(kapi::interrupts::enabled()); AND_WHEN("unlocking the irq_lock") { lock.unlock(); THEN("IRQs are still disabled") { REQUIRE_FALSE(kapi::interrupts::enabled()); } THEN("the inner mutex is unlocked") { REQUIRE(mutex.try_lock()); mutex.unlock(); } } } THEN("the irq_lock is locked") { REQUIRE_FALSE(lock.try_lock()); lock.unlock(); } THEN("the inner mutex is locked") { REQUIRE_FALSE(mutex.try_lock()); lock.unlock(); } } THEN("the irq_lock can be locked") { REQUIRE(lock.try_lock()); lock.unlock(); } } AND_GIVEN("IRQs are currently enabled") { kapi::interrupts::enabled(true); REQUIRE(kapi::interrupts::enabled()); WHEN("locking the irq_lock") { lock.lock(); THEN("IRQs are disabled") { REQUIRE_FALSE(kapi::interrupts::enabled()); AND_WHEN("unlocking the irq_lock") { lock.unlock(); THEN("IRQs are enabled again") { REQUIRE(kapi::interrupts::enabled()); } THEN("the inner mutex is unlocked") { REQUIRE(mutex.try_lock()); mutex.unlock(); } } } THEN("the irq_lock is locked") { REQUIRE_FALSE(lock.try_lock()); lock.unlock(); } THEN("the inner mutex is locked") { REQUIRE_FALSE(mutex.try_lock()); lock.unlock(); } } } AND_GIVEN("the inner mutex is already locked") { auto guard = kstd::lock_guard{mutex}; THEN("the irq_lock cannot be locked") { REQUIRE_FALSE(lock.try_lock()); } } } }