Skip to content

fix(linux): bound the blocking calls on the I/O thread so close() always joins #16

Description

@Kitty-Hivens

SniTrayImpl.close() gives the I/O thread two seconds to stop and, if it is still alive after that, skips dbus_connection_close, dbus_connection_unref and the arena close, logging a warning instead. That was added in 0.1.3 because the alternative is worse: freeing the connection while the thread is inside a dbus_* call segfaults inside libdbus, and leaking one connection at shutdown does not.

It is a backstop, not a solution. The remaining paths that can hold the thread past the join budget are:

Consumer callbacks. fire invokes every onEvent handler on the I/O thread, so a handler that blocks blocks the loop. The Tray interface documents that handlers run on the backend's dispatch thread and that consumers should hop themselves, but "documented" is not "bounded".

dbus_connection_flush against a socket nobody is draining. Bounded in practice by the kernel buffer and the daemon, not by anything libtray controls.

Two directions. Handing events to consumers from a small executor rather than the I/O thread removes the first and changes the threading contract, which is a public-API decision. Replacing the blocking flush with dbus_connection_get_dispatch_status plus a non-blocking write loop removes the second at the cost of more state in the loop.

Until one of them lands, a consumer whose handler blocks for seconds gets a leaked connection at shutdown rather than a crash, which is the intended trade.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions