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.
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!
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");
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With