gpt4 book ai didi

c++ - libuv 中 sd-bus 的事件循环处理

转载 作者:太空宇宙 更新时间:2023-11-04 13:08:52 25 4
gpt4 key购买 nike

我们有一个来自 libuv 的事件循环来处理 unixsockets 和 TCP 套接字。该程序现在还必须处理 DBus,为此我们决定使用 sd-bus

伦纳特 wrote on his blog :

Note that our APIs, including sd-bus, integrate nicely into sd-event
event loops, but do not require it, and may be integrated into other
event loops too, as long as they support watching for time and I/O events.

所以我想,这一定是可能的。

我可以通过 sd_bus_get_fd (sd_bus *bus) 获取 dbus 套接字 fd。但是我找不到任何明显的方法来阻止 sd-bus 使用其 bus_poll 方法在内部等待事件。

例如,当使用 sd_bus_call(...) 调用方法时 will blockppoll .

那么:我如何处理 libuv 中的 dbus 事件?

最佳答案

我明白了,这里有一个关于如何结合 C++、libuv 和 sd-bus 的例子:

我建议您阅读 http://0pointer.de/blog/the-new-sd-bus-api-of-systemd.html总体上了解 sd-bus。

这些是我在 https://github.com/TheJJ/horst 上实现的代码片段

然后可以使用不阻塞的 sd_bus_call_async 完成方法调用(与 sd_bus_call 相对)。不要忘记在 sd_bus_call_async 之后调用 update_events(),以便通过套接字发送调用!

/**
* Callback function that is invoked from libuv
* once dbus events flowed in.
*/
static void on_dbus_ready(uv_poll_t *handle, int /*status*/, int /*events*/) {
DBusConnection *connection = (DBusConnection *)handle->data;

sd_bus *bus = connection->get_bus();

// let dbus handle the available events request
while (true) {
// this will trigger the dbus vtable-registered functions
int r = sd_bus_process(bus, nullptr);

if (r < 0) {
printf("[dbus] Failed to process bus: %s", strerror(-r));
break;
}
else if (r > 0) {
// try to process another request!
continue;
}
else {
// no more progress, wait for the next callback.
break;
}
}

// update the events we watch for on the socket.
connection->update_events();
}

/**
* Convert the sdbus-returned poll flags to
* corresponding libuv flags.
*/
int poll_to_libuv_events(int pollflags) {
int ret = 0;
if (pollflags & (POLLIN | POLLPRI)) {
ret |= UV_READABLE;
}
if (pollflags & POLLOUT) {
ret |= UV_WRITABLE;
}

// we also have the non-corresponding UV_DISCONNECT

return ret;
}


class DBusConnection {
public:
DBusConnection(Satellite *sat);

virtual ~DBusConnection() = default;

/** connect to dbus */
int connect() {
int r = sd_bus_open_system(&this->bus);

if (r < 0) {
printf("[dbus] Failed to connect to bus: %s", strerror(-r));
goto clean_return;
}

r = sd_bus_add_object_vtable(
this->bus,
&this->bus_slot,
"/rofl/lol", // object path
"rofl.lol", // interface name
your_vtable,
this // this is the userdata that'll be passed
// to the dbus methods
);

if (r < 0) {
printf("[dbus] Failed to install the horst sdbus object: %s", strerror(-r));
goto clean_return;
}

// register our service name
r = sd_bus_request_name(this->bus, "moveii.horst", 0);
if (r < 0) {
printf("[dbus] Failed to acquire service name: %s", strerror(-r));
goto clean_return;
}

// register the filedescriptor from
// sd_bus_get_fd(bus) to libuv
uv_poll_init(this->loop, &this->connection, sd_bus_get_fd(this->bus));


// make `this` reachable in callbacks.
this->connection.data = this;

// init the dbus-event-timer
uv_timer_init(this->loop, &this->timer);
this->timer.data = this;

// process initial events and set up the
// events and timers for subsequent calls
on_dbus_ready(&this->connection, 0, 0);

printf("[dbus] Listener initialized");
return 0;

clean_return:
sd_bus_slot_unref(this->bus_slot);
sd_bus_unref(this->bus);
this->bus = nullptr;

return 1;
}



/** update the events watched for on the filedescriptor */
void update_events() {
sd_bus *bus = this->get_bus();

// prepare the callback for calling us the next time.
int new_events = poll_to_libuv_events(
sd_bus_get_events(bus)
);

uint64_t usec;
int r = sd_bus_get_timeout(bus, &usec);

if (not r) {
// if the timer is running already, it is stopped automatically
// inside uv_timer_start.
uv_timer_start(
&this->timer,
[] (uv_timer_t *handle) {
// yes, handle is not a poll_t, but
// we just care for its -> data member anyway.
on_dbus_ready((uv_poll_t *)handle, 0, 0);
},
usec / 1000, // time in milliseconds, sd_bus provides µseconds
0 // don't repeat
);
}

// always watch for disconnects:
new_events |= UV_DISCONNECT;

// activate the socket watching,
// and if active, invoke the callback function
uv_poll_start(&this->connection, new_events, &on_dbus_ready);
}


/** close the connections */
int close() {
// TODO: maybe this memoryerrors when the loop actually
// does the cleanup. we have to wait for the callback.
uv_close((uv_handle_t *) &this->timer, nullptr);

uv_poll_stop(&this->connection);

sd_bus_close(this->bus);
sd_bus_slot_unref(this->bus_slot);
sd_bus_unref(this->bus);
return 0;
}

/**
* Return the bus handle.
*/
sd_bus *get_bus() const {
return this->bus;
}

protected:
/**
* loop handle
*/
uv_loop_t *loop;

/**
* polling object for dbus events
*/
uv_poll_t connection;

/**
* dbus also wants to be called periodically
*/
uv_timer_t timer;

/**
* dbus bus handle
*/
sd_bus *bus;

/**
* dbus slot handle
*/
sd_bus_slot *bus_slot;
};

关于c++ - libuv 中 sd-bus 的事件循环处理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40871126/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com