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

标签 dbus systemd gdbus

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

我在网上搜索并查看了这些链接,但没有取得多大成功。当 gdbus-codegen 用于 systemd API 时,没有太多关于如何做到这一点的示例。

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

1) 我生成了 systemd 自省(introspection)并使用该 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 接受)。

非常感谢任何帮助!

最佳答案

解决方案是在我的程序中使用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");
}

关于dbus - 使用 gdbus-codegen 连接到 systemd DBUS 信号,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29382301/

相关文章:

c - 使用 C 强制立即处理 Glib 中的事件

build - Docker作为构建器,无法安装systemd头文件

ruby-on-rails - 如何让 systemd 使用 Puma 重启 Rails App

c++ - 使用 gdbus-codegen 生成的代码时如何堵塞内存泄漏?

dbus - 如何使用 dbus-send 设置变体数组?

c++ - 从 DBUS 获取发送者 PID

gnome - 用 Onboard -> Hide/Show via DBus 替换 Gnomes 虚拟键盘不起作用

bluetooth - 无法通过 DBus 在 Bluez 中设置 SSP 模式

java - Java-DBus 中的 GSList* 是什么?

docker - 在 ubuntu14.04 docker 容器中安装 systemd - 这可能吗?