For my project , I am using DBUS as IPC to interact between QT application ( Client Side ) and my service daemon (Server-Side - GIO / GDBUS ). At client side , methods are invoked asynchronously using QDBusPendingCallWatcher.
However at server side , how to make method call as async ? . As per my understanding , "g_dbus_method_invocation_return_value" will return response with output parameters making method invocation as sync.
One way I can think of is to return intermediate response using g_dbus_method_invocation_return_value and then once final response is received emit the final response as signal.
Sample Code :-
//Method invocation
static void handle_method_call(GDBusConnection *conn,
const gchar *sender,
const gchar *object_path,
const gchar *interface_name,
const gchar *method_name,
GVariant *parameters,
GDBusMethodInvocation *invocation,
gpointer user_data)
{
if (!g_strcmp0(method_name, "Scan")) {
guint8 radiotype = 0;
guint8temp_resp = 0 ;
g_variant_get(parameters, "(y)", radiotype);
// Async Function Call and takes very
// long time to return final response as needs to scan whole radio band
temp_resp = RadioScan(radiotype);
g_dbus_method_invocation_return_value(invocation, g_variant_new("(y", temp_resp)); // return intermediate response to client and when final response is received then emit the signal
g_free(response);
}
}
// Final scan response callback function
static gboolean on_scanfinalresponse_cb (gpointer user_data)
{
GDBusConnection *connection = G_DBUS_CONNECTION (user_data);
GVariantBuilder *builder;
GVariantBuilder *invalidated_builder;
GError *error;
g_dbus_connection_emit_signal (connection,
NULL,
"/org/example/test",
"org.example.test",
"ScanFinalResponse",
g_variant_new ("(s)",
builder),
&error);
g_assert_no_error (error);
return TRUE;
}
Please let me know is it right approach or is there any better way to achieve async call for the above case ?
However at server side , how to make method call as async ?
There's two concepts you might be referring to with "async" here and D-Bus (or GDBus) do not limit you in either one.
API design: If you can modify the actual exposed API, you can of course make a method that returns immediately and later "returns values" via property changes or signals. This might be a good idea for specific cases like a Wi-Fi scan invocation.
Method implementation: Your API might have a method that takes a long time before returning, and it may be implemented "asynchronously" in the sense that your service does not block while the method has not returned -- other methods can be invoked and signals and property changes can happen during that time. g_dbus_method_invocation_return_*
functions can be used to implement this. Creating long running D-Bus methods is not a problem as long as they are documented as such: clients can handle the calls asynchronously and can even increase the default method call timeout if required.
In context of the example code you posted, the first thing you need to do is to make the RadioScan() call asynchronous, or do the call in another thread: this ensures your service stays responsive during the call.
After your RadioScan is asynchronous it will be easy to implement either kind of of solution. If the RadioScan() method has a clearly defined return value (and you don't want to return intermediate results earlier) I'd opt for a normal method call that just takes longer:
static void handle_method_call(GDBusConnection *conn, ...)
{
if (!g_strcmp0(method_name, "Scan")) {
// start the async scan (maybe using another thread): this should
// return immediately and call the callback when scan is done
start_radio_scan(..., radio_scan_finished_cb);
// do not return the invocation here, just store a pointer to it
}
}
static void radio_scan_finished_cb (...)
{
// return the D-Bbus method call with the invocation that was stored earlier
g_dbus_method_invocation_return_value(invocation, ...)
}
If your scan results actually arrive over time (e.g. first result after 1 sec, more results after 3 secs), it may make sense to actually return the results as signals when they are available and then just return the method call as a sign that scan is finally finished.
Having a single "ScanFinalResponse" signal is certainly possible but I don't think there is any advantage to doing that over a method call that just takes longer.