aboutsummaryrefslogtreecommitdiff
path: root/kapi
diff options
context:
space:
mode:
Diffstat (limited to 'kapi')
-rw-r--r--kapi/kapi/devices/interface_registry.hpp145
1 files changed, 140 insertions, 5 deletions
diff --git a/kapi/kapi/devices/interface_registry.hpp b/kapi/kapi/devices/interface_registry.hpp
index 25a8b90f..e0e70654 100644
--- a/kapi/kapi/devices/interface_registry.hpp
+++ b/kapi/kapi/devices/interface_registry.hpp
@@ -18,10 +18,42 @@
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}
@@ -30,36 +62,65 @@ namespace kapi::devices
, 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 *
{
- return static_cast<Interface *>(m_implementation);
+ 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 *
{
- return static_cast<Interface const *>(m_implementation);
+ if (m_interface == Interface::id)
+ {
+ return static_cast<Interface const *>(m_implementation);
+ }
+ return nullptr;
}
private:
@@ -69,10 +130,19 @@ namespace kapi::devices
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.
@@ -107,14 +177,20 @@ namespace kapi::devices
//!
//! @param device The device to withdraw the interface for.
//! @param interface The interface to withdraw for the given device.
- auto unpublish(device const & device, interface_id interface) -> void;
+ 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
+ //! 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.
@@ -126,7 +202,8 @@ namespace kapi::devices
//! @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
+ //! 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.
@@ -146,6 +223,31 @@ namespace kapi::devices
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.
//!
@@ -156,9 +258,42 @@ namespace kapi::devices
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