The*_*eJJ 5 c++ dbus libuv systemd
我们有一个事件循环来libuv处理 unixsockets 和 TCP 套接字。sd-bus该程序现在还必须处理 DBus,我们决定为此使用。
伦纳特在他的博客上写道:
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.
Run Code Online (Sandbox Code Playgroud)
所以我认为,这一定是可能的。
fd我可以通过获取 dbus 套接字sd_bus_get_fd (sd_bus *bus)。但我找不到任何明显的方法来阻止 sd-bus 使用其bus_poll方法在内部等待事件。
例如,当调用方法时,sd_bus_call(...) 将阻塞ppoll。
那么:如何处理 libuv 中的 dbus 事件?
我明白了,这是一个关于如何联合 C++、libuv 和 sd-bus 的示例:
\n\n我建议您阅读http://0pointer.de/blog/the-new-sd-bus-api-of-systemd.html以大致了解 sd-bus 。
\n\n这些是我的实现中的代码片段https://github.com/TheJJ/horst实现的代码片段
\n\n然后可以使用sd_bus_call_async不阻塞的方法调用(与 相反sd_bus_call)。\n不要忘记update_events()在之后调用sd_bus_call_async,以便通过套接字发送调用!
/**\n * Callback function that is invoked from libuv\n * once dbus events flowed in.\n */\nstatic void on_dbus_ready(uv_poll_t *handle, int /*status*/, int /*events*/) {\n DBusConnection *connection = (DBusConnection *)handle->data;\n\n sd_bus *bus = connection->get_bus();\n\n // let dbus handle the available events request\n while (true) {\n // this will trigger the dbus vtable-registered functions\n int r = sd_bus_process(bus, nullptr);\n\n if (r < 0) {\n printf("[dbus] Failed to process bus: %s", strerror(-r));\n break;\n }\n else if (r > 0) {\n // try to process another request!\n continue;\n }\n else {\n // no more progress, wait for the next callback.\n break;\n }\n }\n\n // update the events we watch for on the socket.\n connection->update_events();\n}\n\n/**\n * Convert the sdbus-returned poll flags to\n * corresponding libuv flags.\n */\nint poll_to_libuv_events(int pollflags) {\n int ret = 0;\n if (pollflags & (POLLIN | POLLPRI)) {\n ret |= UV_READABLE;\n }\n if (pollflags & POLLOUT) {\n ret |= UV_WRITABLE;\n }\n\n // we also have the non-corresponding UV_DISCONNECT\n\n return ret;\n}\n\n\nclass DBusConnection {\npublic:\n DBusConnection(Satellite *sat);\n\n virtual ~DBusConnection() = default;\n\n /** connect to dbus */\n int connect() {\n int r = sd_bus_open_system(&this->bus);\n\n if (r < 0) {\n printf("[dbus] Failed to connect to bus: %s", strerror(-r));\n goto clean_return;\n }\n\n r = sd_bus_add_object_vtable(\n this->bus,\n &this->bus_slot,\n "/rofl/lol", // object path\n "rofl.lol", // interface name\n your_vtable,\n this // this is the userdata that\'ll be passed\n // to the dbus methods\n );\n\n if (r < 0) {\n printf("[dbus] Failed to install the horst sdbus object: %s", strerror(-r));\n goto clean_return;\n }\n\n // register our service name\n r = sd_bus_request_name(this->bus, "moveii.horst", 0);\n if (r < 0) {\n printf("[dbus] Failed to acquire service name: %s", strerror(-r));\n goto clean_return;\n }\n\n // register the filedescriptor from\n // sd_bus_get_fd(bus) to libuv\n uv_poll_init(this->loop, &this->connection, sd_bus_get_fd(this->bus));\n\n\n // make `this` reachable in callbacks.\n this->connection.data = this;\n\n // init the dbus-event-timer\n uv_timer_init(this->loop, &this->timer);\n this->timer.data = this;\n\n // process initial events and set up the\n // events and timers for subsequent calls\n on_dbus_ready(&this->connection, 0, 0);\n\n printf("[dbus] Listener initialized");\n return 0;\n\n clean_return:\n sd_bus_slot_unref(this->bus_slot);\n sd_bus_unref(this->bus);\n this->bus = nullptr;\n\n return 1;\n }\n\n\n\n /** update the events watched for on the filedescriptor */\n void update_events() {\n sd_bus *bus = this->get_bus();\n\n // prepare the callback for calling us the next time.\n int new_events = poll_to_libuv_events(\n sd_bus_get_events(bus)\n );\n\n uint64_t usec;\n int r = sd_bus_get_timeout(bus, &usec);\n\n if (not r) {\n // if the timer is running already, it is stopped automatically\n // inside uv_timer_start.\n uv_timer_start(\n &this->timer,\n [] (uv_timer_t *handle) {\n // yes, handle is not a poll_t, but\n // we just care for its -> data member anyway.\n on_dbus_ready((uv_poll_t *)handle, 0, 0);\n },\n usec / 1000, // time in milliseconds, sd_bus provides \xc2\xb5seconds\n 0 // don\'t repeat\n );\n }\n\n // always watch for disconnects:\n new_events |= UV_DISCONNECT;\n\n // activate the socket watching,\n // and if active, invoke the callback function\n uv_poll_start(&this->connection, new_events, &on_dbus_ready);\n }\n\n\n /** close the connections */\n int close() {\n // TODO: maybe this memoryerrors when the loop actually\n // does the cleanup. we have to wait for the callback.\n uv_close((uv_handle_t *) &this->timer, nullptr);\n\n uv_poll_stop(&this->connection);\n\n sd_bus_close(this->bus);\n sd_bus_slot_unref(this->bus_slot);\n sd_bus_unref(this->bus);\n return 0;\n }\n\n /**\n * Return the bus handle.\n */\n sd_bus *get_bus() const {\n return this->bus;\n }\n\nprotected:\n /**\n * loop handle\n */\n uv_loop_t *loop;\n\n /**\n * polling object for dbus events\n */\n uv_poll_t connection;\n\n /**\n * dbus also wants to be called periodically\n */\n uv_timer_t timer;\n\n /**\n * dbus bus handle\n */\n sd_bus *bus;\n\n /**\n * dbus slot handle\n */\n sd_bus_slot *bus_slot;\n};\nRun Code Online (Sandbox Code Playgroud)\n