Add yielding utility calls
utils.hpp provides a bunch of blocking D-Bus calls that are used
liberally in the ipmi handlers. By adding a yielding option that takes
the ipmi::Context::ptr, this can easily turn all the blocking calls into
yielding calls as the handlers get rewritten.
Tested: Used the upcoming modification of XYZ call:
Before:
ipmitool get session info
After:
ipmitool get session info
Signed-off-by: Vernon Mauery <vernon.mauery@linux.intel.com>
Change-Id: Ia537eeda060ea8e56b94b99ccb46b05f18372589
diff --git a/libipmid/utils.cpp b/libipmid/utils.cpp
index ed493d6..21397f9 100644
--- a/libipmid/utils.cpp
+++ b/libipmid/utils.cpp
@@ -335,18 +335,19 @@
}
}
+static inline std::string convertToString(const InterfaceList& interfaces)
+{
+ std::string intfStr;
+ for (const auto& intf : interfaces)
+ {
+ intfStr += "," + intf;
+ }
+ return intfStr;
+}
+
ObjectTree getAllAncestors(sdbusplus::bus::bus& bus, const std::string& path,
InterfaceList&& interfaces)
{
- auto convertToString = [](InterfaceList& interfaces) -> std::string {
- std::string intfStr;
- for (const auto& intf : interfaces)
- {
- intfStr += "," + intf;
- }
- return intfStr;
- };
-
auto mapperCall = bus.new_method_call(MAPPER_BUS_NAME, MAPPER_OBJ,
MAPPER_INTF, "GetAncestors");
mapperCall.append(path, interfaces);
@@ -400,6 +401,224 @@
}
} // namespace method_no_args
+
+/********* Begin co-routine yielding alternatives ***************/
+
+boost::system::error_code getService(Context::ptr ctx, std::string& service,
+ const std::string& intf,
+ const std::string& path)
+{
+ boost::system::error_code ec;
+ std::map<std::string, std::vector<std::string>> mapperResponse =
+ ctx->bus->yield_method_call<decltype(mapperResponse)>(
+ ctx->yield, ec, "xyz.openbmc_project.ObjectMapper",
+ "/xyz/openbmc_project/object_mapper",
+ "xyz.openbmc_project.ObjectMapper", "GetObject",
+ std::vector<std::string>({intf}));
+
+ if (!ec)
+ {
+ service = std::move(mapperResponse.begin()->first);
+ }
+ return ec;
+}
+
+boost::system::error_code getDbusObject(Context::ptr ctx,
+ const std::string& interface,
+ const std::string& subtreePath,
+ const std::string& match,
+ DbusObjectInfo& dbusObject)
+{
+ std::vector<DbusInterface> interfaces;
+ interfaces.emplace_back(interface);
+
+ auto depth = 0;
+ boost::system::error_code ec;
+ ObjectTree objectTree = ctx->bus->yield_method_call<ObjectTree>(
+ ctx->yield, ec, MAPPER_BUS_NAME, MAPPER_OBJ, MAPPER_INTF, "GetSubTree",
+ subtreePath, depth, interfaces);
+
+ if (ec)
+ {
+ return ec;
+ }
+
+ if (objectTree.empty())
+ {
+ log<level::ERR>("No Object has implemented the interface",
+ entry("INTERFACE=%s", interface.c_str()),
+ entry("NETFN=%x", ctx->netFn),
+ entry("CMD=%x,", ctx->cmd));
+ return boost::system::errc::make_error_code(
+ boost::system::errc::no_such_process);
+ }
+
+ // if match is empty then return the first object
+ if (match == "")
+ {
+ dbusObject = std::make_pair(
+ std::move(objectTree.begin()->first),
+ std::move(objectTree.begin()->second.begin()->first));
+ return ec;
+ }
+
+ // else search the match string in the object path
+ auto found = std::find_if(
+ objectTree.begin(), objectTree.end(), [&match](const auto& object) {
+ return (object.first.find(match) != std::string::npos);
+ });
+
+ if (found == objectTree.end())
+ {
+ log<level::ERR>("Failed to find object which matches",
+ entry("MATCH=%s", match.c_str()),
+ entry("NETFN=%x", ctx->netFn),
+ entry("CMD=%x,", ctx->cmd));
+ // set ec
+ return boost::system::errc::make_error_code(
+ boost::system::errc::no_such_file_or_directory);
+ }
+
+ dbusObject = std::make_pair(std::move(found->first),
+ std::move(found->second.begin()->first));
+ return ec;
+}
+
+boost::system::error_code getAllDbusProperties(Context::ptr ctx,
+ const std::string& service,
+ const std::string& objPath,
+ const std::string& interface,
+ PropertyMap& properties)
+{
+ boost::system::error_code ec;
+ properties = ctx->bus->yield_method_call<PropertyMap>(
+ ctx->yield, ec, service.c_str(), objPath.c_str(), PROP_INTF,
+ METHOD_GET_ALL, interface);
+ return ec;
+}
+
+boost::system::error_code
+ setDbusProperty(Context::ptr ctx, const std::string& service,
+ const std::string& objPath, const std::string& interface,
+ const std::string& property, const Value& value)
+{
+ boost::system::error_code ec;
+ ctx->bus->yield_method_call(ctx->yield, ec, service.c_str(),
+ objPath.c_str(), PROP_INTF, METHOD_SET,
+ interface, property, value);
+ return ec;
+}
+
+boost::system::error_code getAllDbusObjects(Context::ptr ctx,
+ const std::string& serviceRoot,
+ const std::string& interface,
+ const std::string& match,
+ ObjectTree& objectTree)
+{
+ boost::system::error_code ec;
+ std::vector<std::string> interfaces;
+ interfaces.emplace_back(interface);
+
+ auto depth = 0;
+
+ objectTree = ctx->bus->yield_method_call<ObjectTree>(
+ ctx->yield, ec, MAPPER_BUS_NAME, MAPPER_OBJ, MAPPER_INTF, "GetSubTree",
+ serviceRoot, depth, interfaces);
+
+ if (ec)
+ {
+ return ec;
+ }
+
+ for (auto it = objectTree.begin(); it != objectTree.end();)
+ {
+ if (it->first.find(match) == std::string::npos)
+ {
+ it = objectTree.erase(it);
+ }
+ else
+ {
+ ++it;
+ }
+ }
+
+ return ec;
+}
+
+boost::system::error_code deleteAllDbusObjects(Context::ptr ctx,
+ const std::string& serviceRoot,
+ const std::string& interface,
+ const std::string& match)
+{
+ ObjectTree objectTree;
+ boost::system::error_code ec =
+ getAllDbusObjects(ctx, serviceRoot, interface, match, objectTree);
+ if (ec)
+ {
+ return ec;
+ }
+
+ for (auto& object : objectTree)
+ {
+ ctx->bus->yield_method_call(ctx->yield, ec,
+ object.second.begin()->first, object.first,
+ DELETE_INTERFACE, "Delete");
+ if (ec)
+ {
+ log<level::ERR>("Failed to delete all objects",
+ entry("INTERFACE=%s", interface.c_str()),
+ entry("SERVICE=%s", serviceRoot.c_str()),
+ entry("NETFN=%x", ctx->netFn),
+ entry("CMD=%x,", ctx->cmd),
+ entry("ERROR=%s", ec.message().c_str()));
+ break;
+ }
+ }
+ return ec;
+}
+
+boost::system::error_code getManagedObjects(Context::ptr ctx,
+ const std::string& service,
+ const std::string& objPath,
+ ObjectValueTree& objects)
+{
+ boost::system::error_code ec;
+ objects = ctx->bus->yield_method_call<ipmi::ObjectValueTree>(
+ ctx->yield, ec, service.c_str(), objPath.c_str(),
+ "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
+ return ec;
+}
+
+boost::system::error_code getAllAncestors(Context::ptr ctx,
+ const std::string& path,
+ const InterfaceList& interfaces,
+ ObjectTree& objectTree)
+{
+ std::string interfaceList = convertToString(interfaces);
+
+ boost::system::error_code ec;
+ objectTree = ctx->bus->yield_method_call<ObjectTree>(
+ ctx->yield, ec, MAPPER_BUS_NAME, MAPPER_OBJ, MAPPER_INTF,
+ "GetAncestors", path, interfaceList);
+
+ if (ec)
+ {
+ return ec;
+ }
+
+ if (objectTree.empty())
+ {
+ log<level::ERR>("No Object has implemented the interface",
+ entry("PATH=%s", path.c_str()),
+ entry("INTERFACES=%s", interfaceList.c_str()));
+ elog<InternalFailure>();
+ }
+
+ return ec;
+}
+
+/********* End co-routine yielding alternatives ***************/
+
ipmi::Cc i2cWriteRead(std::string i2cBus, const uint8_t slaveAddr,
std::vector<uint8_t> writeData,
std::vector<uint8_t>& readBuf)