Skip to content

Fix sd-bus thread-safety crash in Linux tray (#405)#407

Merged
kdroidFilter merged 1 commit into
masterfrom
fix/sni-bus-thread-safety
Jun 17, 2026
Merged

Fix sd-bus thread-safety crash in Linux tray (#405)#407
kdroidFilter merged 1 commit into
masterfrom
fix/sni-bus-thread-safety

Conversation

@kdroidFilter

Copy link
Copy Markdown
Owner

Summary

Fixes #405Assertion '!bus->current_slot' failed at ... bus_process_internal(). Aborting.

sd-bus objects are not thread-safe. In sni.c the event-loop thread (sni_tray_runsd_bus_process) and the JVM threads driving every sni_tray_set_* / sni_tray_item_* / sni_tray_add_* mutator (→ sd_bus_emit_*) accessed the same tray->bus with zero synchronization. Under frequent icon/menu updates an emit races with an in-flight sd_bus_process and trips the internal current_slot assertion, aborting the process.

Changes

  • Add a bus_lock mutex that serializes all sd_bus_* access and the tray state it reads/writes — held across bus setup, each sd_bus_process batch, and teardown, and acquired by every public mutator.
  • Defer user callbacks (click / menu) through a queue that the event loop flushes after releasing bus_lock. This avoids holding the bus lock across an upcall into Kotlin, which would otherwise deadlock against the LinuxTrayManager ReentrantLock (lock inversion when a callback re-enters the mutators).
  • Add a standalone C concurrency regression test (test_sni_concurrency.c + run_concurrency_test.sh).

Test plan

  • Regression test aborts on the old code (exit 134, exact !bus->current_slot assertion)
  • Regression test passes on the fixed code: 16 runs × 200k contended rounds, zero crashes
  • build.sh rebuilds libLinuxTray.so clean with -Wall -Wextra (no new warnings)

Run the test: ./src/native/linux/run_concurrency_test.sh (uses a private dbus-run-session).

sd-bus objects are not thread-safe, but the event-loop thread
(sd_bus_process) and the JVM threads driving the sni_tray_set_*/
sni_tray_item_* mutators (sd_bus_emit_*) accessed tray->bus with no
synchronization. Under frequent updates an emit races with an in-flight
sd_bus_process and trips 'Assertion !bus->current_slot ... Aborting'.

- Add a bus_lock mutex serializing all sd_bus_* access and the tray
  state it touches: held across setup, each sd_bus_process batch and
  teardown, and acquired by every public mutator.
- Defer user callbacks (click / menu) through a queue flushed by the
  event loop after releasing bus_lock, so upcalls into Kotlin can
  re-enter the mutators without deadlocking against the caller's lock.
- Add a standalone C concurrency regression test that aborts on the
  old code and passes on the fixed code.
@kdroidFilter kdroidFilter merged commit 34dc9d1 into master Jun 17, 2026
@kdroidFilter kdroidFilter deleted the fix/sni-bus-thread-safety branch June 17, 2026 19:41
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.

Crash in bus_process_internal

1 participant