使用gdbus-codegen连接到systemd DBUS信号

8

当使用gdbus-codegen生成的管理代理时,我无法接收systemd DBus信号。但是,我能够成功地通过DBus调用systemd提供的方法。

我在网上搜索并查看了这些链接,但没有取得太大的成功。在使用gdbus-codegen进行systemd API时,没有太多的示例可供参考。

这是我做的事情以及代码片段。

1)我生成了systemd内省,并将其XML用作gdbus-codegen的输入。

...剪辑

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

2) 编写客户端代码使用由gdbus-codegen生成的C API,并创建管理器代理。(所有内容都在系统总线上运行)。

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) 定义一个信号处理程序

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

4) 为该代理连接了一个信号处理程序,用于处理JobRemoved信号。

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

5) 使用代理启动systemd服务。此操作返回成功,我可以看到该单元启动并运行了一两秒钟后终止。

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

6) systemd 生成 JobRemoved 信号。dbus-monitor 显示它。


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) 我的信号处理程序从未被调用。(一切都使用系统总线,没有其他总线)。我尝试了各种字符串作为g_signal_connectdetailed_signal第二个参数(如:JobRemovedjob_removed::job-removed,有些被g_signal_connect不接受)。

非常感谢您的帮助!


我在使用g_signal_connect时遇到了同样的问题,即信号命名要求与XML内省文件不匹配。我的信号名称为“TechnologyAdd”,但必须使用“technology-added”。对我来说,这似乎是纯粹的部落知识。 - Joel Cunningham
1个回答

3
解决方案是在我的程序中使用glib事件循环。我的程序没有运行GMainLoop,这是从glib获取任何回调所必需的。这不是一种优雅的方式,但由于各种原因,我决定生成一个新线程,然后在其中阻塞g_main_loop_run。以下是代码示例。
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
}

我还需要修复我的信号处理程序签名,以便与接收有意义参数的信号兼容。

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接