aboutsummaryrefslogtreecommitdiff
path: root/kernel/kapi/devices/bus.stress.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/kapi/devices/bus.stress.cpp')
-rw-r--r--kernel/kapi/devices/bus.stress.cpp76
1 files changed, 76 insertions, 0 deletions
diff --git a/kernel/kapi/devices/bus.stress.cpp b/kernel/kapi/devices/bus.stress.cpp
new file mode 100644
index 00000000..226b0296
--- /dev/null
+++ b/kernel/kapi/devices/bus.stress.cpp
@@ -0,0 +1,76 @@
+#include <kapi/devices.hpp>
+
+#include <kstd/format.hpp>
+#include <kstd/memory.hpp>
+
+#include <catch2/catch_test_macros.hpp>
+
+#include <atomic>
+#include <cstddef>
+#include <thread>
+#include <tuple>
+#include <vector>
+
+namespace
+{
+
+ struct test_device final : kapi::devices::device
+ {
+ using kapi::devices::device::device;
+ };
+
+} // namespace
+
+constexpr auto thread_count = 32;
+constexpr auto devices_per_thread = 200;
+
+SCENARIO("Concurrent attach/detach/lookup on a bus is race-free")
+{
+ GIVEN("A bus shared by several threads")
+ {
+ auto shared_bus = kstd::make_shared<kapi::devices::bus>("stress_test_bus");
+ kapi::devices::get_root_bus()->add_child(shared_bus);
+
+ WHEN("each thread repeatedly attaches, detaches, and looks up devices concurrently with the others")
+ {
+ auto threads = std::vector<std::jthread>{};
+ threads.reserve(thread_count);
+
+ auto failure_count = std::atomic<std::size_t>{0};
+
+ for (auto thread_index = 0uz; thread_index < thread_count; ++thread_index)
+ {
+ threads.emplace_back([&shared_bus, &failure_count, thread_index] {
+ for (auto i = 0uz; i < devices_per_thread; ++i)
+ {
+ auto name = kstd::format("stress_test_device_{}_{}", thread_index, i);
+ auto device = kstd::make_shared<test_device>(name);
+
+ shared_bus->add_child(device);
+
+ std::ignore = kapi::devices::device_registry::get().find(name);
+ std::ignore = kapi::devices::device_registry::get().all();
+ std::ignore = shared_bus->children().size();
+
+ if (!shared_bus->remove_child(*device))
+ {
+ ++failure_count;
+ };
+ }
+ });
+ }
+
+ threads.clear();
+
+ THEN("every attach was matched by a successful removal")
+ {
+ REQUIRE(failure_count == 0);
+ }
+
+ THEN("the bus has no children")
+ {
+ REQUIRE(shared_bus->children().empty());
+ }
+ }
+ }
+} \ No newline at end of file