Search code examples
creadlineglibdbusbluez

Forcing immediate handling of events in Glib with C


Programming against the C GDBus API from Bluez, I noticed that method calls I am making using DBUS through a proxy won't return their results until the end of the main loop.

For example, typing a function I made "cmd_bpm" in the terminal application executes these things:

cmd_scan("on"); //Outputs "Discovery started", then posts results through a callback.
printf("test"); 
cmd_scan("off"); //Outputs "Discovery stopped", then posts results through a callback.

However, these callbacks are not handled until at the end of the GMainLoop. The output is:

test
discovery started
discovery stopped

Although relying on output to check the order of message calling is not what I have done; I understand printing has to do with line buffers. But breakpointing through the script showed that the callbacks are always handled at the end of the loop. Is there any way to either force glib to handle those events as they are called. E.g. waiting for the reply, run the callback, then continuing the code. Instead of waiting for the code to run then executing all callback functions. I'm not even sure if glib is the culprit, as trying to force main loop iterations was unsuccessful.

I have also tried to make dbus method calls block and wait for a reply, but the StartDiscovery() function I am executing with cmd_scan() is void, so there are no replies.

I would like to provide more information but I wouldn't know what to include, I haven't noticed a similar topic anywhere.

Preparing the main loop and callbacks.

main_loop = g_main_loop_new(NULL, FALSE);
dbus_conn = g_dbus_setup_bus(DBUS_BUS_SYSTEM, NULL, NULL);

signal = setup_signalfd();

client = g_dbus_client_new(dbus_conn, "org.bluez", "/org/bluez");

g_dbus_client_set_connect_watch(client, connect_handler, NULL);
g_dbus_client_set_disconnect_watch(client, disconnect_handler, NULL);
g_dbus_client_set_signal_watch(client, message_handler, NULL);
g_dbus_client_set_proxy_handlers(client, proxy_added, proxy_removed,
                        property_changed, NULL);

input = 0;

g_dbus_client_set_ready_watch(client, client_ready, &input);

g_main_loop_run(main_loop);

Inside this main loop I can input user commands.


Solution

  • GDBus has sync versions of all method call functions. E.g. instead of calling g_dbus_proxy_call() you call g_dbus_proxy_call_sync().

    Some methods return before there are any "results": StartDiscovery() is probably one of those -- even the name suggests it only starts discovery: it doesn't wait for discovery results to appear before returning but will send signals or property changes when results are available. If you need to wait for those results before doing something, then you will have to do that something in the signal (or property change) handler, not in the main code body.