将 sdbus-cpp 与 GLib 事件循环集成

问题描述 投票:0回答:1

我需要将使用 sdbus-cpp 编写的一些代码与我的应用程序的事件循环集成,即 GLib 的 GMainLoop

sdbus-cpp 的

IConnection
接口声明了
getEventLoopPollData()
函数
,根据其文档,该函数应该恰好起到此作用。但是,没有给出与 GMainLoop 集成的示例,并且我在 GitHub 上找不到任何在 GLib 应用程序中使用它的项目。

有人对如何实施集成有一些提示,或者更好的是,有一些可以共享的工作代码吗?

最困难的部分是该函数应返回的

PollData
结构与 GMainContext 的 API 并不真正紧密匹配,而且我发现两个不同的文件描述符字段(
fd
eventFd
)的存在特别令人困惑.

glib event-loop
1个回答
0
投票

您需要创建一个 GSource,它将定期轮询从 sdbus::IConnection 接收的事件描述符并将其附加到 GMainContext

class EventSource
{
public:
    static EventSource *create(sdbus::IConnection &connection);
    static void destroy(EventSource *source);

    gboolean check() const;
    void dispatch();

private:
    GSource m_base;
    GPollFD m_pollFD;
    sdbus::IConnection *m_connection;
};


GSourceFuncs sourceFuncs = {
    /* prepare */
    [](GSource *, int *timeout) -> gboolean {
        *timeout = -1;
        return G_SOURCE_REMOVE;
    },
    /* check */
    [](GSource *gsource) -> gboolean {
        EventSource *source = (EventSource *) gsource;
        return source->check();
    },
    /* dispatch */
    [](GSource *gsource, GSourceFunc, gpointer) -> gboolean {
        EventSource *source = (EventSource *) gsource;

        try {
            source->dispatch();
            return G_SOURCE_CONTINUE;
        }
        catch (const sdbus::Error &err) {
            Log(Err) << "Failed to process dbus connection events (" << err << ")";
            return G_SOURCE_REMOVE;
        }
    },
    /* finalize */
    [](GSource *) {},
    nullptr,
    nullptr,
};

EventSource *EventSource::create(sdbus::IConnection &connection)
{
    EventSource *source = (EventSource *) g_source_new(&sourceFuncs, sizeof(EventSource));
    
    source->m_connection = &connection;
    source->m_pollFD.fd = connection.getEventLoopPollData().fd;
    source->m_pollFD.events = G_IO_IN;

    g_source_add_poll(&source->m_base, &source->m_pollFD);
    g_source_attach(&source->m_base, g_main_context_default());

    return source;
}

void EventSource::destroy(EventSource *source)
{
    g_source_remove_poll(&source->m_base, &source->m_pollFD);
    g_source_destroy(&source->m_base);
    g_source_unref(&source->m_base);
}

gboolean EventSource::check() const
{
    return m_pollFD.revents & G_IO_IN;
}

void EventSource::dispatch()
{
    while (m_connection->processPendingEvent()) {};
}

int main()
{
    std::unique_ptr<sdbus::IConnection> connection(createSessionBusConnection());
    std::unique_ptr<EventSource, void (*)(EventSource*)> source(EventSource::create(connection), &EventSource::destroy);

    GMainLoop *mainloop = g_main_loop_new(NULL, false);
    g_main_loop_run(loop);
    g_main_loop_unref(loop);

    return 0;
}
© www.soinside.com 2019 - 2024. All rights reserved.