0

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.

Zimano
  • 1,870
  • 2
  • 23
  • 41
  • I/O to a terminal is normally line buffered. So you should try `printf("test\n");` , and add a \n anywhere else where you print to stdout as well. (or call fflush(stdout) ). If your issue is not resolve, post a complete, minimal example of your code. – nos Oct 07 '15 at 12:28
  • I've tried that indeed, I forgot to add it though. However I didn't mean that I wanted to fix the output; the entire callback function isn't called, I want to force the application to dispatch the callback immediately whenever I call cmd_scan. I'll edit my answer to make that more clear. Thanks! – Zimano Oct 07 '15 at 12:32
  • It was just a comment, since a \n could make it appear that the callbacks wasn't called, since the output will be deferred in that case, while the work is actually done - you just don't see it on the screen immediately. However, you'll need to post more complete code for people to help you. – nos Oct 07 '15 at 12:33
  • That's the thing; the work isn't being done. I was reluctant to post code since I think this is also more of a conceptual question in that I want to know how to force a GMainloop to dispatch callbacks instantly instead of at the end of the loop after breaking. – Zimano Oct 07 '15 at 12:36
  • And it's hard to know what that means without seeing the code - the GMainLoop is not supposed to run callbacks only when you terminate it.. a GMainLoop runs callbacks immediately, unless you have blocked the GMainLoop (e.g. by doing intensive or blocking work from within a callback). You could process pending events by calling g_main_context_iteration() yourself, however that is often an indication you've done something conceptually wrong somewhere. – nos Oct 07 '15 at 12:40
  • I actually found that calling `g_main_context_iteration()` fixed my issues. I'm beginning to think the readline library that is being used is the culprit of the blocking of the `GMainLoop`. – Zimano Oct 07 '15 at 13:36
  • Perhaps. I do believe readline can be ued asyncronously, but if you use it normally e.g. just calling readline() , it'll certainly block whatever else is going on such as a GMainLoop. – nos Oct 07 '15 at 16:38
  • 1
    One thing you could do now that you have the D-Bus stuff going already is to implement your code with the main-loop as a D-Bus service and drive the tests through e.g. dbus-send or something like D-Feet. That way your entry point to events will be using the same mechanisms, i.e. GDBus and it might ease up troubleshooting and make tests more extensible. – JoGr Oct 08 '15 at 08:23

1 Answers1

2

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.

Jussi Kukkonen
  • 13,857
  • 1
  • 37
  • 54
  • Clear answer. Introduces a new insight (Implementing functionality in the callback/property change handler) and explains two method calling functions. Thanks! – Zimano Oct 09 '15 at 09:20