前面
本文章描述D-Bus同步调用函数与异步调用函数。
D-Bus函数调用
同步调用
new_method_call
需要判断返回值情况:
uint32_t commit(const char* name)
{
using phosphor::logging::log;
auto bus = sdbusplus::bus::new_default();
auto method = bus.new_method_call("xyz.openbmc_project.Logging", "/xyz/openbmc_project/logging/internel/manager", "xyz.openbmc_project.Logging.Internal.Manager", "Commit");
uint64_t id = sdbusplus::server::transaction::get_id();
method.append(id, name);
auto reply = bus.call(method);
uint32_t entryID;
reply.read(entryID);
return entryID;
}
无需判断返回值情况:
void commit(const char* name)
{
using phosphor::logging::log;
auto bus = sdbusplus::bus::new_default();
auto method = bus.new_method_call("xyz.openbmc_project.Logging", "/xyz/openbmc_project/logging/internel/manager", "xyz.openbmc_project.Logging.Internal.Manager", "Commit");
uint64_t id = sdbusplus::server::transaction::get_id();
method.append(id, name);
auto reply = bus.call_noreply(method);
return ;
}
异步调用
通常与lambda表达式混合使用。
async_method_call
static boost::asio::io_context io;
std::shared_ptr<sdbusplus::asio::connection> conn;
static void beep(const uint8_t& beepPriority)
{
lg2::info("Beep with priority: {BEEP_PRIORITY}", "BEEP_PRIORITY",
beepPriority);
conn->async_method_call(
[](boost::system::error_code ec) {
if (ec)
{
lg2::error(
"beep returned error with async_method_call (ec = {ERROR_MSG})",
"ERROR_MSG", ec.message());
return;
}
},
"xyz.openbmc_project.BeepCode", "/xyz/openbmc_project/BeepCode",
"xyz.openbmc_project.BeepCode", "Beep", uint8_t(beepPriority));
}
yield_method_call
yield_method_call 方法实际上是一个异步的方法。它使用的是 asio 库中的异步操作和协程机制。
通过使用 yield_method_call 方法可以在异步环境中执行 DBus 方法调用,并在方法调用完成后恢复协程的执行。这种调用方式允许程序在等待方法调用结果时不会阻塞主线程,而是继续处理其他任务。可以理解为yield_method_call在响应之前会处于等待的状态。
void handleLegacyIpmiCommand(sdbusplus::message_t& m)
{
// make a copy so the next two moves don't wreak havoc on the stack
sdbusplus::message_t b{m};
boost::asio::spawn(*getIoContext(),
[b = std::move(b)](boost::asio::yield_context yield) {
sdbusplus::message_t m{std::move(b)};
unsigned char seq = 0, netFn = 0, lun = 0, cmd = 0;
ipmi::SecureBuffer data;
m.read(seq, netFn, lun, cmd, data);
std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus();
auto ctx = std::make_shared<ipmi::Context>(bus, netFn, lun, cmd, 0, 0, 0, ipmi::Privilege::Admin, 0, 0, yield);
auto request = std::make_shared<ipmi::message::Request>(ctx, std::forward<ipmi::SecureBuffer>(data));
ipmi::message::Response::ptr response = ipmi::executeIpmiCommand(request);
// Responses in IPMI require a bit set. So there ya go...
netFn |= 0x01;
const char *dest, *path;
constexpr const char* DBUS_INTF = "org.openbmc.HostIpmi";
dest = m.get_sender();
path = m.get_path();
boost::system::error_code ec;
bus->yield_method_call(yield, ec, dest, path, DBUS_INTF, "sendMessage",
seq, netFn, lun, cmd, response->cc,
response->payload.raw);
if (ec)
{
log<level::ERR>("Failed to send response to requestor",
entry("ERROR=%s", ec.message().c_str()),
entry("SENDER=%s", dest),
entry("NETFN=0x%X", netFn), entry("CMD=0x%X", cmd));
}
});
}