aboutsummaryrefslogtreecommitdiff
path: root/kernel
diff options
context:
space:
mode:
authorFelix Morgner <felix.morgner@ost.ch>2026-09-30 11:43:54 +0200
committerFelix Morgner <felix.morgner@ost.ch>2026-09-30 11:43:54 +0200
commitee4096101da245a792cd4df68973585305d09087 (patch)
tree982df6acd03b7a13d24a9eae665d7905376e54b3 /kernel
parent5bad38935238da045d9fd467eae9dfd958deea34 (diff)
parenta8f2e1a0edc37cd1c06447c42ff94f3370e8a6bc (diff)
downloadkernel-ee4096101da245a792cd4df68973585305d09087.tar.xz
kernel-ee4096101da245a792cd4df68973585305d09087.zip
Merge branch 'fmorgner/implement-interrupt-locking' into 'develop'
kapi/interrupts: implement irq_lock See merge request teachos/kernel!61
Diffstat (limited to 'kernel')
-rw-r--r--kernel/kapi/interrupts.stress.cpp65
-rw-r--r--kernel/kapi/interrupts.tests.cpp189
-rw-r--r--kernel/kernel/main.cpp2
-rw-r--r--kernel/kernel/test_support/kapi/interrupts.cpp14
4 files changed, 267 insertions, 3 deletions
diff --git a/kernel/kapi/interrupts.stress.cpp b/kernel/kapi/interrupts.stress.cpp
new file mode 100644
index 00000000..d3baf7b8
--- /dev/null
+++ b/kernel/kapi/interrupts.stress.cpp
@@ -0,0 +1,65 @@
+#include <kapi/interrupts.hpp>
+
+#include <kernel/test_support/cpu.hpp>
+
+#include <catch2/catch_test_macros.hpp>
+
+#include <future>
+#include <mutex>
+
+SCENARIO("irq_lock remote unlock protection", "[kapi][interrupts]")
+{
+ GIVEN("a simple irq_lock")
+ {
+ auto lock = kapi::interrupts::irq_lock{};
+
+ WHEN("it is locked on the main core")
+ {
+ auto guard = std::lock_guard{lock};
+
+ THEN("unlocking it on a different core panics")
+ {
+ auto unlocker = [&] {
+ try
+ {
+ lock.unlock();
+ return false;
+ }
+ catch (kernel::tests::cpu::halt const &)
+ {
+ return true;
+ }
+ };
+
+ auto result = std::async(std::launch::async, unlocker);
+
+ REQUIRE(result.get());
+ }
+ }
+ }
+
+ GIVEN("A heap allocated irq_lock")
+ {
+ // We use plain new-delete here, since the destruction path of std::shared_ptr is fully noexcept.
+ auto lock = new kapi::interrupts::irq_lock<>{};
+
+ THEN("destroying it on a different core panics")
+ {
+ auto destroyer = [&] {
+ try
+ {
+ delete lock;
+ return false;
+ }
+ catch (kernel::tests::cpu::halt const &)
+ {
+ return true;
+ }
+ };
+
+ auto result = std::async(std::launch::async, destroyer);
+
+ REQUIRE(result.get());
+ }
+ }
+} \ No newline at end of file
diff --git a/kernel/kapi/interrupts.tests.cpp b/kernel/kapi/interrupts.tests.cpp
new file mode 100644
index 00000000..e87c6a00
--- /dev/null
+++ b/kernel/kapi/interrupts.tests.cpp
@@ -0,0 +1,189 @@
+#include <kapi/interrupts.hpp>
+
+#include <kapi/tracked_mutex.hpp>
+
+#include <kstd/mutex.hpp>
+
+#include <catch2/catch_test_macros.hpp>
+
+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());
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/kernel/kernel/main.cpp b/kernel/kernel/main.cpp
index bc192950..bbbd46c0 100644
--- a/kernel/kernel/main.cpp
+++ b/kernel/kernel/main.cpp
@@ -293,7 +293,7 @@ auto main() -> int
kapi::devices::init_platform_devices();
kstd::println("[OS] Platform devices initialized.");
- kapi::interrupts::enable();
+ kapi::interrupts::enabled(true);
kstd::println("[OS] Interrupts enabled.");
auto modules_bus = kernel::devices::storage::init();
diff --git a/kernel/kernel/test_support/kapi/interrupts.cpp b/kernel/kernel/test_support/kapi/interrupts.cpp
index 00772669..3791b0dc 100644
--- a/kernel/kernel/test_support/kapi/interrupts.cpp
+++ b/kernel/kernel/test_support/kapi/interrupts.cpp
@@ -3,9 +3,19 @@
namespace kapi::interrupts
{
- auto enable() -> void
+ namespace
{
- // TODO: enable simulated interrupts.
+ thread_local bool interrupt_state{};
+ }
+
+ auto enabled() -> bool
+ {
+ return interrupt_state;
+ }
+
+ auto enabled(bool value) -> void
+ {
+ interrupt_state = value;
}
} // namespace kapi::interrupts \ No newline at end of file