diff options
| author | Felix Morgner <felix.morgner@ost.ch> | 2026-07-26 21:46:37 +0200 |
|---|---|---|
| committer | Felix Morgner <felix.morgner@ost.ch> | 2026-07-26 21:46:37 +0200 |
| commit | 4b28e4626e744ac9b779a680f8e9647014956dda (patch) | |
| tree | 9b5203e083ed27091c70d60e3cdf9284af680c81 | |
| parent | e7cb0a5dab291d453fa34c5d1250d85e82478ecf (diff) | |
| download | kernel-4b28e4626e744ac9b779a680f8e9647014956dda.tar.xz kernel-4b28e4626e744ac9b779a680f8e9647014956dda.zip | |
kapi/devices: implement locking discipline
| -rw-r--r-- | .vscode/settings.json | 4 | ||||
| -rw-r--r-- | cmake/Modules/BuildHostTests.cmake | 1 | ||||
| -rw-r--r-- | kapi/kapi/devices/bus.hpp | 3 | ||||
| -rw-r--r-- | kapi/kapi/devices/device_registry.hpp | 3 | ||||
| -rw-r--r-- | kapi/kapi/devices/facet_registry.hpp | 3 | ||||
| -rw-r--r-- | kernel/kapi/devices/bus.cpp | 38 | ||||
| -rw-r--r-- | kernel/kapi/devices/bus.stress.cpp | 76 | ||||
| -rw-r--r-- | kernel/kapi/devices/device_registry.cpp | 96 | ||||
| -rw-r--r-- | kernel/kapi/devices/facet_registry.cpp | 130 | ||||
| -rw-r--r-- | kernel/kernel/filesystem/device_number_registry.cpp | 88 | ||||
| -rw-r--r-- | kernel/kernel/filesystem/device_number_registry.hpp | 3 | ||||
| -rw-r--r-- | kernel/kernel/test_support/cio.hpp | 3 | ||||
| -rw-r--r-- | kernel/kernel/test_support/log_buffer.cpp | 11 | ||||
| -rw-r--r-- | kernel/kernel/test_support/log_buffer.hpp | 5 | ||||
| -rw-r--r-- | kernel/kernel/test_support/output_device.cpp | 3 |
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") |
