138a93a8aSMatthew Barth #pragma once 238a93a8aSMatthew Barth 338a93a8aSMatthew Barth #include "types.hpp" 4336f18a5SMatthew Barth #include "sdbusplus.hpp" 538a93a8aSMatthew Barth #include <phosphor-logging/log.hpp> 638a93a8aSMatthew Barth 738a93a8aSMatthew Barth namespace phosphor 838a93a8aSMatthew Barth { 938a93a8aSMatthew Barth namespace fan 1038a93a8aSMatthew Barth { 1138a93a8aSMatthew Barth namespace control 1238a93a8aSMatthew Barth { 1338a93a8aSMatthew Barth class Zone; 1438a93a8aSMatthew Barth 15336f18a5SMatthew Barth using namespace phosphor::fan; 165a302576SMatthew Barth using namespace sdbusplus::bus::match; 1738a93a8aSMatthew Barth using namespace phosphor::logging; 18336f18a5SMatthew Barth using InternalFailure = sdbusplus::xyz::openbmc_project::Common:: 19336f18a5SMatthew Barth Error::InternalFailure; 2038a93a8aSMatthew Barth 2138a93a8aSMatthew Barth /** 2238a93a8aSMatthew Barth * @brief Create a handler function object 2338a93a8aSMatthew Barth * 2438a93a8aSMatthew Barth * @param[in] handler - The handler being created 2538a93a8aSMatthew Barth * 2638a93a8aSMatthew Barth * @return - The created handler function object 2738a93a8aSMatthew Barth */ 2838a93a8aSMatthew Barth template <typename T> 2938a93a8aSMatthew Barth auto make_handler(T&& handler) 3038a93a8aSMatthew Barth { 3138a93a8aSMatthew Barth return Handler(std::forward<T>(handler)); 3238a93a8aSMatthew Barth } 3338a93a8aSMatthew Barth 3438a93a8aSMatthew Barth /** 3517d1fe23SMatthew Barth * @brief Create an action function object 3617d1fe23SMatthew Barth * 3717d1fe23SMatthew Barth * @param[in] action - The action being created 3817d1fe23SMatthew Barth * 3917d1fe23SMatthew Barth * @return - The created action function object 4017d1fe23SMatthew Barth */ 4117d1fe23SMatthew Barth template <typename T> 4217d1fe23SMatthew Barth auto make_action(T&& action) 4317d1fe23SMatthew Barth { 4417d1fe23SMatthew Barth return Action(std::forward<T>(action)); 4517d1fe23SMatthew Barth } 4617d1fe23SMatthew Barth 4717d1fe23SMatthew Barth /** 4838a93a8aSMatthew Barth * @struct Property Changed 4938a93a8aSMatthew Barth * @brief A match filter functor for Dbus property value changed signals 5038a93a8aSMatthew Barth * 5138a93a8aSMatthew Barth * @tparam T - The type of the property value 5238a93a8aSMatthew Barth * @tparam U - The type of the handler 5338a93a8aSMatthew Barth */ 5438a93a8aSMatthew Barth template <typename T, typename U> 5538a93a8aSMatthew Barth struct PropertyChanged 5638a93a8aSMatthew Barth { 5738a93a8aSMatthew Barth PropertyChanged() = delete; 5838a93a8aSMatthew Barth ~PropertyChanged() = default; 5938a93a8aSMatthew Barth PropertyChanged(const PropertyChanged&) = default; 6038a93a8aSMatthew Barth PropertyChanged& operator=(const PropertyChanged&) = default; 6138a93a8aSMatthew Barth PropertyChanged(PropertyChanged&&) = default; 6238a93a8aSMatthew Barth PropertyChanged& operator=(PropertyChanged&&) = default; 63336f18a5SMatthew Barth PropertyChanged(const char* path, 64336f18a5SMatthew Barth const char* iface, 6538a93a8aSMatthew Barth const char* property, 6638a93a8aSMatthew Barth U&& handler) : 67336f18a5SMatthew Barth _path(path), 6838a93a8aSMatthew Barth _iface(iface), 6938a93a8aSMatthew Barth _property(property), 7038a93a8aSMatthew Barth _handler(std::forward<U>(handler)) { } 7138a93a8aSMatthew Barth 7238a93a8aSMatthew Barth /** @brief Run signal handler function 7338a93a8aSMatthew Barth * 7438a93a8aSMatthew Barth * Extract the property from the PropertiesChanged 75336f18a5SMatthew Barth * message (or read the property when the message is null) 76336f18a5SMatthew Barth * and run the handler function. 7738a93a8aSMatthew Barth */ 78336f18a5SMatthew Barth void operator()(sdbusplus::bus::bus& bus, 7938a93a8aSMatthew Barth sdbusplus::message::message& msg, 8038a93a8aSMatthew Barth Zone& zone) const 8138a93a8aSMatthew Barth { 82336f18a5SMatthew Barth if (msg) 83336f18a5SMatthew Barth { 8438a93a8aSMatthew Barth std::map<std::string, sdbusplus::message::variant<T>> properties; 85d5cfdbe0SMatthew Barth std::string iface; 8638a93a8aSMatthew Barth 8738a93a8aSMatthew Barth msg.read(iface); 88d5cfdbe0SMatthew Barth if (iface != _iface) 8938a93a8aSMatthew Barth { 9038a93a8aSMatthew Barth return; 9138a93a8aSMatthew Barth } 9238a93a8aSMatthew Barth 9338a93a8aSMatthew Barth msg.read(properties); 9438a93a8aSMatthew Barth auto it = properties.find(_property); 9538a93a8aSMatthew Barth if (it == properties.cend()) 9638a93a8aSMatthew Barth { 9738a93a8aSMatthew Barth log<level::ERR>("Unable to find property on interface", 9838a93a8aSMatthew Barth entry("PROPERTY=%s", _property), 99e65f617cSMatthew Barth entry("INTERFACE=%s", _iface), 100e65f617cSMatthew Barth entry("PATH=%s", _path)); 10138a93a8aSMatthew Barth return; 10238a93a8aSMatthew Barth } 10338a93a8aSMatthew Barth 10438a93a8aSMatthew Barth _handler(zone, std::forward<T>(it->second.template get<T>())); 10538a93a8aSMatthew Barth } 106336f18a5SMatthew Barth else 107336f18a5SMatthew Barth { 108336f18a5SMatthew Barth try 109336f18a5SMatthew Barth { 110c72b8911SMatthew Barth auto service = zone.getService(_path, _iface); 111336f18a5SMatthew Barth auto val = util::SDBusPlus::getProperty<T>(bus, 112c72b8911SMatthew Barth service, 113336f18a5SMatthew Barth _path, 114336f18a5SMatthew Barth _iface, 115336f18a5SMatthew Barth _property); 116336f18a5SMatthew Barth _handler(zone, std::forward<T>(val)); 117336f18a5SMatthew Barth } 118336f18a5SMatthew Barth catch (const InternalFailure& ife) 119336f18a5SMatthew Barth { 120336f18a5SMatthew Barth // Property will not be used unless a property changed 121336f18a5SMatthew Barth // signal message is received for this property. 122336f18a5SMatthew Barth log<level::INFO>( 123336f18a5SMatthew Barth "Property not used, unless PropertyChanged signal received", 124336f18a5SMatthew Barth entry("PATH=%s", _path), 125336f18a5SMatthew Barth entry("INTERFACE=%s", _iface), 126336f18a5SMatthew Barth entry("PROPERTY=%s", _property)); 127336f18a5SMatthew Barth } 128336f18a5SMatthew Barth } 129336f18a5SMatthew Barth } 13038a93a8aSMatthew Barth 13138a93a8aSMatthew Barth private: 132336f18a5SMatthew Barth const char* _path; 13338a93a8aSMatthew Barth const char* _iface; 13438a93a8aSMatthew Barth const char* _property; 13538a93a8aSMatthew Barth U _handler; 13638a93a8aSMatthew Barth }; 13738a93a8aSMatthew Barth 13838a93a8aSMatthew Barth /** 13938a93a8aSMatthew Barth * @brief Used to process a Dbus property changed signal event 14038a93a8aSMatthew Barth * 141336f18a5SMatthew Barth * @param[in] path - Object path 142336f18a5SMatthew Barth * @param[in] iface - Object interface 143336f18a5SMatthew Barth * @param[in] property - Object property 14438a93a8aSMatthew Barth * @param[in] handler - Handler function to perform 14538a93a8aSMatthew Barth * 14638a93a8aSMatthew Barth * @tparam T - The type of the property 14738a93a8aSMatthew Barth * @tparam U - The type of the handler 14838a93a8aSMatthew Barth */ 14938a93a8aSMatthew Barth template <typename T, typename U> 150336f18a5SMatthew Barth auto propertySignal(const char* path, 151336f18a5SMatthew Barth const char* iface, 15238a93a8aSMatthew Barth const char* property, 15338a93a8aSMatthew Barth U&& handler) 15438a93a8aSMatthew Barth { 155336f18a5SMatthew Barth return PropertyChanged<T, U>(path, 156336f18a5SMatthew Barth iface, 157336f18a5SMatthew Barth property, 158336f18a5SMatthew Barth std::forward<U>(handler)); 15938a93a8aSMatthew Barth } 16038a93a8aSMatthew Barth 161eb639c57SMatthew Barth /** 162eb639c57SMatthew Barth * @struct Interface Added 163eb639c57SMatthew Barth * @brief A match filter functor for Dbus interface added signals 164eb639c57SMatthew Barth * 165eb639c57SMatthew Barth * @tparam T - The type of the property value 166eb639c57SMatthew Barth * @tparam U - The type of the handler 167eb639c57SMatthew Barth */ 168eb639c57SMatthew Barth template <typename T, typename U> 169eb639c57SMatthew Barth struct InterfaceAdded 170eb639c57SMatthew Barth { 171eb639c57SMatthew Barth InterfaceAdded() = delete; 172eb639c57SMatthew Barth ~InterfaceAdded() = default; 173eb639c57SMatthew Barth InterfaceAdded(const InterfaceAdded&) = default; 174eb639c57SMatthew Barth InterfaceAdded& operator=(const InterfaceAdded&) = default; 175eb639c57SMatthew Barth InterfaceAdded(InterfaceAdded&&) = default; 176eb639c57SMatthew Barth InterfaceAdded& operator=(InterfaceAdded&&) = default; 177eb639c57SMatthew Barth InterfaceAdded(const char* path, 178eb639c57SMatthew Barth const char* iface, 179eb639c57SMatthew Barth const char* property, 180eb639c57SMatthew Barth U&& handler) : 181eb639c57SMatthew Barth _path(path), 182eb639c57SMatthew Barth _iface(iface), 183eb639c57SMatthew Barth _property(property), 184eb639c57SMatthew Barth _handler(std::forward<U>(handler)) { } 185eb639c57SMatthew Barth 186eb639c57SMatthew Barth /** @brief Run signal handler function 187eb639c57SMatthew Barth * 188eb639c57SMatthew Barth * Extract the property from the InterfacesAdded 189eb639c57SMatthew Barth * message and run the handler function. 190eb639c57SMatthew Barth */ 191eb639c57SMatthew Barth void operator()(sdbusplus::bus::bus&, 192eb639c57SMatthew Barth sdbusplus::message::message& msg, 193eb639c57SMatthew Barth Zone& zone) const 194eb639c57SMatthew Barth { 195336f18a5SMatthew Barth if (msg) 196336f18a5SMatthew Barth { 197eb639c57SMatthew Barth std::map<std::string, 198eb639c57SMatthew Barth std::map<std::string, 199eb639c57SMatthew Barth sdbusplus::message::variant<T>>> intfProp; 200eb639c57SMatthew Barth sdbusplus::message::object_path op; 201eb639c57SMatthew Barth 202eb639c57SMatthew Barth msg.read(op); 203d5cfdbe0SMatthew Barth if (static_cast<const std::string&>(op) != _path) 204eb639c57SMatthew Barth { 205eb639c57SMatthew Barth // Object path does not match this handler's path 206eb639c57SMatthew Barth return; 207eb639c57SMatthew Barth } 208eb639c57SMatthew Barth 209eb639c57SMatthew Barth msg.read(intfProp); 210eb639c57SMatthew Barth auto itIntf = intfProp.find(_iface); 211eb639c57SMatthew Barth if (itIntf == intfProp.cend()) 212eb639c57SMatthew Barth { 213eb639c57SMatthew Barth // Interface not found on this handler's path 214eb639c57SMatthew Barth return; 215eb639c57SMatthew Barth } 216eb639c57SMatthew Barth auto itProp = itIntf->second.find(_property); 217eb639c57SMatthew Barth if (itProp == itIntf->second.cend()) 218eb639c57SMatthew Barth { 219eb639c57SMatthew Barth // Property not found on this handler's path 220eb639c57SMatthew Barth return; 221eb639c57SMatthew Barth } 222eb639c57SMatthew Barth 223eb639c57SMatthew Barth _handler(zone, std::forward<T>(itProp->second.template get<T>())); 224eb639c57SMatthew Barth } 225336f18a5SMatthew Barth } 226eb639c57SMatthew Barth 227eb639c57SMatthew Barth private: 228eb639c57SMatthew Barth const char* _path; 229eb639c57SMatthew Barth const char* _iface; 230eb639c57SMatthew Barth const char* _property; 231eb639c57SMatthew Barth U _handler; 232eb639c57SMatthew Barth }; 233eb639c57SMatthew Barth 234eb639c57SMatthew Barth /** 235eb639c57SMatthew Barth * @brief Used to process a Dbus interface added signal event 236eb639c57SMatthew Barth * 237eb639c57SMatthew Barth * @param[in] path - Object path 238eb639c57SMatthew Barth * @param[in] iface - Object interface 239eb639c57SMatthew Barth * @param[in] property - Object property 240eb639c57SMatthew Barth * @param[in] handler - Handler function to perform 241eb639c57SMatthew Barth * 242eb639c57SMatthew Barth * @tparam T - The type of the property 243eb639c57SMatthew Barth * @tparam U - The type of the handler 244eb639c57SMatthew Barth */ 245eb639c57SMatthew Barth template <typename T, typename U> 246eb639c57SMatthew Barth auto objectSignal(const char* path, 247eb639c57SMatthew Barth const char* iface, 248eb639c57SMatthew Barth const char* property, 249eb639c57SMatthew Barth U&& handler) 250eb639c57SMatthew Barth { 251eb639c57SMatthew Barth return InterfaceAdded<T, U>(path, 252eb639c57SMatthew Barth iface, 253eb639c57SMatthew Barth property, 254eb639c57SMatthew Barth std::forward<U>(handler)); 255eb639c57SMatthew Barth } 256eb639c57SMatthew Barth 2578fa02dabSMatthew Barth /** 258*1499a5c3SMatthew Barth * @struct Interface Removed 259*1499a5c3SMatthew Barth * @brief A match filter functor for Dbus interface removed signals 260*1499a5c3SMatthew Barth * 261*1499a5c3SMatthew Barth * @tparam U - The type of the handler 262*1499a5c3SMatthew Barth */ 263*1499a5c3SMatthew Barth template <typename U> 264*1499a5c3SMatthew Barth struct InterfaceRemoved 265*1499a5c3SMatthew Barth { 266*1499a5c3SMatthew Barth InterfaceRemoved() = delete; 267*1499a5c3SMatthew Barth ~InterfaceRemoved() = default; 268*1499a5c3SMatthew Barth InterfaceRemoved(const InterfaceRemoved&) = default; 269*1499a5c3SMatthew Barth InterfaceRemoved& operator=(const InterfaceRemoved&) = default; 270*1499a5c3SMatthew Barth InterfaceRemoved(InterfaceRemoved&&) = default; 271*1499a5c3SMatthew Barth InterfaceRemoved& operator=(InterfaceRemoved&&) = default; 272*1499a5c3SMatthew Barth InterfaceRemoved(const char* path, 273*1499a5c3SMatthew Barth const char* iface, 274*1499a5c3SMatthew Barth U&& handler) : 275*1499a5c3SMatthew Barth _path(path), 276*1499a5c3SMatthew Barth _iface(iface), 277*1499a5c3SMatthew Barth _handler(std::forward<U>(handler)) { } 278*1499a5c3SMatthew Barth 279*1499a5c3SMatthew Barth /** @brief Run signal handler function 280*1499a5c3SMatthew Barth * 281*1499a5c3SMatthew Barth * Extract the property from the InterfacesRemoved 282*1499a5c3SMatthew Barth * message and run the handler function. 283*1499a5c3SMatthew Barth */ 284*1499a5c3SMatthew Barth void operator()(sdbusplus::bus::bus&, 285*1499a5c3SMatthew Barth sdbusplus::message::message& msg, 286*1499a5c3SMatthew Barth Zone& zone) const 287*1499a5c3SMatthew Barth { 288*1499a5c3SMatthew Barth if (msg) 289*1499a5c3SMatthew Barth { 290*1499a5c3SMatthew Barth std::vector<std::string> intfs; 291*1499a5c3SMatthew Barth sdbusplus::message::object_path op; 292*1499a5c3SMatthew Barth 293*1499a5c3SMatthew Barth msg.read(op); 294*1499a5c3SMatthew Barth if (static_cast<const std::string&>(op) != _path) 295*1499a5c3SMatthew Barth { 296*1499a5c3SMatthew Barth // Object path does not match this handler's path 297*1499a5c3SMatthew Barth return; 298*1499a5c3SMatthew Barth } 299*1499a5c3SMatthew Barth 300*1499a5c3SMatthew Barth msg.read(intfs); 301*1499a5c3SMatthew Barth auto itIntf = std::find(intfs.begin(), intfs.end(), _iface); 302*1499a5c3SMatthew Barth if (itIntf == intfs.cend()) 303*1499a5c3SMatthew Barth { 304*1499a5c3SMatthew Barth // Interface not found on this handler's path 305*1499a5c3SMatthew Barth return; 306*1499a5c3SMatthew Barth } 307*1499a5c3SMatthew Barth 308*1499a5c3SMatthew Barth _handler(zone); 309*1499a5c3SMatthew Barth } 310*1499a5c3SMatthew Barth } 311*1499a5c3SMatthew Barth 312*1499a5c3SMatthew Barth private: 313*1499a5c3SMatthew Barth const char* _path; 314*1499a5c3SMatthew Barth const char* _iface; 315*1499a5c3SMatthew Barth U _handler; 316*1499a5c3SMatthew Barth }; 317*1499a5c3SMatthew Barth 318*1499a5c3SMatthew Barth /** 319*1499a5c3SMatthew Barth * @brief Used to process a Dbus interface removed signal event 320*1499a5c3SMatthew Barth * 321*1499a5c3SMatthew Barth * @param[in] path - Object path 322*1499a5c3SMatthew Barth * @param[in] iface - Object interface 323*1499a5c3SMatthew Barth * @param[in] handler - Handler function to perform 324*1499a5c3SMatthew Barth * 325*1499a5c3SMatthew Barth * @tparam U - The type of the handler 326*1499a5c3SMatthew Barth */ 327*1499a5c3SMatthew Barth template <typename U> 328*1499a5c3SMatthew Barth auto objectSignal(const char* path, 329*1499a5c3SMatthew Barth const char* iface, 330*1499a5c3SMatthew Barth U&& handler) 331*1499a5c3SMatthew Barth { 332*1499a5c3SMatthew Barth return InterfaceRemoved<U>(path, 333*1499a5c3SMatthew Barth iface, 334*1499a5c3SMatthew Barth std::forward<U>(handler)); 335*1499a5c3SMatthew Barth } 336*1499a5c3SMatthew Barth 337*1499a5c3SMatthew Barth /** 3388fa02dabSMatthew Barth * @struct Name Owner Changed 3398fa02dabSMatthew Barth * @brief A match filter functor for Dbus name owner changed signals 3408fa02dabSMatthew Barth * 3418fa02dabSMatthew Barth * @tparam U - The type of the handler 3428fa02dabSMatthew Barth */ 3438fa02dabSMatthew Barth template <typename U> 3448fa02dabSMatthew Barth struct NameOwnerChanged 3458fa02dabSMatthew Barth { 3468fa02dabSMatthew Barth NameOwnerChanged() = delete; 3478fa02dabSMatthew Barth ~NameOwnerChanged() = default; 3488fa02dabSMatthew Barth NameOwnerChanged(const NameOwnerChanged&) = default; 3498fa02dabSMatthew Barth NameOwnerChanged& operator=(const NameOwnerChanged&) = default; 3508fa02dabSMatthew Barth NameOwnerChanged(NameOwnerChanged&&) = default; 3518fa02dabSMatthew Barth NameOwnerChanged& operator=(NameOwnerChanged&&) = default; 3528fa02dabSMatthew Barth NameOwnerChanged(const char* path, 3538fa02dabSMatthew Barth const char* iface, 3548fa02dabSMatthew Barth U&& handler) : 3558fa02dabSMatthew Barth _path(path), 3568fa02dabSMatthew Barth _iface(iface), 3578fa02dabSMatthew Barth _handler(std::forward<U>(handler)) { } 3588fa02dabSMatthew Barth 3598fa02dabSMatthew Barth /** @brief Run signal handler function 3608fa02dabSMatthew Barth * 3618fa02dabSMatthew Barth * Extract the name owner from the NameOwnerChanged 3628fa02dabSMatthew Barth * message (or read the name owner when the message is null) 3638fa02dabSMatthew Barth * and run the handler function. 3648fa02dabSMatthew Barth */ 3658fa02dabSMatthew Barth void operator()(sdbusplus::bus::bus& bus, 3668fa02dabSMatthew Barth sdbusplus::message::message& msg, 3678fa02dabSMatthew Barth Zone& zone) const 3688fa02dabSMatthew Barth { 3695a302576SMatthew Barth std::string name; 3705a302576SMatthew Barth bool hasOwner = false; 3718fa02dabSMatthew Barth if (msg) 3728fa02dabSMatthew Barth { 3735a302576SMatthew Barth // Handle NameOwnerChanged signals 3745a302576SMatthew Barth msg.read(name); 3755a302576SMatthew Barth 3765a302576SMatthew Barth std::string oldOwn; 3775a302576SMatthew Barth msg.read(oldOwn); 3785a302576SMatthew Barth 3795a302576SMatthew Barth std::string newOwn; 3805a302576SMatthew Barth msg.read(newOwn); 3815a302576SMatthew Barth if (!newOwn.empty()) 3825a302576SMatthew Barth { 3835a302576SMatthew Barth hasOwner = true; 3845a302576SMatthew Barth } 3858fa02dabSMatthew Barth } 3868fa02dabSMatthew Barth else 3878fa02dabSMatthew Barth { 3885a302576SMatthew Barth try 3895a302576SMatthew Barth { 3905a302576SMatthew Barth // Initialize NameOwnerChanged data store with service name 391c72b8911SMatthew Barth name = zone.getService(_path, _iface); 3925a302576SMatthew Barth hasOwner = util::SDBusPlus::callMethodAndRead<bool>( 3935a302576SMatthew Barth bus, 3945a302576SMatthew Barth "org.freedesktop.DBus", 3955a302576SMatthew Barth "/org/freedesktop/DBus", 3965a302576SMatthew Barth "org.freedesktop.DBus", 3975a302576SMatthew Barth "NameHasOwner", 3985a302576SMatthew Barth name); 3998fa02dabSMatthew Barth } 4005a302576SMatthew Barth catch (const InternalFailure& ife) 4015a302576SMatthew Barth { 4025a302576SMatthew Barth // Failed to get service name owner state 4035a302576SMatthew Barth hasOwner = false; 4045a302576SMatthew Barth } 4055a302576SMatthew Barth } 4065a302576SMatthew Barth 4075a302576SMatthew Barth _handler(zone, name, hasOwner); 4088fa02dabSMatthew Barth } 4098fa02dabSMatthew Barth 4108fa02dabSMatthew Barth private: 4118fa02dabSMatthew Barth const char* _path; 4128fa02dabSMatthew Barth const char* _iface; 4138fa02dabSMatthew Barth U _handler; 4148fa02dabSMatthew Barth }; 4158fa02dabSMatthew Barth 4168fa02dabSMatthew Barth /** 4178fa02dabSMatthew Barth * @brief Used to process a Dbus name owner changed signal event 4188fa02dabSMatthew Barth * 4198fa02dabSMatthew Barth * @param[in] path - Object path 4208fa02dabSMatthew Barth * @param[in] iface - Object interface 4218fa02dabSMatthew Barth * @param[in] handler - Handler function to perform 4228fa02dabSMatthew Barth * 4238fa02dabSMatthew Barth * @tparam U - The type of the handler 4248fa02dabSMatthew Barth * 4258fa02dabSMatthew Barth * @return - The NameOwnerChanged signal struct 4268fa02dabSMatthew Barth */ 4278fa02dabSMatthew Barth template <typename U> 4288fa02dabSMatthew Barth auto ownerSignal(const char* path, 4298fa02dabSMatthew Barth const char* iface, 4308fa02dabSMatthew Barth U&& handler) 4318fa02dabSMatthew Barth { 4328fa02dabSMatthew Barth return NameOwnerChanged<U>(path, 4338fa02dabSMatthew Barth iface, 4348fa02dabSMatthew Barth std::forward<U>(handler)); 4358fa02dabSMatthew Barth } 4368fa02dabSMatthew Barth 43738a93a8aSMatthew Barth } // namespace control 43838a93a8aSMatthew Barth } // namespace fan 43938a93a8aSMatthew Barth } // namespace phosphor 440