Skip to content

fix(inhibitor): use a private system bus connection and reconnect when closed - #5272

Open
ravi-arnan wants to merge 1 commit into
Alexays:masterfrom
ravi-arnan:fix-inhibitor-dbus-reconnect
Open

fix(inhibitor): use a private system bus connection and reconnect when closed#5272
ravi-arnan wants to merge 1 commit into
Alexays:masterfrom
ravi-arnan:fix-inhibitor-dbus-reconnect

Conversation

@ravi-arnan

Copy link
Copy Markdown

What does this PR do?

The inhibitor module took its connection from g_bus_get_sync(), which returns the process-wide shared system bus, and its destructor called g_dbus_connection_close_sync() on it. Destroying an Inhibitor therefore closes the shared connection for the whole process, and GLib keeps handing that same closed connection back to every later g_bus_get_sync() caller, so the Inhibitor built for the next bar starts life holding a dead connection with no way to get a live one. Every toggle then fails with The connection is closed until waybar is restarted.

A bar is destroyed and rebuilt whenever its output goes away and comes back (Client::handleDeferredMonitorRemoval), which is what happens across suspend/resume. That is why #5260 shows up after a sleep.

This opens a private system bus connection that the module owns and may legitimately close, and re-establishes it when it is found closed.

Related issues

Closes #5260

How to reproduce and verify

No suspend needed, cycling the output is enough. Bar with only the inhibitor module, systemd-inhibit --list as ground truth for whether the lock was really taken, clicks injected through the compositor rather than by hand:

niri msg output eDP-1 off; sleep 3; niri msg output eDP-1 on
step master (d561b9d) this branch
click the module lock held lock held
click again released released
output off, then on bar removed, bar reconfigured bar removed, bar reconfigured
click the module no lock lock held
log at that click g_dbus_connection_call_with_unix_fd_list_sync() failed: The connection is closed + cannot get inhibitor locks nothing

Why the connection can never be re-acquired on master

A short GIO program on the same machine: take the shared system bus, close it the way the destructor does, iterate the main context, ask for it again. GLib returns the identical pointer with is_closed = 1, so "just call g_bus_get_sync() again" is not a fix. That is what makes a private connection the right shape here.

Second case, a genuine peer-side drop

Running waybar against a pass-through dbus proxy and killing the proxy, again with only the inhibitor module configured:

master this branch
bus connection dropped waybar exits (g_bus_get_sync() connections have exit-on-close) waybar stays up
click after the bus is back n/a lock held

Worth stating precisely: waybar surviving that drop is a property of this test config. Other modules still take the shared bus through g_bus_get_sync(), so a real config with them present will still exit on a bus drop. Nothing here changes that, it only stops the inhibitor from breaking the shared connection for everyone else.

Checklist

  • Code is formatted with clang-format (--dry-run --Werror clean on both touched files)
  • Builds locally (ninja -C build)
  • Man page updated for any new/changed user-facing option (not applicable, no config surface changes)
  • Tested against the affected module(s) (meson test -C build: 3/3 ok, plus the two live A/B runs above)

Tested on NixOS 26.11, GLib 2.88.3, GTK 3, niri 26.04, single output.

…n closed

The module took its connection from g_bus_get_sync(), which returns the
process-wide shared system bus, and its destructor closed that connection.
Destroying an Inhibitor therefore closes the shared connection for the whole
process, and GLib keeps handing the same closed connection back to every later
g_bus_get_sync() caller, so the module built for the next bar can never take a
lock again: every toggle fails with "The connection is closed" until waybar is
restarted.

A bar is destroyed and rebuilt whenever its output goes away and comes back
(Client::handleDeferredMonitorRemoval), which is what happens across
suspend/resume, so the inhibitor stops working after a sleep.

Open a private connection that the module owns and may close, and re-establish
it when it is found closed.

Closes Alexays#5260
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

inhibitor module retains closed D-Bus connection after resume

1 participant