From 4b916f139a9b3ccac76610f5e4da1fe0bb4dfd51 Mon Sep 17 00:00:00 2001 From: Brad Bishop Date: Tue, 23 May 2017 18:06:38 -0400 Subject: Add property watches Property watches cache DBus property values given an externally supplied index of property names and paths, in an externally supplied storage location. Change-Id: I155081da88c3ab0e4f6a13b012fc9719203b1888 Signed-off-by: Brad Bishop --- src/propertywatchimpl.hpp | 183 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 183 insertions(+) create mode 100644 src/propertywatchimpl.hpp (limited to 'src/propertywatchimpl.hpp') diff --git a/src/propertywatchimpl.hpp b/src/propertywatchimpl.hpp new file mode 100644 index 0000000..46799ed --- /dev/null +++ b/src/propertywatchimpl.hpp @@ -0,0 +1,183 @@ +#pragma once + +#include +#include +#include +#include "data_types.hpp" +#include "propertywatch.hpp" + +namespace phosphor +{ +namespace dbus +{ +namespace monitoring +{ + +static constexpr auto MAPPER_BUSNAME = "xyz.openbmc_project.ObjectMapper"; +static constexpr auto MAPPER_PATH = "/xyz/openbmc_project/object_mapper"; +static constexpr auto MAPPER_INTERFACE = + "xyz.openbmc_project.ObjectMapper"; + +using MappedPropertyIndex = + RefKeyMap>>; + +MappedPropertyIndex convert(const PropertyIndex& index); + +template +void PropertyWatch::start() +{ + if (alreadyRan) + { + return; + } + else + { + alreadyRan = true; + } + + // The index has a flat layout which is not optimal here. Nest + // properties in a map of interface names in a map of object paths. + auto mapped = convert(index); + + for (const auto& m : mapped) + { + const auto& path = m.first.get(); + const auto& interfaces = m.second; + + // Watch for new interfaces on this path. + DBusInterfaceType::addMatch( + sdbusplus::bus::match::rules::interfacesAdded(path), + [this](auto & msg) + // *INDENT-OFF* + { + this->interfacesAdded(msg); + }); + // *INDENT-ON* + + // Do a query to populate the cache. Start with a mapper query. + // The specific services are queried below. + const std::vector queryInterfaces; // all interfaces + auto mapperResp = + DBusInterfaceType::template callMethodAndRead( + MAPPER_BUSNAME, + MAPPER_PATH, + MAPPER_INTERFACE, + "GetObject", + path, + queryInterfaces); + + for (const auto& i : interfaces) + { + const auto& interface = i.first.get(); + + // Watch for property changes on this interface. + DBusInterfaceType::addMatch( + sdbusplus::bus::match::rules::propertiesChanged( + path, interface), + [this](auto & msg) + // *INDENT-OFF* + { + std::string interface; + msg.read(interface); + auto path = msg.get_path(); + this->propertiesChanged(msg, path, interface); + }); + // *INDENT-ON* + + // The mapper response is a busname:[interfaces] map. Look for + // each interface in the index and if found, query the service and + // populate the cache entries for the interface. + for (const auto& mr : mapperResp) + { + const auto& busName = mr.first; + const auto& mapperInterfaces = mr.second; + if (mapperInterfaces.end() == std::find( + mapperInterfaces.begin(), + mapperInterfaces.end(), + interface)) + { + // This interface isn't being watched. + continue; + } + + // Delegate type specific property updates to subclasses. + updateProperties(busName, path, interface); + } + } + } +} + +template +void PropertyWatchOfType::updateProperties( + const std::string& busName, + const std::string& path, + const std::string& interface) +{ + auto properties = + DBusInterfaceType::template callMethodAndRead>( + busName.c_str(), + path.c_str(), + "org.freedesktop.DBus.Properties", + "GetAll", + interface); + propertiesChanged(path, interface, properties); +} + +template +void PropertyWatchOfType::propertiesChanged( + const std::string& path, + const std::string& interface, + const PropertiesChanged& properties) +{ + // Update the cache for any watched properties. + for (const auto& p : properties) + { + auto key = std::make_tuple(path, interface, p.first); + auto item = this->index.find(key); + if (item == this->index.end()) + { + // This property isn't being watched. + continue; + } + + std::get<2>(item->second).get() = p.second.template get(); + } +} + +template +void PropertyWatchOfType::propertiesChanged( + sdbusplus::message::message& msg, + const std::string& path, + const std::string& interface) +{ + PropertiesChanged properties; + msg.read(properties); + propertiesChanged(path, interface, properties); +} + +template +void PropertyWatchOfType::interfacesAdded( + const std::string& path, + const InterfacesAdded& interfaces) +{ + for (const auto& i : interfaces) + { + propertiesChanged(path, i.first, i.second); + } +} + +template +void PropertyWatchOfType::interfacesAdded( + sdbusplus::message::message& msg) +{ + sdbusplus::message::object_path path; + InterfacesAdded interfaces; + msg.read(path, interfaces); + interfacesAdded(path, interfaces); +} + +} // namespace monitoring +} // namespace dbus +} // namespace phosphor -- cgit v1.2.1