我需要将使用 sdbus-cpp 编写的一些代码与我的应用程序的事件循环集成,即 GLib 的 GMainLoop。
sdbus-cpp 的
IConnection
接口声明了 getEventLoopPollData()
函数,根据其文档,该函数应该恰好起到此作用。但是,没有给出与 GMainLoop 集成的示例,并且我在 GitHub 上找不到任何在 GLib 应用程序中使用它的项目。
有人对如何实施集成有一些提示,或者更好的是,有一些可以共享的工作代码吗?
最困难的部分是该函数应返回的
PollData
结构与 GMainContext 的 API 并不真正紧密匹配,而且我发现两个不同的文件描述符字段(fd
和 eventFd
)的存在特别令人困惑.
您需要创建一个 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;
}