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

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 事件?

The*_*eJJ 2

我明白了,这是一个关于如何联合 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\n
/**\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};\n
Run Code Online (Sandbox Code Playgroud)\n