2015-04-01 23 views
6

Ich bin nicht in der Lage, Systemd DBus-Signale zu empfangen, wenn Sie gdbus-codegen generierten Manager-Proxy verwenden. Aber ich bin in der Lage, Methoden von Systemd über DBus erfolgreich aufzurufen.Verbinden mit Systemd DBUS-Signalen mit gdbus-codegen

Ich suchte online und sah diese Links ohne viel Erfolg. Es gibt nicht viele Beispiele dafür, wie es funktioniert, wenn gdbus-codegen für systemd API verwendet wird.

Hier ist, was ich zusammen mit Code-Schnipsel tat.

1) Ich habe systemd introspection generiert und dieses XML als Eingabe für gdbus-codegen verwendet.

... schnipp

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

... schnipp

2) mein Client-Code Schrieb von gdbus-codegen generierten C-APIs zu verwenden und einen Manager-Proxy erstellt. (Alles ist auf Systembus).

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) Definieren einer Signalbehandlungsroutine

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

4) eine Signalbehandlungsroutine für JobRemoved Signal an diesem Proxy verbunden ist.

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

5) Verwendet den Proxy, um einen Systemd-Dienst zu starten. Das bringt Erfolg zurück und ich konnte sehen, dass die Einheit für eine Sekunde oder zwei startet und läuft und beendet.

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

6) systemd generiert ein JobRemoved-Signal. dbus-monitor zeigt es an.

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) Mein Signalhandler wird nie aufgerufen. (Alles benutzt Systembus, es gibt keine anderen Busse). Ich habe verschiedene Strings für detailed_signal 2. Parameter für g_signal_connect versucht (wie: JobRemoved, job_removed, ::job-removed, einige werden nicht von g_signal_connect akzeptiert).

Jede Hilfe wird sehr geschätzt!

Antwort

2

Die Lösung war eine glib event loop in meinem Programm zu verwenden. Mein Programm hatte keine laufende GMainLoop, die notwendig war, um Rückrufe von glib zu bekommen. Das ist kein eleganter Weg, aber aus verschiedenen Gründen habe ich beschlossen, einen neuen Thread zu erstellen, der dann auf g_main_loop_run blockiert. So sieht es aus.

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 
} 

Auch hatte ich meine Signal-Handler Unterschrift zu beheben mit dem Signal kompatibel ist sinnvolle Parameter zu erhalten.

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