From 261e72b6fb5f4fbe95b68a5a6e3ee863025b3be3 Mon Sep 17 00:00:00 2001 From: Vernon Mauery Date: Tue, 25 Sep 2018 12:34:25 -0700 Subject: Add coroutine support for sdbusplus::asio method calls Using a coroutine to asynchronously execute method calls gives the best of both worlds: 1) better readability because the code reads like synchronous code 2) better throughput because it is actually asynchronous When passed in a boost::asio::yield_context, the sdbusplus::asio dbus connection members async_send and async_method_call will execute asynchronously using coroutines. This also adds an example of how this works in the example/asio-example.cpp file. Change-Id: Ifb71b2c757ecbfd16b3be95bdefc45a701ca0d51 Signed-off-by: Vernon Mauery --- example/asio-example.cpp | 75 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 74 insertions(+), 1 deletion(-) (limited to 'example/asio-example.cpp') diff --git a/example/asio-example.cpp b/example/asio-example.cpp index cced85d..9819eba 100644 --- a/example/asio-example.cpp +++ b/example/asio-example.cpp @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -9,6 +10,7 @@ #include #include +using variant = sdbusplus::message::variant; int foo(int test) { return ++test; @@ -24,6 +26,68 @@ int voidBar(void) return 42; } +void do_start_async_method_call_one( + std::shared_ptr conn, + boost::asio::yield_context yield) +{ + boost::system::error_code ec; + variant testValue; + conn->yield_method_call<>(yield[ec], "xyz.openbmc_project.asio-test", + "/xyz/openbmc_project/test", + "org.freedesktop.DBus.Properties", "Set", + "xyz.openbmc_project.test", "int", variant(24)); + testValue = conn->yield_method_call( + yield[ec], "xyz.openbmc_project.asio-test", "/xyz/openbmc_project/test", + "org.freedesktop.DBus.Properties", "Get", "xyz.openbmc_project.test", + "int"); + if (!ec && testValue.get() == 24) + { + std::cout << "async call to Properties.Get serialized via yield OK!\n"; + } + else + { + std::cout << "ec = " << ec << ": " << testValue.get() << "\n"; + } + conn->yield_method_call( + yield[ec], "xyz.openbmc_project.asio-test", "/xyz/openbmc_project/test", + "org.freedesktop.DBus.Properties", "Set", "xyz.openbmc_project.test", + "int", variant(42)); + testValue = conn->yield_method_call( + yield[ec], "xyz.openbmc_project.asio-test", "/xyz/openbmc_project/test", + "org.freedesktop.DBus.Properties", "Get", "xyz.openbmc_project.test", + "int"); + if (!ec && testValue.get() == 42) + { + std::cout << "async call to Properties.Get serialized via yield OK!\n"; + } + else + { + std::cout << "ec = " << ec << ": " << testValue.get() << "\n"; + } +} + +void do_start_async_method_call_two( + std::shared_ptr conn, + boost::asio::yield_context yield) +{ + boost::system::error_code ec; + int32_t testCount; + std::string testValue; + std::tie(testCount, testValue) = + conn->yield_method_call( + yield[ec], "xyz.openbmc_project.asio-test", + "/xyz/openbmc_project/test", "xyz.openbmc_project.test", + "TestMethod", int32_t(42)); + if (!ec && testCount == 42 && testValue == "success: 42") + { + std::cout << "async call to TestMethod serialized via yield OK!\n"; + } + else + { + std::cout << "ec = " << ec << ": " << testValue << "\n"; + } +} + int main() { using GetSubTreeType = std::vectorregister_method("TestMethod", [](const int32_t& callCount) { - return "success: " + std::to_string(callCount); + return std::make_tuple(callCount, + "success: " + std::to_string(callCount)); }); iface->register_method("TestFunction", foo); @@ -141,6 +206,14 @@ int main() // add the sd_event wrapper to the io object sdbusplus::asio::sd_event_wrapper sdEvents(io); + // set up a client to make an async call to the server + // using coroutines (userspace cooperative multitasking) + boost::asio::spawn(io, [conn](boost::asio::yield_context yield) { + do_start_async_method_call_one(conn, yield); + }); + boost::asio::spawn(io, [conn](boost::asio::yield_context yield) { + do_start_async_method_call_two(conn, yield); + }); io.run(); return 0; -- cgit v1.2.3