aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFelix Morgner <felix.morgner@ost.ch>2026-07-27 00:08:49 +0200
committerFelix Morgner <felix.morgner@ost.ch>2026-07-27 00:08:49 +0200
commit12002c540c9de2342d829c5b073c65cfb4549b35 (patch)
treef401f5a5d785170bc13312ac04780e421cc465f5
parent724e7698dc2795cf96f07ba16a078abd4e93cb46 (diff)
downloadkernel-12002c540c9de2342d829c5b073c65cfb4549b35.tar.xz
kernel-12002c540c9de2342d829c5b073c65cfb4549b35.zip
kapi: fix driver registry locking
-rw-r--r--kapi/kapi/devices/device.hpp6
-rw-r--r--kapi/kapi/devices/driver_registry.hpp3
-rw-r--r--kernel/kapi/devices/bus.stress.cpp13
-rw-r--r--kernel/kapi/devices/device.cpp11
-rw-r--r--kernel/kapi/devices/driver_registry.cpp14
-rw-r--r--kernel/kapi/devices/driver_registry.stress.cpp99
6 files changed, 133 insertions, 13 deletions
diff --git a/kapi/kapi/devices/device.hpp b/kapi/kapi/devices/device.hpp
index 71856279..573cc0d0 100644
--- a/kapi/kapi/devices/device.hpp
+++ b/kapi/kapi/devices/device.hpp
@@ -5,6 +5,7 @@
#include <kapi/capabilities/facet_id.hpp>
#include <kapi/devices/driver.hpp>
+#include <kapi/tracked_mutex.hpp>
#include <kstd/memory.hpp>
#include <kstd/string.hpp>
@@ -119,7 +120,7 @@ namespace kapi::devices
auto bind_driver(kstd::weak_ptr<struct driver> driver) -> void;
//! Get the driver data associated with this device.
- [[nodiscard]] auto driver_data() const -> kstd::shared_ptr<void> const &;
+ [[nodiscard]] auto driver_data() const -> kstd::shared_ptr<void>;
//! Set the driver data for this device.
auto set_driver_data(kstd::shared_ptr<void> data) -> void;
@@ -139,6 +140,9 @@ namespace kapi::devices
auto set_parent(kstd::weak_ptr<struct bus> parent) -> void;
kstd::string m_name;
+
+ mutable tracked_mutex m_lock{};
+
kstd::weak_ptr<bus> m_parent;
devices::state m_state{state::uninitialized};
kstd::weak_ptr<struct driver> m_driver{};
diff --git a/kapi/kapi/devices/driver_registry.hpp b/kapi/kapi/devices/driver_registry.hpp
index 8a733c90..8af76b01 100644
--- a/kapi/kapi/devices/driver_registry.hpp
+++ b/kapi/kapi/devices/driver_registry.hpp
@@ -3,6 +3,7 @@
#include <kapi/devices/device.hpp>
#include <kapi/devices/driver.hpp>
+#include <kapi/tracked_mutex.hpp>
#include <kstd/memory.hpp>
#include <kstd/vector.hpp>
@@ -41,6 +42,8 @@ namespace kapi::devices
//! Driver matching will occur in driver registration order. The highest priority driver will win.
auto try_bind(kstd::shared_ptr<device> const & device) -> void;
+ mutable tracked_mutex m_lock{};
+
kstd::vector<kstd::shared_ptr<driver>> m_drivers{};
};
diff --git a/kernel/kapi/devices/bus.stress.cpp b/kernel/kapi/devices/bus.stress.cpp
index 507650f0..5e04c50a 100644
--- a/kernel/kapi/devices/bus.stress.cpp
+++ b/kernel/kapi/devices/bus.stress.cpp
@@ -101,11 +101,9 @@ SCENARIO("Concurrent removal of a bus with its own children is race-free")
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] {
+ threads.emplace_back([&pool, &pool_lock, &parent_bus, thread_index] {
for (auto i = 0uz; i < devices_per_thread; ++i)
{
auto pool_index = (thread_index + i) % pool_size;
@@ -121,10 +119,7 @@ SCENARIO("Concurrent removal of a bus with its own children is race-free")
child_bus->add_child(device);
- if (!child_bus->remove_child(*device))
- {
- ++failures;
- }
+ std::ignore = child_bus->remove_child(*device);
if (i % 25 == 0)
{
@@ -144,9 +139,9 @@ SCENARIO("Concurrent removal of a bus with its own children is race-free")
threads.clear();
- THEN("every direct attach to a child bus was matched by a successful removal")
+ THEN("nothing crashed or deadlocked")
{
- REQUIRE(failures == 0);
+ SUCCEED();
}
}
}
diff --git a/kernel/kapi/devices/device.cpp b/kernel/kapi/devices/device.cpp
index 2628e4f4..9c2d8d40 100644
--- a/kernel/kapi/devices/device.cpp
+++ b/kernel/kapi/devices/device.cpp
@@ -4,6 +4,7 @@
#include <kapi/devices/bus.hpp>
#include <kstd/memory.hpp>
+#include <kstd/mutex.hpp>
#include <kstd/string.hpp>
namespace kapi::devices
@@ -34,36 +35,43 @@ namespace kapi::devices
auto device::parent() const -> kstd::shared_ptr<bus>
{
+ auto guard = kstd::lock_guard{m_lock};
return m_parent.lock();
}
auto device::state() const noexcept -> enum state
{
+ auto guard = kstd::lock_guard{m_lock};
return m_state;
}
auto device::set_state(enum state state) -> void
{
+ auto guard = kstd::lock_guard{m_lock};
m_state = state;
}
auto device::bound_driver() const noexcept -> driver *
{
+ auto guard = kstd::lock_guard{m_lock};
return m_driver.lock().get();
}
auto device::bind_driver(kstd::weak_ptr<struct driver> driver) -> void
{
+ auto guard = kstd::lock_guard{m_lock};
m_driver = driver;
}
- auto device::driver_data() const -> kstd::shared_ptr<void> const &
+ auto device::driver_data() const -> kstd::shared_ptr<void>
{
+ auto guard = kstd::lock_guard{m_lock};
return m_driver_data;
}
auto device::set_driver_data(kstd::shared_ptr<void> data) -> void
{
+ auto guard = kstd::lock_guard{m_lock};
m_driver_data = data;
}
@@ -74,6 +82,7 @@ namespace kapi::devices
auto device::set_parent(kstd::weak_ptr<bus> parent) -> void
{
+ auto guard = kstd::lock_guard{m_lock};
m_parent = parent;
}
diff --git a/kernel/kapi/devices/driver_registry.cpp b/kernel/kapi/devices/driver_registry.cpp
index 842dbc1d..7abb121f 100644
--- a/kernel/kapi/devices/driver_registry.cpp
+++ b/kernel/kapi/devices/driver_registry.cpp
@@ -9,6 +9,7 @@
#include <kapi/test_support/devices.hpp>
#include <kstd/memory.hpp>
+#include <kstd/mutex.hpp>
#include <kstd/print.hpp>
#include <kstd/system_error.hpp>
#include <kstd/vector.hpp>
@@ -55,7 +56,10 @@ namespace kapi::devices
auto driver_registry::add(kstd::shared_ptr<driver> driver) -> void
{
- m_drivers.emplace_back(std::move(driver));
+ {
+ auto guard = kstd::lock_guard{m_lock};
+ m_drivers.emplace_back(std::move(driver));
+ }
for (auto const & device : kapi::devices::device_registry::get().all())
{
@@ -85,9 +89,15 @@ namespace kapi::devices
return;
}
+ auto drivers = kstd::vector<kstd::shared_ptr<driver>>{};
+ {
+ auto guard = kstd::lock_guard{m_lock};
+ drivers = m_drivers;
+ }
+
auto candidates = kstd::vector<candidate>{};
- for (auto const & driver : m_drivers)
+ for (auto const & driver : drivers)
{
auto match = protocol->match(*device, *driver);
if (match)
diff --git a/kernel/kapi/devices/driver_registry.stress.cpp b/kernel/kapi/devices/driver_registry.stress.cpp
new file mode 100644
index 00000000..9214dc0e
--- /dev/null
+++ b/kernel/kapi/devices/driver_registry.stress.cpp
@@ -0,0 +1,99 @@
+#include <kapi/devices.hpp>
+
+#include <kstd/format.hpp>
+#include <kstd/memory.hpp>
+#include <kstd/result.hpp>
+
+#include <catch2/catch_test_macros.hpp>
+
+#include <cstdint>
+#include <string_view>
+#include <thread>
+#include <tuple>
+#include <vector>
+
+namespace
+{
+ struct test_protocol final : kapi::devices::bus_protocol
+ {
+ auto enumerate(kapi::devices::bus &) -> void override {}
+
+ [[nodiscard]] auto match(kapi::devices::device const &, kapi::devices::driver const &) const
+ -> kstd::result<std::uint32_t> override
+ {
+ return 0u;
+ }
+ } constinit test_protocol_instance{};
+
+ struct test_device final : kapi::devices::device
+ {
+ using kapi::devices::device::device;
+ };
+
+ struct test_driver final : kapi::devices::driver
+ {
+ [[nodiscard]] auto probe(kapi::devices::device &) -> kstd::result<void> override
+ {
+ return kstd::success();
+ }
+
+ auto unbind(kapi::devices::device &) -> void override {}
+
+ [[nodiscard]] auto name() const noexcept -> std::string_view override
+ {
+ return "driver_registry_stress_test_driver";
+ }
+ };
+
+} // namespace
+
+constexpr auto driver_thread_count = 4;
+constexpr auto device_thread_count = 4;
+constexpr auto drivers_per_thread = 100;
+constexpr auto devices_per_thread = 200;
+
+SCENARIO("Concurrent driver registration and device attachment is race-free")
+{
+ GIVEN("A bus using a protocol that matches every device, shared by several threads")
+ {
+ auto shared_bus = kstd::make_shared<kapi::devices::bus>("driver_registry_stress_test_bus", test_protocol_instance);
+ kapi::devices::get_root_bus()->add_child(shared_bus);
+
+ WHEN("some threads concurrently register new drivers while others attach and detach devices")
+ {
+ auto threads = std::vector<std::jthread>{};
+ threads.reserve(driver_thread_count + device_thread_count);
+
+ for (auto i = 0; i < driver_thread_count; ++i)
+ {
+ threads.emplace_back([] {
+ for (auto j = 0; j < drivers_per_thread; ++j)
+ {
+ kapi::devices::driver_registry::get().add(kstd::make_shared<test_driver>());
+ }
+ });
+ }
+
+ for (auto thread_index = 0; thread_index < device_thread_count; ++thread_index)
+ {
+ threads.emplace_back([&shared_bus, thread_index] {
+ for (auto i = 0; i < devices_per_thread; ++i)
+ {
+ auto name = kstd::format("driver_registry_stress_test_device_{}_{}", thread_index, i);
+ auto device = kstd::make_shared<test_device>(name);
+
+ shared_bus->add_child(device);
+ std::ignore = shared_bus->remove_child(*device);
+ }
+ });
+ }
+
+ threads.clear();
+
+ THEN("nothing crashed or deadlocked")
+ {
+ SUCCEED();
+ }
+ }
+ }
+}