aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFelix Morgner <felix.morgner@ost.ch>2026-07-26 21:46:37 +0200
committerFelix Morgner <felix.morgner@ost.ch>2026-07-26 21:46:37 +0200
commit4b28e4626e744ac9b779a680f8e9647014956dda (patch)
tree9b5203e083ed27091c70d60e3cdf9284af680c81
parente7cb0a5dab291d453fa34c5d1250d85e82478ecf (diff)
downloadkernel-4b28e4626e744ac9b779a680f8e9647014956dda.tar.xz
kernel-4b28e4626e744ac9b779a680f8e9647014956dda.zip
kapi/devices: implement locking discipline
-rw-r--r--.vscode/settings.json4
-rw-r--r--cmake/Modules/BuildHostTests.cmake1
-rw-r--r--kapi/kapi/devices/bus.hpp3
-rw-r--r--kapi/kapi/devices/device_registry.hpp3
-rw-r--r--kapi/kapi/devices/facet_registry.hpp3
-rw-r--r--kernel/kapi/devices/bus.cpp38
-rw-r--r--kernel/kapi/devices/bus.stress.cpp76
-rw-r--r--kernel/kapi/devices/device_registry.cpp96
-rw-r--r--kernel/kapi/devices/facet_registry.cpp130
-rw-r--r--kernel/kernel/filesystem/device_number_registry.cpp88
-rw-r--r--kernel/kernel/filesystem/device_number_registry.hpp3
-rw-r--r--kernel/kernel/test_support/cio.hpp3
-rw-r--r--kernel/kernel/test_support/log_buffer.cpp11
-rw-r--r--kernel/kernel/test_support/log_buffer.hpp5
-rw-r--r--kernel/kernel/test_support/output_device.cpp3
15 files changed, 320 insertions, 147 deletions
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 7b537ecb..b38c2c7d 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -14,8 +14,8 @@
"explorer.fileNesting.enabled": true,
"explorer.fileNesting.expand": false,
"explorer.fileNesting.patterns": {
- "*.hpp": "${capture}.cpp, ${capture}.tests.cpp, ${capture}.S",
- "*.cpp": "${capture}.tests.cpp",
+ "*.hpp": "${capture}.cpp, ${capture}.tests.cpp, ${capture}.stress.cpp, ${capture}.S",
+ "*.cpp": "${capture}.tests.cpp, ${capture}.stress.cpp",
},
"[cpp]": {
"editor.formatOnSave": true,
diff --git a/cmake/Modules/BuildHostTests.cmake b/cmake/Modules/BuildHostTests.cmake
index aa3ae66d..70038b46 100644
--- a/cmake/Modules/BuildHostTests.cmake
+++ b/cmake/Modules/BuildHostTests.cmake
@@ -8,6 +8,7 @@ function("teachos_add_tests" NAME)
TEST_SOURCES
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
CONFIGURE_DEPENDS
+ "*.stress.cpp"
"*.tests.cpp"
)
diff --git a/kapi/kapi/devices/bus.hpp b/kapi/kapi/devices/bus.hpp
index 13951e46..2ee12628 100644
--- a/kapi/kapi/devices/bus.hpp
+++ b/kapi/kapi/devices/bus.hpp
@@ -6,6 +6,7 @@
#include <kapi/capabilities/facet_id.hpp>
#include <kapi/devices/bus_protocol.hpp>
#include <kapi/devices/device.hpp>
+#include <kapi/tracked_mutex.hpp>
#include <kstd/memory.hpp>
#include <kstd/print.hpp>
@@ -65,6 +66,8 @@ namespace kapi::devices
private:
auto do_remove_child(device & child) -> void;
+ mutable tracked_mutex m_lock{};
+
bus_protocol * m_protocol{};
kstd::vector<kstd::shared_ptr<device>> m_devices{};
};
diff --git a/kapi/kapi/devices/device_registry.hpp b/kapi/kapi/devices/device_registry.hpp
index a65bd4ad..816ad984 100644
--- a/kapi/kapi/devices/device_registry.hpp
+++ b/kapi/kapi/devices/device_registry.hpp
@@ -4,6 +4,7 @@
// IWYU pragma: private, include <kapi/devices.hpp>
#include <kapi/devices/device.hpp>
+#include <kapi/tracked_mutex.hpp>
#include <kstd/flat_map.hpp>
#include <kstd/memory.hpp>
@@ -79,6 +80,8 @@ namespace kapi::devices
auto subscribe(kstd::weak_ptr<device_registry_observer> observer) -> void;
private:
+ mutable tracked_mutex m_lock{};
+
kstd::flat_map<kstd::string, kstd::weak_ptr<device>> m_devices{};
kstd::vector<kstd::weak_ptr<device_registry_observer>> m_observers{};
};
diff --git a/kapi/kapi/devices/facet_registry.hpp b/kapi/kapi/devices/facet_registry.hpp
index 82bb304b..7006c026 100644
--- a/kapi/kapi/devices/facet_registry.hpp
+++ b/kapi/kapi/devices/facet_registry.hpp
@@ -5,6 +5,7 @@
#include <kapi/capabilities/facet_id.hpp>
#include <kapi/devices/device.hpp>
+#include <kapi/tracked_mutex.hpp>
#include <kstd/memory.hpp>
#include <kstd/result.hpp>
@@ -268,6 +269,8 @@ namespace kapi::devices
//! @param device The device.
auto do_notify_withdrawn(kapi::capabilities::facet_id id, device const & device) -> void;
+ mutable tracked_mutex m_lock{};
+
kstd::vector<entry> m_entries;
kstd::vector<kstd::weak_ptr<facet_registry_observer>> m_observers;
kstd::vector<facet_registry_observer *> m_static_observers;
diff --git a/kernel/kapi/devices/bus.cpp b/kernel/kapi/devices/bus.cpp
index d917eb96..71dd01e6 100644
--- a/kernel/kapi/devices/bus.cpp
+++ b/kernel/kapi/devices/bus.cpp
@@ -6,6 +6,7 @@
#include <kapi/system.hpp>
#include <kstd/memory.hpp>
+#include <kstd/mutex.hpp>
#include <kstd/string.hpp>
#include <kstd/vector.hpp>
@@ -42,30 +43,32 @@ namespace kapi::devices
kapi::system::panic("[OS:DEV] Failed to register child device {}", child->name());
}
- // TODO: lock bus
+ auto attached = kstd::shared_ptr<device>{};
+ {
+ auto guard = kstd::lock_guard{m_lock};
+ attached = m_devices.emplace_back(std::move(child));
+ }
- auto & attached = m_devices.emplace_back(std::move(child));
attached->set_state(state::present);
- // TODO: unlock bus
-
driver_registry::get().device_attached(attached);
}
auto bus::remove_child(device & device) -> bool // NOLINT(misc-no-recursion)
{
- // TODO: lock bus
-
- auto found = std::ranges::find_if(m_devices, [&](auto const & d) { return d.get() == &device; });
- if (!found)
+ auto lifeline = kstd::shared_ptr<struct device>{};
{
- return false;
- }
+ auto guard = kstd::lock_guard{m_lock};
- auto lifeline = *found;
- m_devices.erase(found);
+ auto found = std::ranges::find_if(m_devices, [&](auto const & d) { return d.get() == &device; });
+ if (found == m_devices.end())
+ {
+ return false;
+ }
- // TODO: unlock bus
+ lifeline = *found;
+ m_devices.erase(found);
+ }
do_remove_child(*lifeline);
return true;
@@ -100,10 +103,11 @@ namespace kapi::devices
if (auto child_bus = device.facet<bus>())
{
auto grandchildren = kstd::vector<kstd::shared_ptr<kapi::devices::device>>{};
- // TODO: lock child bus
- // NOTE: this could be more efficient one vector::assign is implemented.
- grandchildren = kstd::vector(child_bus->m_devices.begin(), child_bus->m_devices.end());
- // TODO: unlock child bus
+ {
+ auto guard = kstd::lock_guard{m_lock};
+ // NOTE: this could be more efficient one vector::assign is implemented.
+ grandchildren = kstd::vector(child_bus->m_devices.begin(), child_bus->m_devices.end());
+ }
for (auto & grandchild : grandchildren)
{
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
diff --git a/kernel/kapi/devices/device_registry.cpp b/kernel/kapi/devices/device_registry.cpp
index f5c20a6d..80ddde65 100644
--- a/kernel/kapi/devices/device_registry.cpp
+++ b/kernel/kapi/devices/device_registry.cpp
@@ -4,6 +4,7 @@
#include <kapi/system.hpp>
#include <kstd/memory.hpp>
+#include <kstd/mutex.hpp>
#include <kstd/print.hpp>
#include <kstd/string.hpp>
#include <kstd/vector.hpp>
@@ -27,7 +28,7 @@ namespace kapi::devices
system::panic("[OS:DEV] Device registry has already been initialized");
}
- instance = device_registry{};
+ instance.emplace();
}
auto device_registry::get() -> device_registry &
@@ -50,33 +51,38 @@ namespace kapi::devices
kstd::println("[OS:DEV] Registering device {}", device->name());
auto added = false;
-
- // TODO: lock the registry
- auto found = m_devices.find(device->name());
- if (found != m_devices.end())
{
- if (!found->second.expired())
+ auto guard = kstd::lock_guard{m_lock};
+
+ auto found = m_devices.find(device->name());
+ if (found != m_devices.end())
{
- added = false;
- }
+ if (!found->second.expired())
+ {
+ added = false;
+ }
- found->second = device;
- added = true;
- }
- else
- {
- added = m_devices.emplace(device->name(), device).second;
+ found->second = device;
+ added = true;
+ }
+ else
+ {
+ added = m_devices.emplace(device->name(), device).second;
+ }
}
- // TODO: unlock registry
if (!added)
{
return false;
}
- // TODO: consider if we need to lock the registry observers here, since somebody may add an observer in the meantime
- // once multiple codepaths can run at the same time.
- for (auto const & observer : m_observers)
+ auto observers = kstd::vector<kstd::weak_ptr<device_registry_observer>>{};
+ {
+ auto guard = kstd::lock_guard{m_lock};
+ observers = m_observers;
+ }
+
+ for (auto const & observer : observers)
{
if (auto locked_observer = observer.lock())
{
@@ -84,36 +90,43 @@ namespace kapi::devices
}
}
- // TODO: lock registry
- erase_if(m_observers, [](auto const & observer) { return observer.expired(); });
- // TODO: unlock registry
+ {
+ auto guard = kstd::lock_guard{m_lock};
+ erase_if(m_observers, [](auto const & observer) { return observer.expired(); });
+ }
return true;
}
auto device_registry::remove(device & device) -> bool
{
- // TODO: lock registry
-
- auto found = m_devices.find(device.name());
- if (found == m_devices.end())
{
- return false;
- }
+ auto guard = kstd::lock_guard{m_lock};
- auto locked = found->second.lock();
- if (!locked || locked.get() != &device)
- {
- return false;
- }
+ auto found = m_devices.find(device.name());
+ if (found == m_devices.end())
+ {
+ return false;
+ }
- found->second = kstd::weak_ptr<struct device>{};
+ auto locked = found->second.lock();
+ if (!locked || locked.get() != &device)
+ {
+ return false;
+ }
- // TODO: unlock registry
+ found->second = kstd::weak_ptr<struct device>{};
+ }
kstd::println("[OS:DEV] Unregistering device {}", device.name());
- for (auto const & observer : m_observers)
+ auto observers = kstd::vector<kstd::weak_ptr<device_registry_observer>>{};
+ {
+ auto guard = kstd::lock_guard{m_lock};
+ observers = m_observers;
+ }
+
+ for (auto const & observer : observers)
{
if (auto locked_observer = observer.lock())
{
@@ -121,16 +134,17 @@ namespace kapi::devices
}
}
- // TODO: lock registry
- erase_if(m_observers, [](auto const & observer) { return observer.expired(); });
- // TODO: unlock registry
+ {
+ auto guard = kstd::lock_guard{m_lock};
+ erase_if(m_observers, [](auto const & observer) { return observer.expired(); });
+ }
return true;
}
auto device_registry::find(std::string_view name) const -> kstd::shared_ptr<device>
{
- // TODO: lock registry
+ auto guard = kstd::lock_guard{m_lock};
auto found = m_devices.find(kstd::string{name});
if (found == m_devices.end())
@@ -143,7 +157,7 @@ namespace kapi::devices
auto device_registry::all() const -> kstd::vector<kstd::shared_ptr<device>>
{
- // TODO: lock registry
+ auto guard = kstd::lock_guard{m_lock};
auto result = kstd::vector<kstd::shared_ptr<device>>{};
@@ -160,7 +174,7 @@ namespace kapi::devices
auto device_registry::subscribe(kstd::weak_ptr<device_registry_observer> observer) -> void
{
- // TODO: lock registry
+ auto guard = kstd::lock_guard{m_lock};
erase_if(m_observers, [](auto const & observer) { return observer.expired(); });
m_observers.push_back(observer);
diff --git a/kernel/kapi/devices/facet_registry.cpp b/kernel/kapi/devices/facet_registry.cpp
index 4aeebfc1..623ecba2 100644
--- a/kernel/kapi/devices/facet_registry.cpp
+++ b/kernel/kapi/devices/facet_registry.cpp
@@ -5,6 +5,7 @@
#include <kapi/test_support/devices.hpp>
#include <kstd/memory.hpp>
+#include <kstd/mutex.hpp>
#include <kstd/result.hpp>
#include <kstd/string.hpp>
#include <kstd/system_error.hpp>
@@ -46,64 +47,87 @@ namespace kapi::devices
auto facet_registry::do_publish(kstd::shared_ptr<device> device, kstd::string name, kapi::capabilities::facet_id id,
void * facet) -> kstd::result<void>
{
- // TODO: lock registry
+ auto published = std::optional<entry>{};
- erase_if(m_entries, [id](auto e) { return e.id() == id && !e.device(); });
-
- if (!device || !facet || name.empty())
{
- return kstd::failure(make_error_code(kstd::errc::invalid_argument));
- }
+ auto guard = kstd::lock_guard{m_lock};
- auto already_published = std::ranges::any_of(
- m_entries, [&](auto const & entry) { return entry.id() == id && entry.device().get() == device.get(); });
+ erase_if(m_entries, [id](auto e) { return e.id() == id && !e.device(); });
- if (already_published)
- {
- return kstd::failure(make_error_code(kstd::errc::file_exists));
- }
+ if (!device || !facet || name.empty())
+ {
+ return kstd::failure(make_error_code(kstd::errc::invalid_argument));
+ }
- auto & published = m_entries.emplace_back(device, std::move(name), id, facet);
+ auto already_published = std::ranges::any_of(
+ m_entries, [&](auto const & entry) { return entry.id() == id && entry.device().get() == device.get(); });
- do_notify_published(id, published);
+ if (already_published)
+ {
+ return kstd::failure(make_error_code(kstd::errc::file_exists));
+ }
+
+ published = m_entries.emplace_back(device, std::move(name), id, facet);
+ }
+
+ do_notify_published(id, *published);
return kstd::success();
}
auto facet_registry::do_notify_published(kapi::capabilities::facet_id id, entry const & published) -> void
{
- std::ranges::for_each(m_observers, [&](auto observer) {
+ auto observers = kstd::vector<kstd::weak_ptr<facet_registry_observer>>{};
+ auto static_observers = kstd::vector<facet_registry_observer *>{};
+ {
+ auto guard = kstd::lock_guard{m_lock};
+ observers = m_observers;
+ static_observers = m_static_observers;
+ }
+
+ std::ranges::for_each(observers, [&](auto observer) {
if (auto locked_observer = observer.lock())
{
locked_observer->on_facet_published(id, published);
}
});
- std::ranges::for_each(m_static_observers, [&](auto observer) { observer->on_facet_published(id, published); });
+ std::ranges::for_each(static_observers, [&](auto observer) { observer->on_facet_published(id, published); });
}
auto facet_registry::do_notify_withdrawn(kapi::capabilities::facet_id id, device const & device) -> void
{
- std::ranges::for_each(m_observers, [&](auto observer) {
+ auto observers = kstd::vector<kstd::weak_ptr<facet_registry_observer>>{};
+ auto static_observers = kstd::vector<facet_registry_observer *>{};
+ {
+ auto guard = kstd::lock_guard{m_lock};
+ observers = m_observers;
+ static_observers = m_static_observers;
+ }
+
+ std::ranges::for_each(observers, [&](auto observer) {
if (auto locked_observer = observer.lock())
{
locked_observer->on_facet_withdrawn(id, const_cast<devices::device &>(device));
}
});
- std::ranges::for_each(m_static_observers, [&](auto observer) {
+ std::ranges::for_each(static_observers, [&](auto observer) {
observer->on_facet_withdrawn(id, const_cast<devices::device &>(device));
});
}
auto facet_registry::withdraw(device const & device, kapi::capabilities::facet_id id) -> void
{
- // TODO: lock registry
+ auto did_remove = false;
- auto did_remove = erase_if(m_entries, [&](auto e) {
- auto locked_device = e.device();
- return e.id() == id && locked_device && locked_device.get() == &device;
- }) != 0;
+ {
+ auto guard = kstd::lock_guard{m_lock};
+ did_remove = erase_if(m_entries, [&](auto e) {
+ auto locked_device = e.device();
+ return e.id() == id && locked_device && locked_device.get() == &device;
+ }) != 0;
+ }
if (did_remove)
{
@@ -113,26 +137,28 @@ namespace kapi::devices
auto facet_registry::withdraw_all_for(device const & device) -> void
{
- // TODO: lock registry
-
auto withdrawn_facets = kstd::vector<kapi::capabilities::facet_id>{};
- erase_if(m_entries, [&](auto e) {
- auto locked_device = e.device();
- auto do_erase = locked_device && locked_device.get() == &device;
- if (do_erase)
- {
- withdrawn_facets.push_back(e.id());
- }
- return do_erase;
- });
+ {
+ auto guard = kstd::lock_guard{m_lock};
+
+ erase_if(m_entries, [&](auto e) {
+ auto locked_device = e.device();
+ auto do_erase = locked_device && locked_device.get() == &device;
+ if (do_erase)
+ {
+ withdrawn_facets.push_back(e.id());
+ }
+ return do_erase;
+ });
+ }
std::ranges::for_each(withdrawn_facets, [&](auto facet) { do_notify_withdrawn(facet, device); });
}
auto facet_registry::all(kapi::capabilities::facet_id id) const -> kstd::vector<entry>
{
- // TODO: lock registry
+ auto guard = kstd::lock_guard{m_lock};
auto filtered = m_entries;
erase_if(filtered, [&](auto e) {
@@ -142,33 +168,39 @@ namespace kapi::devices
return filtered;
}
- auto facet_registry::resolve(kapi::capabilities::facet_id id, std::string_view name) -> void *
+ auto facet_registry::resolve(kapi::capabilities::facet_id facet, std::string_view name) -> void *
{
- // TODO: lock registry
+ auto found_device = kstd::shared_ptr<device>{};
+ {
+ auto guard = kstd::lock_guard{m_lock};
- auto found = std::ranges::find_if(m_entries, [&](auto e) { return e.name() == name && e.device(); });
+ auto found = std::ranges::find_if(m_entries, [&](auto e) { return e.name() == name && e.device(); });
- if (found == m_entries.cend())
- {
- return nullptr;
+ if (found == m_entries.cend())
+ {
+ return nullptr;
+ }
+
+ found_device = found->device();
}
- else if (auto device = found->device())
+
+ if (!found_device)
{
- return resolve(id, *device);
+ return nullptr;
}
- return nullptr;
+ return resolve(facet, *found_device);
}
auto facet_registry::resolve(kapi::capabilities::facet_id id, device & device) -> void *
{
- // TODO: lock registry
-
if (auto by_device = device.facet(id))
{
return by_device;
}
+ auto guard = kstd::lock_guard{m_lock};
+
auto found = std::ranges::find_if(m_entries, [&](auto e) {
auto locked_device = e.device();
return e.id() == id && locked_device && locked_device.get() == &device;
@@ -184,7 +216,7 @@ namespace kapi::devices
auto facet_registry::subscribe(kstd::weak_ptr<facet_registry_observer> observer) -> void
{
- // TODO: lock registry
+ auto guard = kstd::lock_guard{m_lock};
erase_if(m_observers, [](auto const & observer) { return observer.expired(); });
m_observers.push_back(observer);
@@ -192,14 +224,14 @@ namespace kapi::devices
auto facet_registry::subscribe(facet_registry_observer & observer) -> void
{
- // TODO: lock registry
+ auto guard = kstd::lock_guard{m_lock};
m_static_observers.push_back(&observer);
}
auto facet_registry::unsubscribe(facet_registry_observer & observer) -> void
{
- // TODO: lock registry
+ auto guard = kstd::lock_guard{m_lock};
erase_if(m_observers, [&](auto const & subscribed) { return subscribed.lock().get() == &observer; });
erase(m_static_observers, &observer);
diff --git a/kernel/kernel/filesystem/device_number_registry.cpp b/kernel/kernel/filesystem/device_number_registry.cpp
index d51a343a..0292ff94 100644
--- a/kernel/kernel/filesystem/device_number_registry.cpp
+++ b/kernel/kernel/filesystem/device_number_registry.cpp
@@ -8,6 +8,7 @@
#include <kapi/filesystem.hpp>
#include <kstd/memory.hpp>
+#include <kstd/mutex.hpp>
#include <kstd/result.hpp>
#include <kstd/vector.hpp>
@@ -56,7 +57,7 @@ namespace kernel::filesystem
auto device_number_registry::resolve(kapi::filesystem::device_number number, file_type type) const
-> kstd::result<kstd::shared_ptr<kapi::devices::device>>
{
- // TODO: lock registry
+ auto guard = kstd::lock_guard{m_lock};
erase_if(m_entries, [&](auto entry) { return entry.device.expired(); });
@@ -79,7 +80,7 @@ namespace kernel::filesystem
auto device_number_registry::number_of(kapi::devices::device const & device) const
-> kstd::result<kapi::filesystem::device_number>
{
- // TODO: lock registry
+ auto guard = kstd::lock_guard{m_lock};
erase_if(m_entries, [&](auto entry) { return entry.device.expired(); });
@@ -98,7 +99,7 @@ namespace kernel::filesystem
auto device_number_registry::all() const -> kstd::vector<entry>
{
- // TODO: lock registry
+ auto guard = kstd::lock_guard{m_lock};
erase_if(m_entries, [&](auto entry) { return entry.device.expired(); });
@@ -107,7 +108,7 @@ namespace kernel::filesystem
auto device_number_registry::subscribe(kstd::weak_ptr<device_number_registry_observer> observer) -> void
{
- // TODO: lock registry
+ auto guard = kstd::lock_guard{m_lock};
erase_if(m_observers, [&](auto existing) { return existing.expired(); });
@@ -131,24 +132,32 @@ namespace kernel::filesystem
return;
}
- // TODO: lock registry
+ auto unnumbered = entry{};
- auto found = std::ranges::find_if(m_entries, [&](auto entry) {
- auto locked = entry.device.lock();
- return entry.type == binding->posix_type && locked.get() == &device;
- });
-
- if (found == std::ranges::cend(m_entries))
{
+ auto guard = kstd::lock_guard{m_lock};
+
+ auto found = std::ranges::find_if(m_entries, [&](auto entry) {
+ auto locked = entry.device.lock();
+ return entry.type == binding->posix_type && locked.get() == &device;
+ });
+
+ if (found == std::ranges::cend(m_entries))
+ {
+ return;
+ }
+
+ unnumbered = *found;
m_entries.erase(found);
}
- auto unnumbered = *found;
- m_entries.erase(found);
-
- // TODO: drop lock
+ auto observers = kstd::vector<kstd::weak_ptr<device_number_registry_observer>>{};
+ {
+ auto guard = kstd::lock_guard{m_lock};
+ observers = m_observers;
+ }
- std::ranges::for_each(m_observers, [&](auto const & weak_observer) {
+ std::ranges::for_each(observers, [&](auto const & weak_observer) {
auto observer = weak_observer.lock();
if (observer)
{
@@ -189,31 +198,38 @@ namespace kernel::filesystem
return;
}
- // TODO: lock registry
-
- auto next_minor = m_next_minor.find(driver);
- auto minor = std::uint8_t{};
- if (next_minor != m_next_minor.end())
- {
- minor = next_minor->second++;
- }
- else
+ auto numbered = entry{};
{
- m_next_minor.emplace(driver, std::uint8_t{1});
- }
+ auto guard = kstd::lock_guard{m_lock};
+
+ auto next_minor = m_next_minor.find(driver);
+ auto minor = std::uint8_t{};
+ if (next_minor != m_next_minor.end())
+ {
+ minor = next_minor->second++;
+ }
+ else
+ {
+ m_next_minor.emplace(driver, std::uint8_t{1});
+ }
- auto numbered = entry{
- .number = {.major = *driver_major, .minor = minor},
- .type = binding->posix_type,
- .name = published.name(),
- .device = device,
- };
+ numbered = entry{
+ .number = {.major = *driver_major, .minor = minor},
+ .type = binding->posix_type,
+ .name = published.name(),
+ .device = device,
+ };
- m_entries.push_back(numbered);
+ m_entries.push_back(numbered);
+ }
- // TODO: drop lock here
+ auto observers = kstd::vector<kstd::weak_ptr<device_number_registry_observer>>{};
+ {
+ auto guard = kstd::lock_guard{m_lock};
+ observers = m_observers;
+ }
- std::ranges::for_each(m_observers, [&](auto const & weak_observer) {
+ std::ranges::for_each(observers, [&](auto const & weak_observer) {
auto observer = weak_observer.lock();
if (observer)
{
diff --git a/kernel/kernel/filesystem/device_number_registry.hpp b/kernel/kernel/filesystem/device_number_registry.hpp
index 8ace3727..43f30f72 100644
--- a/kernel/kernel/filesystem/device_number_registry.hpp
+++ b/kernel/kernel/filesystem/device_number_registry.hpp
@@ -5,6 +5,7 @@
#include <kapi/devices.hpp>
#include <kapi/filesystem.hpp>
+#include <kapi/tracked_mutex.hpp>
#include <kstd/flat_map.hpp>
#include <kstd/memory.hpp>
@@ -85,6 +86,8 @@ namespace kernel::filesystem
auto try_number(kapi::capabilities::facet_id facet, kapi::devices::facet_registry::entry const & published) -> void;
+ mutable kapi::tracked_mutex m_lock{};
+
kstd::observer_ptr<kapi::devices::facet_registry> m_facet_registry;
mutable kstd::vector<entry> m_entries{};
kstd::flat_map<kapi::devices::driver const *, std::uint8_t> m_next_minor;
diff --git a/kernel/kernel/test_support/cio.hpp b/kernel/kernel/test_support/cio.hpp
index afe27e05..71564727 100644
--- a/kernel/kernel/test_support/cio.hpp
+++ b/kernel/kernel/test_support/cio.hpp
@@ -5,6 +5,7 @@
#include <kapi/cio.hpp>
+#include <mutex>
#include <string_view>
namespace kernel::tests::cio
@@ -22,6 +23,8 @@ namespace kernel::tests::cio
[[nodiscard]] auto log_buffer() noexcept -> kernel::tests::log_buffer &;
private:
+ mutable std::mutex m_lock{};
+
//! The log buffer of this device.
kernel::tests::log_buffer m_log_buffer{};
};
diff --git a/kernel/kernel/test_support/log_buffer.cpp b/kernel/kernel/test_support/log_buffer.cpp
index 04d875bd..9074e4f0 100644
--- a/kernel/kernel/test_support/log_buffer.cpp
+++ b/kernel/kernel/test_support/log_buffer.cpp
@@ -1,6 +1,7 @@
#include <kernel/test_support/log_buffer.hpp>
#include <algorithm>
+#include <mutex>
#include <string>
#include <vector>
@@ -9,24 +10,32 @@ namespace kernel::tests
auto log_buffer::append(std::string const & message) -> void
{
+ auto guard = std::lock_guard{m_lock};
+
m_messages.push_back(message);
}
auto log_buffer::clear() -> void
{
+ auto guard = std::lock_guard{m_lock};
+
m_messages.clear();
}
auto log_buffer::flat_messages() -> std::string
{
+ auto guard = std::lock_guard{m_lock};
+
return std::ranges::fold_left(m_messages, std::string{}, [](std::string accumulator, std::string const & message) {
accumulator += message;
return accumulator;
});
}
- auto log_buffer::messages() -> std::vector<std::string> const &
+ auto log_buffer::messages() -> std::vector<std::string>
{
+ auto guard = std::lock_guard{m_lock};
+
return m_messages;
}
diff --git a/kernel/kernel/test_support/log_buffer.hpp b/kernel/kernel/test_support/log_buffer.hpp
index 41d9a762..b1ba6e0a 100644
--- a/kernel/kernel/test_support/log_buffer.hpp
+++ b/kernel/kernel/test_support/log_buffer.hpp
@@ -1,6 +1,7 @@
#ifndef KERNEL_TEST_SUPPORT_LOG_BUFFER_HPP
#define KERNEL_TEST_SUPPORT_LOG_BUFFER_HPP
+#include <mutex>
#include <string>
#include <vector>
@@ -27,9 +28,11 @@ namespace kernel::tests
//! size.
//!
//! @return All messages in this buffer.
- auto messages() -> std::vector<std::string> const &;
+ auto messages() -> std::vector<std::string>;
private:
+ mutable std::mutex m_lock{};
+
std::vector<std::string> m_messages{};
};
} // namespace kernel::tests
diff --git a/kernel/kernel/test_support/output_device.cpp b/kernel/kernel/test_support/output_device.cpp
index 45fb4bc8..4fc601ec 100644
--- a/kernel/kernel/test_support/output_device.cpp
+++ b/kernel/kernel/test_support/output_device.cpp
@@ -4,6 +4,7 @@
#include <kapi/cio.hpp>
#include <iostream>
+#include <mutex>
#include <string>
#include <string_view>
@@ -12,6 +13,8 @@ namespace kernel::tests::cio
auto output_device::write(kapi::cio::output_stream stream, std::string_view text) -> void
{
+ auto guard = std::lock_guard{m_lock};
+
auto & standard_stream = stream == kapi::cio::output_stream::stdout ? std::cout : std::cerr;
standard_stream << text;
if (text != "\n")