aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFelix Morgner <felix.morgner@ost.ch>2026-07-26 23:44:11 +0200
committerFelix Morgner <felix.morgner@ost.ch>2026-07-26 23:44:11 +0200
commit724e7698dc2795cf96f07ba16a078abd4e93cb46 (patch)
tree94ef9c43c1a5baf3459bbc239e603cafea76e627
parent8ea14be48c3fce44add60533904a77ccc80138f7 (diff)
downloadkernel-724e7698dc2795cf96f07ba16a078abd4e93cb46.tar.xz
kernel-724e7698dc2795cf96f07ba16a078abd4e93cb46.zip
kapi/bus: extend stress tests
-rw-r--r--kernel/kapi/devices/bus.stress.cpp81
1 files changed, 79 insertions, 2 deletions
diff --git a/kernel/kapi/devices/bus.stress.cpp b/kernel/kapi/devices/bus.stress.cpp
index 3fefc892..507650f0 100644
--- a/kernel/kapi/devices/bus.stress.cpp
+++ b/kernel/kapi/devices/bus.stress.cpp
@@ -7,6 +7,7 @@
#include <atomic>
#include <cstddef>
+#include <mutex>
#include <thread>
#include <tuple>
#include <vector>
@@ -21,8 +22,8 @@ namespace
} // namespace
-constexpr auto thread_count = 8;
-constexpr auto devices_per_thread = 200;
+constexpr auto thread_count = 8uz;
+constexpr auto devices_per_thread = 200uz;
SCENARIO("Concurrent attach/detach/lookup on a bus is race-free")
{
@@ -73,4 +74,80 @@ SCENARIO("Concurrent attach/detach/lookup on a bus is race-free")
}
}
}
+}
+
+SCENARIO("Concurrent removal of a bus with its own children is race-free")
+{
+ GIVEN("A shared parent bus, and a pool of child busses attached to it")
+ {
+ auto parent_bus = kstd::make_shared<kapi::devices::bus>("stress_test_nested_parent");
+ kapi::devices::get_root_bus()->add_child(parent_bus);
+
+ constexpr auto pool_size = 8uz;
+
+ auto pool_lock = std::mutex{};
+ auto pool = std::vector<kstd::shared_ptr<kapi::devices::bus>>{};
+
+ for (auto i = 0uz; i < pool_size; ++i)
+ {
+ auto child = kstd::make_shared<kapi::devices::bus>(kstd::format("stress_test_nested_child_{}", i));
+ parent_bus->add_child(child);
+ pool.push_back(child);
+ }
+
+ WHEN("threads concurrently attach devices to shared child busses, while others tear an entire child bus down "
+ "through the parent and replace it")
+ {
+ auto threads = std::vector<std::jthread>{};
+ threads.reserve(thread_count);
+
+ auto failures = std::atomic<std::size_t>{0};
+
+ for (auto thread_index = 0uz; thread_index < thread_count; ++thread_index)
+ {
+ threads.emplace_back([&pool, &pool_lock, &parent_bus, &failures, thread_index] {
+ for (auto i = 0uz; i < devices_per_thread; ++i)
+ {
+ auto pool_index = (thread_index + i) % pool_size;
+
+ auto child_bus = kstd::shared_ptr<kapi::devices::bus>{};
+ {
+ auto guard = std::lock_guard{pool_lock};
+ child_bus = pool[pool_index];
+ }
+
+ auto name = kstd::format("stress_test_nested_device_{}_{}", thread_index, i);
+ auto device = kstd::make_shared<test_device>(name);
+
+ child_bus->add_child(device);
+
+ if (!child_bus->remove_child(*device))
+ {
+ ++failures;
+ }
+
+ if (i % 25 == 0)
+ {
+ if (parent_bus->remove_child(*child_bus))
+ {
+ auto replacement =
+ kstd::make_shared<kapi::devices::bus>(kstd::format("stress_test_nested_child_{}", pool_index));
+ parent_bus->add_child(replacement);
+
+ auto guard = std::lock_guard{pool_lock};
+ pool[pool_index] = replacement;
+ }
+ }
+ }
+ });
+ }
+
+ threads.clear();
+
+ THEN("every direct attach to a child bus was matched by a successful removal")
+ {
+ REQUIRE(failures == 0);
+ }
+ }
+ }
} \ No newline at end of file