https://bugs.kde.org/show_bug.cgi?id=527147
steven <[email protected]> changed: What |Removed |Added ---------------------------------------------------------------------------- CC| |[email protected] --- Comment #2 from steven <[email protected]> --- Created attachment 197161 --> https://bugs.kde.org/attachment.cgi?id=197161&action=edit plasma-hang-bt I can add a second, fully symbolized hang site in the same teardown chain, captured red-handed during a deterministic login-race repro. The description's backtrace hangs in QQmlEngine (Qt6Quick frames); this one hangs one library over, in kguiaddons — and it is a true deadlock cycle, not just a slow join. Environment: Plasma 6.8.0 (plasma-workspace 6.8.0-1), Arch Linux, kernel 7.2.8-1-cachyos, Wayland session, kguiaddons 6.31.0-1.1. Repro: plasmashell starts at login (systemd user service); an autostart entry runs `plasmashell --replace` while the session's Wayland connection to KWin is still establishing. The old shell is told to quit, never finishes quitting, and the replacement process dies with "Failed to register name" because the old shell still holds org.kde.plasmashell. End state: frozen zombie shell, no new shell. From a settled session, every quit path (SIGTERM, D-Bus /MainApplication quit, --replace, unit stop) exits cleanly — verified across seven variants. The hang needs the quit to happen during session startup. Main thread of the hung shell (gdb attach; plasma-workspace-debug + libplasma-debug installed): Thread 1 (LWP 1103 "plasmashell"): #0 futex_wait_cancelled (libc) #1 futex_wait (libc) #2 pthread_cond_wait (libc) #3 (Qt6Core internal) #4 QThread::wait(QDeadlineTimer) libQt6Core #5 (local symbol, libKF6GuiAddons.so.6.31.0 +0x2b417) #6 (local symbol, libKF6GuiAddons.so.6.31.0 +0x2b472) #7 QObjectPrivate::deleteChildren() libQt6Core #8 QObject::~QObject() libQt6Core #9 main () at shell/main.cpp:223 plasma-workspace 6.8.0 main.cpp:223 is `return app.exec();` — the event loop already returned; the hang is in the destructor chain of the local QCoreApplication during unwinding. Same shape as the description's backtrace, but frames #5/#6 are in libKF6GuiAddons, not libQt6Quick. Frames #5/#6 are local (non-exported) symbols; I resolved them by offset against the shipped .so (symbolization note at the end). The only QThread wait() call site in kguiaddons 6.31.0 src/ is src/systemclipboard/waylandclipboard.cpp: WaylandClipboard::~WaylandClipboard() { if (m_thread && m_thread->isRunning()) { m_thread->requestInterruption(); m_thread->syncQueue(); m_thread->wait(); // line 631 — no deadline } } The thread being joined is also in the dump, and this is where it stops being a slow join and becomes a deadlock cycle: Thread 2 (LWP 1624 "QThread"): #0 syscall () libc #1 QBasicMutex::lockInternal() libQt6Core #2 QRecursiveMutex::tryLock(QDeadlineTimer) libQt6Core #3 (local symbol, libKF6GuiAddons.so.6) libKF6GuiAddons #4 (Qt6Core thread start) Thread 16 (LWP 1224 "WaylandEventThr"): #0 futex_wait_cancelled (libc) #1 pthread_cond_wait (libc) #2 QWaitCondition::wait(QMutex*, QDeadlineTimer) libQt6Core #3 (Qt6WaylandClient display roundtrip wait) libQt6WaylandClient #4 (Qt6WaylandClient event thread loop) Cycle: the main thread enters ~WaylandClipboard holding kguiaddons' internal mutex, then blocks in m_thread->wait(). Thread 2 (the clipboard's own worker thread) is blocked trying to lock that same mutex inside libKF6GuiAddons, so it can never reach thread completion. requestInterruption() sets a flag the blocked thread cannot observe; syncQueue() queues an event that is never processed. Neither side can make progress. Thread 16 (a Qt6WaylandClient ConnectionThread parked in a compositor roundtrip wait) is consistent with the connection being mid-establishment at quit time. Note the difference in log tells: the description's repro logs "qt.core.qobject.connect: QObject::disconnect: Unexpected nullptr parameter"; this repro's journal has no such line. Two hang sites, one failure mode: deadline-less QThread::wait() calls reached via ~app -> QObjectPrivate::deleteChildren(), where the joined thread is blocked on work that needs the main thread (or a compositor reply that a young connection will never answer). Suggested fix directions: 1. WaylandClipboard::~WaylandClipboard(): give wait() a deadline (e.g. wait(5000)) and abandon/detach the thread on timeout. 2. Break the lock cycle: do not hold kguiaddons' internal mutex across the join, or have the worker's sync path check the interruption flag before taking the lock. 3. Audit the other deadline-less joins in the same teardown chain (the QQmlEngine site from the description, and KKeySequenceRecorder's threaded-connection pattern) — fixing one site will not close this bug. Symbolization note: the repo kguiaddons-debug (6.31.0-1) does not match the shipped kguiaddons 6.31.0-1.1 (gdb CRC mismatch), so kguiaddons frames show as ?? in gdb. I resolved them manually: exec segment base from /proc/<pid>/maps, eu-addr2line + nearest dynsym below the offsets. Full 17-thread backtrace attached. -- You are receiving this mail because: You are watching all bug changes.
