4

I have a problem using Glib. I want to subscribe to a dbus signal without launching the mainloop with g_main_loop_run.

I create the connection to the correct bus and call the function g_dbus_connection_signal_subscribe.

I replaced the call to g_main_loop_run in the main function by a while(1).

Unfortunately, it's not working. If I understand correctly the GLib, there is no need to launch the mainloop for a such treatment.

Please help.

Sample code :

session_bus = g_bus_get_sync(G_BUS_TYPE_SESSION,
                             NULL,
                             NULL );


g_dbus_connection_signal_subscribe(session_bus,
                                   "org.freedesktop.Notifications",
                                   "org.freedesktop.Notifications",
                                   "NotificationClosed",
                                   "/org/freedesktop/Notifications",
                                   NULL,
                                   G_DBUS_SIGNAL_FLAGS_NONE,
                                   (GDBusSignalCallback) onNotifClosed,
                                   NULL,
                                   NULL );

loop = g_main_loop_new(NULL, FALSE);
g_main_loop_run(loop);
g_main_loop_unref(loop);
g_object_unref(session_bus);
amenophiks
  • 73
  • 2
  • 6
  • 3
    "there is no need to launch the mainloop" - on the contrary, the only way it will work is to run a main loop. – ptomato May 20 '14 at 05:56

2 Answers2

4

If I understand correctly the GLib, there is no need to launch the mainloop for a such treatment.

If you want to wait for incoming DBus events, you have to run main loop. What main loop does is to wait and process events, and you want to wait and then process events. As an alternative to g_main_loop_run, you may try to run g_main_context_iteration in while(1).

3

I had a similar need to process GLib events in a non-blocking manner and I couldn't find a complete answer anywhere, so I'm posting my solution here for reference.

As el.pescado said, the one alternative to g_main_loop_run() is calling g_main_context_iteration() repeatedly on the context of the GMainLoop object. This may be done in a loop for example, allowing some intervening_task() to be performed between event processing cycles until some sort of termination_condition() is met:

GMainLoop *loop = g_main_loop_new();
while (!termination_condition())
{
  g_main_context_iteration(g_main_loop_get_context(loop), FALSE);
  intervening_task();
}

g_main_loop_unref(loop);

In the snippet above, the loop context is retrieved by g_main_loop_get_context(), and any pending GLib events are processed by g_main_context_iteration(). Setting the may_block argument to FALSE causes the function to return immediately if there are no pending events (otherwise it would block waiting for something to process).

It's worth noticing however that if the above is all you want to do, then you might as well stick to g_main_loop_run() and use g_timeout_add() or g_idle_add() to register the intervening task and termination condition as event callbacks — the later would call g_main_loop_quit() to terminate the loop. The point here is not to use that code as-is, but merely to demonstrate how GLib events can be processed in a non-blocking manner, so it can be integrated to the main loop of another framework. e.g. Qt or ROS.

xperroni
  • 2,606
  • 1
  • 23
  • 29
  • You’ve basically reinvented a poor version of `g_main_loop_run()` there. If you look at the [source code for `g_main_loop_run()`](https://gitlab.gnome.org/GNOME/glib/-/blob/master/glib/gmain.c#L4271), it does the equivalent of calling `g_main_context_iteration()` in a loop. You would be better off creating a `GSource` for your `intervening_task()` (for example, using `g_idle_source_new()`) and adding that to the main context. Then your intervening task can be polled/waited for in the same `poll()` call as the rest of the event sources in the main context. – Philip Withnall Oct 28 '20 at 21:15
  • Yes, but you miss the point. The purpose of that code snippet is not to be used as-is, but to demonstrate how GLib events can be processed in a non-blocking manner. Then you're free to apply that however you need. – xperroni Oct 29 '20 at 11:38
  • In my case for example, I wanted to call `g_main_context_iteration()` from a [ROS timer](http://wiki.ros.org/roscpp/Overview/Timers) callback function. If I had seen a snippet like that, it would have made things easier for me, even though my finished code looks nothing like that. – xperroni Oct 29 '20 at 11:45
  • 1
    Ah, I missed the fact that you were calling `g_main_context_iteration()` with `may_block` set to false. i.e. Chaining the GLib main loop to another main loop, rather than the other way round. What you’ve said makes sense in that case, sorry for the misinterpretation. One simplification you could make is to drop the `GMainLoop` entirely, and construct/use `GMainContext` directly (`g_main_context_new()` or `g_main_context_default()`). `GMainLoop` is just a closure which contains a `GMainContext` and an exit condition. – Philip Withnall Oct 29 '20 at 19:57