Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Connecting to systemd DBUS signals using gdbus-codegen

I am not able to receive systemd DBus signals when using gdbus-codegen generated manager proxy. But I am able to successfully call methods provided by systemd over DBus.

I searched online and looked these links without much success. There aren't much examples on how to do it when gdbus-codegen is used for systemd API.

  • https://developer.gnome.org/gio/stable/gdbus-codegen.html
  • http://www.freedesktop.org/software/gstreamer-sdk/data/docs/latest/gio/ch30s05.html

Here is what I did along with code snippets.

1) I generated systemd introspection and used that XML as input to gdbus-codegen.

...snip

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

...snip

2) Wrote my client code to use C APIs generated by gdbus-codegen and created a manager proxy. (Everything is on 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) Connected a signal handler to that proxy for 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) Used the proxy to start a systemd service. This returns success and I could see the unit start and run for a second or two and terminate.

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

6) systemd generates a JobRemoved signal. dbus-monitor shows it.

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 signal handler never gets called. (Everything uses system bus, there are no other buses). I have tried various strings for detailed_signal 2nd parameter for g_signal_connect (like: JobRemoved, job_removed, ::job-removed, some are not accepted by g_signal_connect).

Any help is greatly appreciated!

like image 727
VJ- Avatar asked Apr 01 '15 03:04

VJ-


Video Answer


1 Answers

The solution was to use a glib event loop in my program. My program did not have a running GMainLoop which was necessary to get any callbacks from glib. This is not an elegant way but for various reasons I decided to spawn a new thread which would then block on g_main_loop_run. Here is how it looks like.

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
}

Also I had to fix my signal handler signature to be compatible with the signal to receive meaningful parameters.

static void on_done(SystemdManager *manager,
        guint32 job_id,
        gchar *job_obj,
        gchar *unit_name,
        gchar *status)
{
    LOG_ERROR("on_done");
}
like image 184
VJ- Avatar answered Nov 15 '22 08:11

VJ-