diff options
Diffstat (limited to 'kapi')
| -rw-r--r-- | kapi/kapi/boot_modules/device.hpp | 10 | ||||
| -rw-r--r-- | kapi/kapi/capabilities/facet_id.hpp | 36 | ||||
| -rw-r--r-- | kapi/kapi/capabilities/interface_id.hpp | 34 | ||||
| -rw-r--r-- | kapi/kapi/devices.hpp | 47 | ||||
| -rw-r--r-- | kapi/kapi/devices/bus.hpp | 14 | ||||
| -rw-r--r-- | kapi/kapi/devices/bus_protocol.hpp | 4 | ||||
| -rw-r--r-- | kapi/kapi/devices/device.hpp | 64 | ||||
| -rw-r--r-- | kapi/kapi/devices/driver.hpp | 40 | ||||
| -rw-r--r-- | kapi/kapi/devices/facet_registry.hpp | 305 | ||||
| -rw-r--r-- | kapi/kapi/devices/interface_id.hpp | 15 | ||||
| -rw-r--r-- | kapi/kapi/devices/interface_registry.hpp | 299 | ||||
| -rw-r--r-- | kapi/kapi/filesystem.hpp | 2 | ||||
| -rw-r--r-- | kapi/kapi/filesystem/block_special_file.hpp | 4 | ||||
| -rw-r--r-- | kapi/kapi/filesystem/character_special_file.hpp | 4 | ||||
| -rw-r--r-- | kapi/kapi/filesystem/interface_id.hpp | 15 | ||||
| -rw-r--r-- | kapi/kapi/test_support/devices.hpp | 2 |
16 files changed, 438 insertions, 457 deletions
diff --git a/kapi/kapi/boot_modules/device.hpp b/kapi/kapi/boot_modules/device.hpp index a6aba9b0..74152306 100644 --- a/kapi/kapi/boot_modules/device.hpp +++ b/kapi/kapi/boot_modules/device.hpp @@ -14,13 +14,13 @@ namespace kapi::boot_modules //! @addtogroup kapi-boot_modules-kernel-defined //! @{ - //! The signature interface of a boot module device. + //! The signature facet of a boot module device. //! //! Boot module devices are "virtual" devices that get attached to the boot module bus. The purpose is to allow them //! to materialize as "real" devices, e.g. a ram disk, and have a driver bound to them. struct boot_module_signature { - constexpr auto static id = kapi::devices::interface_id{"boot_module_signature"}; + constexpr auto static id = kapi::capabilities::facet_id{"boot_module_signature"}; virtual ~boot_module_signature() = default; @@ -31,10 +31,10 @@ namespace kapi::boot_modules [[nodiscard]] auto virtual module() const -> kapi::boot_modules::module const & = 0; }; - //! The claim interface of a boot module driver. + //! The claim facet of a boot module driver. struct boot_module_claim { - constexpr auto static id = kapi::devices::interface_id{"boot_module_claim"}; + constexpr auto static id = kapi::capabilities::facet_id{"boot_module_claim"}; virtual ~boot_module_claim() = default; @@ -52,7 +52,7 @@ namespace kapi::boot_modules [[nodiscard]] auto module() const -> struct module const & override; protected: - auto query_interface(kapi::devices::interface_id interface) -> void * override; + auto query_facet(kapi::capabilities::facet_id facet) -> void * override; private: struct module m_module; diff --git a/kapi/kapi/capabilities/facet_id.hpp b/kapi/kapi/capabilities/facet_id.hpp new file mode 100644 index 00000000..0ceae747 --- /dev/null +++ b/kapi/kapi/capabilities/facet_id.hpp @@ -0,0 +1,36 @@ +#ifndef TEACHOS_KAPI_CAPABILITIES_FACET_ID_HPP +#define TEACHOS_KAPI_CAPABILITIES_FACET_ID_HPP + +// IWYU pragma: private + +#include <string_view> + +namespace kapi::capabilities +{ + + //! A tag to mark the presence of a given behavioral or data facet. + struct facet_id + { + //! Construct a new facet id. + //! + //! @param name The name of the facet. + constexpr explicit facet_id(std::string_view name) + : m_name{name} + {} + + //! Get the name of this facet. + [[nodiscard]] constexpr auto name() const noexcept -> std::string_view const & + { + return m_name; + } + + //! Check if this facet is equal to another one. + constexpr auto operator==(facet_id const &) const noexcept -> bool = default; + + private: + std::string_view m_name; + }; + +} // namespace kapi::capabilities + +#endif diff --git a/kapi/kapi/capabilities/interface_id.hpp b/kapi/kapi/capabilities/interface_id.hpp deleted file mode 100644 index 8e6870cc..00000000 --- a/kapi/kapi/capabilities/interface_id.hpp +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef TEACHOS_KAPI_CAPABILITIES_INTERFACE_ID_HPP -#define TEACHOS_KAPI_CAPABILITIES_INTERFACE_ID_HPP - -// IWYU pragma: private - -#include <string_view> - -namespace kapi::capabilities -{ - - //! A tag to mark that a given devices provides a specific device capability interface. - struct interface_id - { - //! Construct a new interface with a given name. - constexpr explicit interface_id(std::string_view name) - : m_name{name} - {} - - //! Get the name of this interface. - [[nodiscard]] constexpr auto name() const noexcept -> std::string_view const & - { - return m_name; - } - - //! Check if this interface is equal to another one. - constexpr auto operator==(interface_id const &) const noexcept -> bool = default; - - private: - std::string_view m_name; - }; - -} // namespace kapi::capabilities - -#endif diff --git a/kapi/kapi/devices.hpp b/kapi/kapi/devices.hpp index 51f5129e..59fcc568 100644 --- a/kapi/kapi/devices.hpp +++ b/kapi/kapi/devices.hpp @@ -1,16 +1,16 @@ #ifndef TEACHOS_KAPI_DEVICES_HPP #define TEACHOS_KAPI_DEVICES_HPP -#include <kapi/devices/bus.hpp> // IWYU pragma: export -#include <kapi/devices/bus_protocol.hpp> // IWYU pragma: export -#include <kapi/devices/cpu.hpp> // IWYU pragma: export -#include <kapi/devices/device.hpp> // IWYU pragma: export -#include <kapi/devices/device_registry.hpp> // IWYU pragma: export -#include <kapi/devices/driver.hpp> // IWYU pragma: export -#include <kapi/devices/driver_registry.hpp> // IWYU pragma: export -#include <kapi/devices/error.hpp> // IWYU pragma: export -#include <kapi/devices/interface_id.hpp> // IWYU pragma: export -#include <kapi/devices/interface_registry.hpp> // IWYU pragma: export +#include <kapi/capabilities/facet_id.hpp> // IWYU pragma: export +#include <kapi/devices/bus.hpp> // IWYU pragma: export +#include <kapi/devices/bus_protocol.hpp> // IWYU pragma: export +#include <kapi/devices/cpu.hpp> // IWYU pragma: export +#include <kapi/devices/device.hpp> // IWYU pragma: export +#include <kapi/devices/device_registry.hpp> // IWYU pragma: export +#include <kapi/devices/driver.hpp> // IWYU pragma: export +#include <kapi/devices/driver_registry.hpp> // IWYU pragma: export +#include <kapi/devices/error.hpp> // IWYU pragma: export +#include <kapi/devices/facet_registry.hpp> // IWYU pragma: export #include <kstd/memory.hpp> #include <kstd/result.hpp> @@ -34,28 +34,27 @@ namespace kapi::devices //! @return a shared pointer to the root bus. auto get_root_bus() -> kstd::shared_ptr<bus>; - //! Publish the fact that a given device implements a given interface. + //! Publish the fact that a device supports a specific facet. //! - //! @tparam Interface The interface type implemented by the given device. - //! @param device The device to publish the interface for. + //! @tparam Facet The facet type provided by the device. + //! @param device The device to publish the facet for. //! @param name A stable name for the device. - template<typename Interface> - auto publish_interface(kstd::shared_ptr<device> device, kstd::string name) -> kstd::result<void> + template<typename Facet> + auto publish_facet(kstd::shared_ptr<device> device, kstd::string name) -> kstd::result<void> { - return interface_registry::get().publish<Interface>(device, std::move(name)); + return facet_registry::get().publish<Facet>(device, std::move(name)); } - //! Publish the fact that a given device implements a given interface. + //! Publish the fact that a given device provides a given facet. //! - //! @tparam Interface The interface type implemented by the given device. - //! @param device The device to publish the interface for. + //! @tparam Facet The facet type provided by the given device. + //! @param device The device to publish the facet for. //! @param name A stable name for the device. - //! @param implementation The implementation of the interface for the device. - template<typename Interface> - auto publish_interface(kstd::shared_ptr<device> device, kstd::string name, Interface * implementation) - -> kstd::result<void> + //! @param implementation The implementation of the facet for the device. + template<typename Facet> + auto publish_facet(kstd::shared_ptr<device> device, kstd::string name, Facet * implementation) -> kstd::result<void> { - return interface_registry::get().publish(device, std::move(name), implementation); + return facet_registry::get().publish(device, std::move(name), implementation); } //! @} diff --git a/kapi/kapi/devices/bus.hpp b/kapi/kapi/devices/bus.hpp index 2a306031..6c42d1de 100644 --- a/kapi/kapi/devices/bus.hpp +++ b/kapi/kapi/devices/bus.hpp @@ -3,8 +3,8 @@ // IWYU pragma: private, include <kapi/devices.hpp> +#include <kapi/capabilities/facet_id.hpp> #include <kapi/devices/device.hpp> -#include <kapi/devices/interface_id.hpp> #include <kstd/memory.hpp> #include <kstd/print.hpp> @@ -23,7 +23,7 @@ namespace kapi::devices struct bus : device { //! The id of the bus facet. - constexpr auto static id = interface_id{"bus"}; + constexpr auto static id = kapi::capabilities::facet_id{"bus"}; //! Construct a bus with the given name. //! @@ -42,14 +42,14 @@ namespace kapi::devices //! @return A vector of all children attached to this bus. [[nodiscard]] auto children() const -> std::span<kstd::shared_ptr<device> const>; - //! Get this bus's protocol facet, if present. - //! - //! @return this bus's protocol facet if it has one, nullptr otherwise. - [[nodiscard]] virtual auto protocol() -> struct bus_protocol *; + // //! Get this bus's protocol facet, if present. + // //! + // //! @return this bus's protocol facet if it has one, nullptr otherwise. + // [[nodiscard]] virtual auto protocol() -> struct bus_protocol *; protected: //! All busses have the "bus" facet. - auto query_interface(interface_id interface) -> void * override; + auto query_facet(kapi::capabilities::facet_id facet) -> void * override; private: kstd::vector<kstd::shared_ptr<device>> m_devices; diff --git a/kapi/kapi/devices/bus_protocol.hpp b/kapi/kapi/devices/bus_protocol.hpp index 2e4e6993..cc1f2e5b 100644 --- a/kapi/kapi/devices/bus_protocol.hpp +++ b/kapi/kapi/devices/bus_protocol.hpp @@ -3,6 +3,7 @@ // IWYU pragma: private, include <kapi/devices.hpp> +#include <kapi/capabilities/facet_id.hpp> #include <kapi/devices/bus.hpp> #include <kapi/devices/device.hpp> #include <kapi/devices/driver.hpp> @@ -20,6 +21,9 @@ namespace kapi::devices //! it a pure behavioral mixin. struct bus_protocol { + //! The id of the bus protocol facet. + constexpr auto static id = kapi::capabilities::facet_id{"bus_protocol"}; + //! Allow safe destruction through base pointers. virtual ~bus_protocol() = default; diff --git a/kapi/kapi/devices/device.hpp b/kapi/kapi/devices/device.hpp index 50fc10b6..71856279 100644 --- a/kapi/kapi/devices/device.hpp +++ b/kapi/kapi/devices/device.hpp @@ -3,8 +3,8 @@ // IWYU pragma: private, include <kapi/devices.hpp> +#include <kapi/capabilities/facet_id.hpp> #include <kapi/devices/driver.hpp> -#include <kapi/devices/interface_id.hpp> #include <kstd/memory.hpp> #include <kstd/string.hpp> @@ -46,52 +46,52 @@ namespace kapi::devices //! Enable safe destruction through base pointers. virtual ~device() = default; - //! Get a given capability from this device, if it implements it. + //! Get a specific facet of this device, if it supports it. //! - //! @param interface The id of the desired interface. - //! @return An opaque pointer to the interface implementation if this device supports it, nullptr otherwise. - [[nodiscard]] auto as(interface_id interface) noexcept -> void *; + //! @param id The id of the desired facet. + //! @return An opaque pointer to the facet implementation if this device supports it, nullptr otherwise. + [[nodiscard]] auto facet(kapi::capabilities::facet_id id) noexcept -> void *; - //! Get a given capability from this device, if it implements it. + //! Get a specific facet of this device, if it supports it. //! - //! @param interface The id of the desired interface. - //! @return A opaque pointer to the interface implementation if this device supports it, nullptr otherwise. - [[nodiscard]] auto as(interface_id interface) const noexcept -> void const *; + //! @param id The id of the desired facet. + //! @return A opaque pointer to the facet implementation if this device supports it, nullptr otherwise. + [[nodiscard]] auto facet(kapi::capabilities::facet_id id) const noexcept -> void const *; - //! Get a given capability from this device, if it implements it. + //! Get a specific facet of this device, if it supports it. //! - //! @tparam Interface The id of the desired interface. - //! @return A typed pointer to the interface implementation if this device supports it, nullptr otherwise. - template<typename InterfaceType> - [[nodiscard]] auto as() -> InterfaceType * + //! @tparam FacetType The type of the desired facet. + //! @return A typed pointer to the facet implementation if this device supports it, nullptr otherwise. + template<typename FacetType> + [[nodiscard]] auto facet() -> FacetType * { - return static_cast<InterfaceType *>(as(InterfaceType::id)); + return static_cast<FacetType *>(facet(FacetType::id)); } - //! Get a given capability from this device, if it implements it. + //! Get a specific facet of this device, if it supports it. //! - //! @tparam Interface The id of the desired interface. - //! @return A typed pointer to the interface implementation if this device supports it, nullptr otherwise. - template<typename InterfaceType> - [[nodiscard]] auto as() const noexcept -> InterfaceType const * + //! @tparam FacetType The type of the desired facet. + //! @return A typed pointer to the facet implementation if this device supports it, nullptr otherwise. + template<typename FacetType> + [[nodiscard]] auto facet() const noexcept -> FacetType const * { - return static_cast<InterfaceType const *>(as(InterfaceType::id)); + return static_cast<FacetType const *>(facet(FacetType::id)); } - //! Check if this device implements a given capability interface. + //! Check if this device has a specific facet. //! - //! @param interface The id of the queried interface. - //! @return true iff. this device implements the given interface, false otherwise. - [[nodiscard]] auto is_a(interface_id interface) const noexcept -> bool; + //! @param id The id of the desired facet. + //! @return true iff. this device has the given facet, false otherwise. + [[nodiscard]] auto has_facet(kapi::capabilities::facet_id id) const noexcept -> bool; - //! Check if this device implements a given capability interface. + //! Check if this device has a specific facet. //! - //! @tparam Interface The id of the queried interface. - //! @return true iff. this device implements the given interface, false otherwise. - template<typename InterfaceType> - [[nodiscard]] auto is_a() const noexcept -> bool + //! @tparam FacetType The type of the desired facet. + //! @return true iff. this device has the given facet, false otherwise. + template<typename FacetType> + [[nodiscard]] auto has_facet() const noexcept -> bool { - return is_a(InterfaceType::id); + return has_facet(FacetType::id); } //! Get the name of the device. @@ -125,7 +125,7 @@ namespace kapi::devices auto set_driver_data(kstd::shared_ptr<void> data) -> void; protected: - auto virtual query_interface(interface_id interface) -> void *; + auto virtual query_facet(kapi::capabilities::facet_id facet) -> void *; private: //! Busses need to be able to register themselves as a device's parent. diff --git a/kapi/kapi/devices/driver.hpp b/kapi/kapi/devices/driver.hpp index a2c2e396..348e2841 100644 --- a/kapi/kapi/devices/driver.hpp +++ b/kapi/kapi/devices/driver.hpp @@ -3,7 +3,7 @@ // IWYU pragma: private, include <kapi/devices.hpp> -#include <kapi/devices/interface_id.hpp> +#include <kapi/capabilities/facet_id.hpp> #include <kstd/result.hpp> @@ -46,33 +46,33 @@ namespace kapi::devices //! @param device The device to release. virtual auto unbind(device & device) -> void = 0; - //! Retrieve this drivers implementation of a given capability interface. + //! Retrieve this drivers implementation of a given capability facet. //! - //! @return A pointer to this drivers implementation of the requested interface, nullptr if this driver does not - //! support the requested interface. - template<typename InterfaceType> - [[nodiscard]] auto as() -> InterfaceType * + //! @return A pointer to this drivers implementation of the requested facet, nullptr if this driver does not + //! support the requested facet. + template<typename FacetType> + [[nodiscard]] auto facet() -> FacetType * { - return static_cast<InterfaceType *>(query_interface(InterfaceType::id)); + return static_cast<FacetType *>(query_facet(FacetType::id)); } - //! Retrieve this drivers implementation of a given capability interface. + //! Retrieve this drivers implementation of a given capability facet. //! - //! @return A pointer to this drivers implementation of the requested interface, nullptr if this driver does not - //! support the requested interface. - template<typename InterfaceType> - [[nodiscard]] auto as() const -> InterfaceType const * + //! @return A pointer to this drivers implementation of the requested facet, nullptr if this driver does not + //! support the requested facet. + template<typename FacetType> + [[nodiscard]] auto facet() const -> FacetType const * { - return static_cast<InterfaceType *>(const_cast<driver *>(this)->query_interface(InterfaceType::id)); + return static_cast<FacetType *>(const_cast<driver *>(this)->query_facet(FacetType::id)); } - //! Check if this driver implements a given capability interface. + //! Check if this driver implements a given capability facet. //! - //! @return true iff. this driver implements the requested capability interface, false otherwise. - template<typename InterfaceType> - [[nodiscard]] auto is_a() const noexcept -> bool + //! @return true iff. this driver implements the requested capability facet, false otherwise. + template<typename FacetType> + [[nodiscard]] auto has_facet() const noexcept -> bool { - return query_interface(InterfaceType::id) != nullptr; + return query_facet(FacetType::id) != nullptr; } //! Get the major number associated with this driver, if any. @@ -86,8 +86,8 @@ namespace kapi::devices [[nodiscard]] virtual auto name() const noexcept -> std::string_view = 0; protected: - //! Return a pointer to the implementation of the given interface if this driver supports it. - virtual auto query_interface(interface_id interface) -> void *; + //! Return a pointer to the implementation of the given facet if this driver supports it. + virtual auto query_facet(kapi::capabilities::facet_id facet) -> void *; }; //! @} diff --git a/kapi/kapi/devices/facet_registry.hpp b/kapi/kapi/devices/facet_registry.hpp new file mode 100644 index 00000000..82bb304b --- /dev/null +++ b/kapi/kapi/devices/facet_registry.hpp @@ -0,0 +1,305 @@ +#ifndef TEACHOS_KAPI_DEVICES_FACET_REGISTRY_HPP +#define TEACHOS_KAPI_DEVICES_FACET_REGISTRY_HPP + +// IWYU pragma: private, include <kapi/devices.hpp> + +#include <kapi/capabilities/facet_id.hpp> +#include <kapi/devices/device.hpp> + +#include <kstd/memory.hpp> +#include <kstd/result.hpp> +#include <kstd/string.hpp> +#include <kstd/system_error.hpp> +#include <kstd/vector.hpp> + +#include <string_view> +#include <utility> + +namespace kapi::devices +{ + + //! @addtogroup kapi-devices-kernel-defined + //! @{ + + struct facet_registry_observer; + + //! The device facet registry. + //! + //! The purpose of the facet registry is to allow system components, for example drivers, to publish capabilities in + //! terms of facets for devices. An example for such a capability are block devices. A driver for a given type of + //! block devices may choose too publish a the "block" facet on a bound device. Other subsystems may then query if a + //! given device exposes the "block" facet or get all devices implementing that capability. + //! + //! @note The device registry holds only non-owning references to the published devices. If a device dies after + //! publishing, without being unpublished, the registry accessors will prevent a dead handle from being exported. + //! + //! @see kernel::drivers::storage::ram_disk + //! @see kernel::filesystem::device_inode + //! @see kernel::filesystem::device_number_registry + struct facet_registry + { + //! A registry entry. + //! + //! Registry entries are used to record published facets on devices. + struct entry + { + //! Create a new registry entry, associating a device with a name and facet + //! + //! @param device The device to record the published facet for. + //! @param name The stable name to associate with this facet record. + //! @param facet The id of the implemented facet. + //! @param implementation A pointer to the actual implementation of the facet for the given device. + constexpr entry(kstd::shared_ptr<struct device> device, kstd::string name, kapi::capabilities::facet_id facet, + void * implementation) + : m_device{device} + , m_name{name} + , m_id{facet} + , m_facet{implementation} + {} + + //! Get a handle to the device of this entry. + //! + //! @return A non-null pointer to the device if it is still alive, a null + //! pointer otherwise. + [[nodiscard]] constexpr auto device() const noexcept -> kstd::shared_ptr<device> + { + return m_device.lock(); + } + + //! Get the name of this entry. + //! + //! @return The name associated with this entry. + [[nodiscard]] constexpr auto name() const noexcept -> kstd::string const & + { + return m_name; + } + + //! Get the id of the facet of the device-facet-implementation tuple described by this entry. + //! + //! @return The facet id of this entry. + [[nodiscard]] constexpr auto id() const noexcept -> kapi::capabilities::facet_id + { + return m_id; + } + + //! Get the facet of the device-facet-implementation tuple described by this entry. + //! + //! @return An untyped pointer to the facet implementation. + [[nodiscard]] constexpr auto untyped_facet() const noexcept -> void * + { + return m_facet; + } + + //! Get the facet of the device-facet-implementation tuple described by this entry. + //! + //! @return A typed pointer to the facet if the facet id matches, nullptr otherwise. + template<typename FacetType> + [[nodiscard]] constexpr auto facet() noexcept -> FacetType * + { + if (m_id == FacetType::id) + { + return static_cast<FacetType *>(untyped_facet()); + } + return nullptr; + } + + //! Get the facet of the device-facet-implementation tuple described by this entry. + //! + //! @return A typed pointer to the facet if the facet id matches, nullptr otherwise. + template<typename FacetType> + [[nodiscard]] constexpr auto facet() const noexcept -> FacetType const * + { + if (m_id == FacetType::id) + { + return static_cast<FacetType const *>(untyped_facet()); + } + return nullptr; + } + + private: + kstd::weak_ptr<struct device> m_device; + kstd::string m_name; + kapi::capabilities::facet_id m_id; + void * m_facet; + }; + + //! Construct an empty facet registry. + facet_registry() = default; + + //! Initialize the system global singleton. + //! + //! @warning This function will panic if the global singleton has already been + //! initialized. + auto static init() -> void; + + //! Get the system global singleton. + //! + //! @warning This function will panic if the global singleton has not been + //! initialized. + auto static get() -> facet_registry &; + + //! Publish the fact that a given device has a given facet. + //! + //! Each published device-facet tuple must be associated with a unique stable name, to allow unique lookup via the + //! stable name. + //! + //! This overload is designed for devices that know about the existence of the given facet on themselves. + //! + //! @tparam FacetType The facet type supported by the given device. + //! @param device The device to publish the facet for. + //! @param name A stable name for the device. + template<typename FacetType> + auto publish(kstd::shared_ptr<device> device, kstd::string name) -> kstd::result<void> + { + if (!device) + { + return kstd::failure(make_error_code(kstd::errc::invalid_argument)); + } + + return do_publish(device, std::move(name), FacetType::id, device->facet<FacetType>()); + } + + //! Publish the fact that a given device has a given facet. + //! + //! Each published device-facet tuple must be associated with a unique stable name, to allow unique lookup via the + //! stable name. + //! + //! This overload is designed to externally assign facets to a device. + //! + //! @tparam FacetType The facet type supported by the given device. + //! @param device The device to publish the facet for. + //! @param name A stable name for the device. + //! @param facet The implementation of the facet for the device. + template<typename FacetType> + auto publish(kstd::shared_ptr<device> device, kstd::string name, FacetType * facet) -> kstd::result<void> + { + return do_publish(device, std::move(name), FacetType::id, facet); + } + + //! Withdraw a previously published facets for a device. + //! + //! @param device The device to withdraw the facet for. + //! @param id The id of the facet to withdraw for the device. + auto withdraw(device const & device, kapi::capabilities::facet_id id) -> void; + + //! Withdraw every facet previously published for a device. + //! + //! @param device The device to withdraw all facets for. + auto withdraw_all_for(device const & device) -> void; + + //! Get all devices supporting a given facet. + //! + //! @param id The id of the facet for which to get the devices supporting it. + [[nodiscard]] auto all(kapi::capabilities::facet_id id) const -> kstd::vector<entry>; + + //! Attempt to resolve a facet for a device by name. + //! + //! @param id The id of the facet to look for. + //! @param name The stable name of the device. + [[nodiscard]] auto resolve(kapi::capabilities::facet_id id, std::string_view name) -> void *; + + //! Attempt to resolve a facet for a device. + //! + //! @param id The id of the facet to look for. + //! @param device The device. + [[nodiscard]] auto resolve(kapi::capabilities::facet_id id, device & device) -> void *; + + //! Attempt to resolve a facet for a device by name. + //! + //! @tparam FacetType The facet to look for. + //! @param name The stable name of the device. + template<typename FacetType> + [[nodiscard]] auto resolve(std::string_view name) -> FacetType * + { + return static_cast<FacetType *>(resolve(FacetType::id, name)); + } + + //! Attempt to resolve a facet for a device. + //! + //! @tparam FacetType The facet to look for. + //! @param device The device. + template<typename FacetType> + [[nodiscard]] auto resolve(device & device) -> FacetType * + { + return static_cast<FacetType *>(resolve(FacetType::id, device)); + } + + //! Subscribe to facet publish/withdraw notifications. + //! + //! Observers subscribed through this function are held through non-owning pointers. It is safe of an observer + //! subscribed through this function to be destroyed without being unsubscribed. + //! + //! @param observer The observer to subscribe. + auto subscribe(kstd::weak_ptr<facet_registry_observer> observer) -> void; + + //! Subscribe to facet publish/withdraw notifications. + //! + //! @warning The registry has no way of detecting liveness of observers subscribed through this function. This + //! function is intended to be used solely with long-lived observers. If an observer subscribed through this + //! function is destroyed before being unregistered, the behavior of any triggered notifications becomes undefined. + //! + //! @param observer The observer to subscribe. + auto subscribe(facet_registry_observer & observer) -> void; + + //! Cancel a subscription previously made for a given observer. + //! + //! @param observer The observer to unsubscribe. + auto unsubscribe(facet_registry_observer & observer) -> void; + + private: + //! Publish the fact that a device has a specific facet + //! + //! @param device The device to publish the facet for. + //! @param name A stable name for the device. + //! @param id The id of the facet to be published for the device. + //! @param facet The facet of the device. + auto do_publish(kstd::shared_ptr<device> device, kstd::string name, kapi::capabilities::facet_id id, void * facet) + -> kstd::result<void>; + + //! Notify all subscribed observers about a new facet having been published for a device. + //! + //! @param id The id of the published facet. + //! @param published The entry representing the published device-facet combination. + auto do_notify_published(kapi::capabilities::facet_id id, entry const & published) -> void; + + //! Notify all subscribed observers that a facet was withdrawn for a device. + //! + //! @param id The id of the withdrawn device. + //! @param device The device. + auto do_notify_withdrawn(kapi::capabilities::facet_id id, device const & device) -> void; + + kstd::vector<entry> m_entries; + kstd::vector<kstd::weak_ptr<facet_registry_observer>> m_observers; + kstd::vector<facet_registry_observer *> m_static_observers; + }; + + //! @} + + //! @addtogroup kapi-devices + //! @{ + + //! The facet for types interested in observing facet transaction on an facet registry. + struct facet_registry_observer + { + //! Enable correct destruction through base pointers. + virtual ~facet_registry_observer() = default; + + //! Called after an facet has been published for a device. + //! + //! @param facet The facet id of the published facet. + //! @param published The published entry. + virtual auto on_facet_published(kapi::capabilities::facet_id facet, facet_registry::entry const & published) + -> void = 0; + + //! Called after an facet has been withdrawn. + //! + //! @param facet The facet that was withdrawn. + //! @param device The device for which the facet was withdrawn. + virtual auto on_facet_withdrawn(kapi::capabilities::facet_id facet, device & device) -> void = 0; + }; + + //! @} + +} // namespace kapi::devices + +#endif diff --git a/kapi/kapi/devices/interface_id.hpp b/kapi/kapi/devices/interface_id.hpp deleted file mode 100644 index 0698d2fd..00000000 --- a/kapi/kapi/devices/interface_id.hpp +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef TEACHOS_KAPI_DEVICES_INTERFACE_ID_HPP -#define TEACHOS_KAPI_DEVICES_INTERFACE_ID_HPP - -// IWYU pragma: private - -#include <kapi/capabilities/interface_id.hpp> - -namespace kapi::devices -{ - - using interface_id = kapi::capabilities::interface_id; - -} - -#endif diff --git a/kapi/kapi/devices/interface_registry.hpp b/kapi/kapi/devices/interface_registry.hpp deleted file mode 100644 index e0e70654..00000000 --- a/kapi/kapi/devices/interface_registry.hpp +++ /dev/null @@ -1,299 +0,0 @@ -#ifndef TEACHOS_KAPI_DEVICES_INTERFACE_REGISTRY_HPP -#define TEACHOS_KAPI_DEVICES_INTERFACE_REGISTRY_HPP - -// IWYU pragma: private, include <kapi/devices.hpp> - -#include <kapi/devices/device.hpp> -#include <kapi/devices/interface_id.hpp> - -#include <kstd/memory.hpp> -#include <kstd/result.hpp> -#include <kstd/string.hpp> -#include <kstd/system_error.hpp> -#include <kstd/vector.hpp> - -#include <string_view> -#include <utility> - -namespace kapi::devices -{ - - //! @addtogroup kapi-devices-kernel-defined - //! @{ - - struct interface_registry_observer; - - //! The device capability interface registry. - //! - //! The purpose of the interface registry is to allow system components, for - //! example drivers, to plush interfaces/capabilities for devices. An example - //! for such a capability are block devices. A driver for a given type of block - //! devices may choose too publish a the "block" capability on a bound device. - //! Other subsystems may then query if a given device exposes the "block" - //! capability or get all devices implementing that capability. - //! - //! @note The device registry holds only non-owning references to the published - //! devices. If a device dies after publishing, without being unpublished, the - //! registry accessors will prevent a dead handle from being exported. - //! - //! @see kernel::drivers::storage::ram_disk - //! @see kernel::filesystem::device_inode - //! @see kernel::filesystem::device_number_registry - struct interface_registry - { - //! A registry entry. - //! - //! Registry entries are used to record published interfaces on devices. - struct entry - { - //! Create a new registry entry, associating a device with a name, - //! interface, and interface implementation. - //! - //! @param device The device to record the published interface for. - //! @param name The stable name to associate with this interface record. - //! @param interface The id of the implemented interface. - //! @param implementation A pointer to the actual implementation of the - //! interface for the given device. - constexpr entry(kstd::shared_ptr<struct device> device, kstd::string name, interface_id interface, - void * implementation) - : m_device{device} - , m_name{name} - , m_interface{interface} - , m_implementation{implementation} - {} - - //! Get a handle to the device of this entry. - //! - //! @return A non-null pointer to the device if it is still alive, a null - //! pointer otherwise. - [[nodiscard]] constexpr auto device() const noexcept -> kstd::shared_ptr<device> - { - return m_device.lock(); - } - - //! Get the name of this entry. - //! - //! @return The name associated with this entry. - [[nodiscard]] constexpr auto name() const noexcept -> kstd::string const & - { - return m_name; - } - - //! Get the interface id associated with this entry. - //! - //! @return The interface id of this entry. - [[nodiscard]] constexpr auto interface() const noexcept -> interface_id - { - return m_interface; - } - - //! Get the interface implementation associated with this entry. - //! - //! @return An untyped pointer to the interface implementation. - [[nodiscard]] constexpr auto implementation() const noexcept -> void * - { - return m_implementation; - } - - //! Get the interface implementation associated with this entry. - //! - //! @return A typed pointer to the implementation if the interface type - //! matches, nullptr otherwise. - template<typename Interface> - [[nodiscard]] constexpr auto as() noexcept -> Interface * - { - if (m_interface == Interface::id) - { - return static_cast<Interface *>(m_implementation); - } - return nullptr; - } - - //! Get the interface implementation associated with this entry. - //! - //! @return A typed pointer to the implementation if the interface type - //! matches, nullptr otherwise. - template<typename Interface> - [[nodiscard]] constexpr auto as() const noexcept -> Interface const * - { - if (m_interface == Interface::id) - { - return static_cast<Interface const *>(m_implementation); - } - return nullptr; - } - - private: - kstd::weak_ptr<struct device> m_device; - kstd::string m_name; - interface_id m_interface; - void * m_implementation; - }; - - //! Construct an empty interface registry. - interface_registry() = default; - - //! Initialize the system global singleton. - //! - //! @warning This function will panic if the global singleton has already been - //! initialized. - auto static init() -> void; - - //! Get the system global singleton. - //! - //! @warning This function will panic if the global singleton has not been - //! initialized. - auto static get() -> interface_registry &; - - //! Publish the fact that a given device implements a given interface. - //! - //! @tparam Interface The interface type implemented by the given device. - //! @param device The device to publish the interface for. - //! @param name A stable name for the device. - template<typename Interface> - auto publish(kstd::shared_ptr<device> device, kstd::string name) -> kstd::result<void> - { - if (!device) - { - return kstd::failure(make_error_code(kstd::errc::invalid_argument)); - } - - return do_publish(device, std::move(name), Interface::id, device->as<Interface>()); - } - - //! Publish the fact that a given device implements a given interface. - //! - //! @tparam Interface The interface type implemented by the given device. - //! @param device The device to publish the interface for. - //! @param name A stable name for the device. - //! @param implementation The implementation of the interface for the device. - template<typename Interface> - auto publish(kstd::shared_ptr<device> device, kstd::string name, Interface * implementation) -> kstd::result<void> - { - return do_publish(device, std::move(name), Interface::id, implementation); - } - - //! Withdraw a previously published inteface for a given device. - //! - //! @param device The device to withdraw the interface for. - //! @param interface The interface to withdraw for the given device. - auto withdraw(device const & device, interface_id interface) -> void; - - //! Withdraw every interface previously published for a given device. - //! - //! @param device The device to withdraw all interfaces for. - auto withdraw_all_for(device const & device) -> void; - - //! Get all devices implementing a given interface. - //! - //! @param interface The interface for which to get the implementing devices. - [[nodiscard]] auto all(interface_id interface) const -> kstd::vector<entry>; - - //! Attempt to resolve a given device, by name, to a given interface - //! implementation - //! - //! @param interface The interface to look for. - //! @param name The stable name of the device to look for. - [[nodiscard]] auto resolve(interface_id interface, std::string_view name) -> void *; - - //! Attempt to resolve a given device to a given interface implementation - //! - //! @param interface The interface to look for. - //! @param device The device to look for. - [[nodiscard]] auto resolve(interface_id interface, device & device) -> void *; - - //! Attempt to resolve a given device, by name, to a given interface - //! implementation - //! - //! @tparam Interface The interface to look for. - //! @param name The stable name of the device to look for. - template<typename Interface> - [[nodiscard]] auto resolve(std::string_view name) -> Interface * - { - return static_cast<Interface *>(resolve(Interface::id, name)); - } - - //! Attempt to resolve a given device to a given interface implementation - //! - //! @tparam Interface The interface to look for. - //! @param device The device to look for. - template<typename Interface> - [[nodiscard]] auto resolve(device & device) -> Interface * - { - return static_cast<Interface *>(resolve(Interface::id, device)); - } - - //! Subscribe to interface publish/withdraw notifications. - //! - //! Observers subscribed through this function are held through non-owning - //! pointers. It is safe of an observer subscribed through this function to be - //! destroyed without being unsubscribed. - //! - //! @param observer The observer to subscribe. - auto subscribe(kstd::weak_ptr<interface_registry_observer> observer) -> void; - - //! Subscribe to interface publish/withdraw notifications. - //! - //! @warning The registry has no way of detecting liveness of observers - //! subscribed through this function. This function is intended to be used - //! solely with long-lived observers. If an observer subscribed through this - //! function is destroyed before being unregistered, the behavior of any - //! triggered notifications becomes undefined. - //! - //! @param observer The observer to subscribe. - auto subscribe(interface_registry_observer & observer) -> void; - - //! Cancel a subscription previously made for a given observer. - //! - //! @param observer The observer to unsubscribe. - auto unsubscribe(interface_registry_observer & observer) -> void; - - private: - //! Publish the fact that a given device implements a given interface. - //! - //! @param device The device to publish the interface for. - //! @param name A stable name for the device. - //! @param interface The capability interface to be published for the device. - //! @param implementation The implementation of the interface for the device. - auto do_publish(kstd::shared_ptr<device> device, kstd::string name, interface_id interface, void * implementation) - -> kstd::result<void>; - - auto do_notify_published(interface_id interface, entry const & published) -> void; - - auto do_notify_withdrawn(interface_id interface, device const & device) -> void; - - kstd::vector<entry> m_entries; - kstd::vector<kstd::weak_ptr<interface_registry_observer>> m_observers; - kstd::vector<interface_registry_observer *> m_static_observers; - }; - - //! @} - - //! @addtogroup kapi-devices - //! @{ - - //! The interface for types interested in observing interface transaction on an interface registry. - struct interface_registry_observer - { - //! Enable correct destruction through base pointers. - virtual ~interface_registry_observer() = default; - - //! Called after an interface has been published for a device. - //! - //! @param interface The interface id of the published interface. - //! @param published The published entry. - virtual auto on_interface_published(interface_id interface, interface_registry::entry const & published) - -> void = 0; - - //! Called after an interface has been withdrawn. - //! - //! @param interface The interface that was withdrawn. - //! @param device The device for which the interface was withdrawn. - virtual auto on_interface_withdrawn(interface_id interface, device & device) -> void = 0; - }; - - //! @} - -} // namespace kapi::devices - -#endif diff --git a/kapi/kapi/filesystem.hpp b/kapi/kapi/filesystem.hpp index 52bc22bc..da72f523 100644 --- a/kapi/kapi/filesystem.hpp +++ b/kapi/kapi/filesystem.hpp @@ -1,12 +1,12 @@ #ifndef TEACHOS_KAPI_FILESYSTEM_HPP #define TEACHOS_KAPI_FILESYSTEM_HPP +#include <kapi/capabilities/facet_id.hpp> // IWYU pragma: export #include <kapi/filesystem/block_special_file.hpp> // IWYU pragma: export #include <kapi/filesystem/character_special_file.hpp> // IWYU pragma: export #include <kapi/filesystem/device_number.hpp> // IWYU pragma: export #include <kapi/filesystem/file_status.hpp> // IWYU pragma: export #include <kapi/filesystem/file_type.hpp> // IWYU pragma: export -#include <kapi/filesystem/interface_id.hpp> // IWYU pragma: export #include <kstd/result.hpp> #include <kstd/system_error.hpp> diff --git a/kapi/kapi/filesystem/block_special_file.hpp b/kapi/kapi/filesystem/block_special_file.hpp index c7f3ac51..0e44fe35 100644 --- a/kapi/kapi/filesystem/block_special_file.hpp +++ b/kapi/kapi/filesystem/block_special_file.hpp @@ -3,7 +3,7 @@ // IWYU pragma: private, include <kapi/filesystem.hpp> -#include <kapi/filesystem/interface_id.hpp> +#include <kapi/capabilities/facet_id.hpp> #include <kstd/result.hpp> #include <kstd/units.hpp> @@ -15,7 +15,7 @@ namespace kapi::filesystem struct block_special_file { - constexpr auto static id = interface_id{"block"}; + constexpr auto static id = kapi::capabilities::facet_id{"block"}; //! Virtual destructor to enable clean deletes through base pointers. virtual ~block_special_file() = default; diff --git a/kapi/kapi/filesystem/character_special_file.hpp b/kapi/kapi/filesystem/character_special_file.hpp index 7ce5fdaa..328bbef9 100644 --- a/kapi/kapi/filesystem/character_special_file.hpp +++ b/kapi/kapi/filesystem/character_special_file.hpp @@ -3,7 +3,7 @@ // IWYU pragma: private, include <kapi/filesystem.hpp> -#include <kapi/filesystem/interface_id.hpp> +#include <kapi/capabilities/facet_id.hpp> #include <kstd/result.hpp> #include <kstd/units.hpp> @@ -16,7 +16,7 @@ namespace kapi::filesystem struct character_special_file { - constexpr auto static id = interface_id{"char"}; + constexpr auto static id = kapi::capabilities::facet_id{"char"}; //! Virtual destructor to enable clean deletes through base pointers. virtual ~character_special_file() = default; diff --git a/kapi/kapi/filesystem/interface_id.hpp b/kapi/kapi/filesystem/interface_id.hpp deleted file mode 100644 index 18e0fbc4..00000000 --- a/kapi/kapi/filesystem/interface_id.hpp +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef TEACHOS_KAPI_FILESYSTEM_INTERFACE_ID_HPP -#define TEACHOS_KAPI_FILESYSTEM_INTERFACE_ID_HPP - -// IWYU pragma: private - -#include <kapi/capabilities/interface_id.hpp> - -namespace kapi::filesystem -{ - - using interface_id = kapi::capabilities::interface_id; - -} - -#endif diff --git a/kapi/kapi/test_support/devices.hpp b/kapi/kapi/test_support/devices.hpp index 3cb1cd8b..623bb87a 100644 --- a/kapi/kapi/test_support/devices.hpp +++ b/kapi/kapi/test_support/devices.hpp @@ -4,7 +4,7 @@ namespace kapi::test_support::devices { auto deinit() -> void; - auto deinit_interface_registry() -> void; + auto deinit_facet_registry() -> void; auto deinit_driver_registry() -> void; auto deinit_device_registry() -> void; } // namespace kapi::test_support::devices |
