Connect to DBUS system signals using gdbus-codegen

I cannot receive systemd DBus signals when using the manager proxy created by gdbus-codegen. But I can successfully call the methods provided by systemd via DBus.

I searched the Internet and looked at these links without much success. There are not many examples of how to do this when gdbus-codegen is used for the systemd API.

Here is what I did with the code snippets.

1) I generated a system introspection and used this XML as input for gdbus-codegen.

... chick

<interface name="org.freedesktop.systemd1.Manager"> <signal name="JobRemoved"> <arg type="u"/> <arg type="o"/> <arg type="s"/> <arg type="s"/> </signal> 

... chick

2) I wrote a client code for using the C API generated by gdbus-codegen, and created a manager proxy. (Everything is on the system bus).

 SystemdManager *systemdProxy = systemd_manager_proxy_new_for_bus_sync( G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_NONE, "org.freedesktop.systemd1", "/org/freedesktop/systemd1", NULL, error); 

3) Define a signal handler

 static void on_done(GDBusProxy *proxy, gchar *sender_name, gchar *signal_name, GVariant *parameters, gpointer user_data) { LOG_ERROR("on_done"); } 

4) I connected the signal handler to this proxy for the JobRemoved signal.

 if (g_signal_connect(systemdProxy, "job-removed", G_CALLBACK(on_done), NULL) <= 0 ) { LOG_ERROR("Failed to connect to signal job-removed"); } 

5) A proxy server is used to start the systemd service. This returns success, and I could see that the device starts and starts for a second or two and ends.

 ret = systemd_manager_call_start_unit_sync( systemdProxy, unit_name, unit_mode, &job_obj, NULL, &error); 

6) systemd generates a JobRemoved signal. The dbus monitor shows this.

 signal sender=:1.0 -> dest=(null destination) serial=11931 path=/org/freedesktop/systemd1; interface=org.freedesktop.systemd1.Manager; member=JobRemoved uint32 7009 object path "/org/freedesktop/systemd1/job/7009" string "mysample.service" string "done" 

7) My handler is never called. (Everything uses a system bus, no other buses). I tried different lines for detailed_signal 2nd parameter for g_signal_connect (for example: JobRemoved , job_removed , ::job-removed , some of them are not accepted by g_signal_connect ).

Any help is much appreciated!

+6
source share
1 answer

The solution was to use glib event loop in my program. My program did not have a GMainLoop run, which was necessary to receive any callbacks from glib . This is not an elegant way, but for various reasons I decided to create a new thread, which then blocks g_main_loop_run. Here is how it looks.

 void *event_loop_thread(void *unused) { GMainLoop *loop = g_main_loop_new(NULL, 0); g_main_loop_run(loop); } int main() { // snip pthread_create(&thread_id, NULL, event_loop_thread, NULL); // do steps 2 to 6, and at step 7 signal handler is called } 

I also had to fix my signature on the signal handler in order to be compatible with the signal to get meaningful parameters.

 static void on_done(SystemdManager *manager, guint32 job_id, gchar *job_obj, gchar *unit_name, gchar *status) { LOG_ERROR("on_done"); } 
+2
source

Source: https://habr.com/ru/post/984536/


All Articles