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

VJ-*_*VJ- 7 dbus systemd gdbus

使用gdbus-codegen生成的管理器代理时,我无法接收系统DBus信号.但我能够成功调用systemd提供的方法而不是DBus.

我在线搜索并查看这些链接但没有取得多大成功.当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>
Run Code Online (Sandbox Code Playgroud)

...略

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);
Run Code Online (Sandbox Code Playgroud)

3)定义信号处理程序

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

4)将一个信号处理程序连接到JobRemoved信号的代理.

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

5)使用代理启动systemd服务.这会返回成功,我可以看到设备启动并运行一两秒并终止.

ret = systemd_manager_call_start_unit_sync(
    systemdProxy, unit_name, unit_mode, &job_obj,
    NULL, &error);
Run Code Online (Sandbox Code Playgroud)

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"
Run Code Online (Sandbox Code Playgroud)

7)我的信号处理程序永远不会被调用.(一切都使用系统总线,没有其他公共汽车).我曾尝试各种字符串detailed_signal第二个参数g_signal_connect(如:JobRemoved,job_removed,::job-removed,一些不被接受g_signal_connect).

任何帮助是极大的赞赏!

VJ-*_*VJ- 3

解决方案是在我的程序中使用 a glib event loop。我的程序没有运行,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
}
Run Code Online (Sandbox Code Playgroud)

此外,我还必须修复信号处理程序签名,使其与信号兼容才能接收有意义的参数。

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