https://bugs.kde.org/show_bug.cgi?id=359611

--- Comment #43 from [email protected] ---
Created attachment 197263
  --> https://bugs.kde.org/attachment.cgi?id=197263&action=edit
Symbolized backtraces: main and QDBusConnection threads

-Same permanent hang here, on Kubuntu 26.04, reached through a different
caller of retrieveInitialProperties(). That suggests the problem is in the
blocking call itself rather than in AccessPoint.

Versions: Plasma 6.6.6 (plasma-nm 4:6.6.6-0ubuntu0.1), KF 6.24.0
(libkf6networkmanagerqt6 6.24.0-0ubuntu1), Qt 6.10.2+dfsg-7, Wayland.
I diffed networkstatus.cpp, manager.cpp, vpnconnection.cpp and
qdbuspendingcall.cpp against current master/dev, and the code involved is
unchanged.

Trigger: resume from suspend at 13:50:27, then NetworkManager re-activated
Wi-Fi at 13:50:31. The panel was frozen from then on. I aborted plasmashell
about 8 minutes later to get a core. It was not a busy loop: the main thread
used 0 CPU.

Main thread (symbolized with Ubuntu dbgsym packages; full text attached):

  #15 QDBusPendingCallPrivate::waitForFinished   qdbuspendingcall.cpp:207
  #16 QDBusConnectionPrivate::sendWithReply      qdbusintegrator.cpp:2073
  #17 QDBusConnection::call (mode=QDBus::Block, timeout=-1)
  #18 NetworkManagerPrivate::retrieveInitialProperties   manager.cpp:259
  #19 VpnConnection::VpnConnection          vpnconnection.cpp
  #20 NetworkManagerPrivate::findRegisteredActiveConnection
  #21 NetworkManagerPrivate::activeConnections        manager.cpp:979
  #23 NetworkStatus::activeConnectionsChanged         plasma-nm
libs/networkstatus.cpp:107

So the entry point here is the active-connection list changing, not
accessPointAdded(). activeConnections() constructs a VpnConnection, which
NM-Qt uses for every active connection, for a path it has registered but
not yet built, and that constructor does the synchronous GetAll. There are
no VPN connections on this machine.

Stalled call and connection state, from the core:

  - sentMessage: org.freedesktop.NetworkManager
      /org/freedesktop/NetworkManager/ActiveConnection/9
      org.freedesktop.DBus.Properties.GetAll
  - pcall->pending is non-null, so QDBusConnectionPrivate::sendInternal()
    ran on the D-Bus thread and dbus_connection_send_with_reply() succeeded.
  - pcall->replyMessage.type() == InvalidMessage: no reply or error was ever
    delivered.
  - The QDBusConnectionPrivate has exactly 1 entry in `timeouts` and 1 in
    `watchers`.
  - The QDBusConnectionManager thread is idle in its event loop
    (QThread::exec -> QEventDispatcherGlib::processEvents -> ppoll), the same
    as in comment 3. So this isn't a lock-order deadlock between the threads.

A possible lead: plasmashell's only log line at the moment of the freeze
(13:50:31, the second Wi-Fi re-activated) was

  QSocketNotifier: Socket notifiers cannot be enabled or disabled from another
thread

qDBusToggleWatch() (qdbusintegrator.cpp:251) calls
QSocketNotifier::setEnabled() on the connection's watch notifiers and only
Q_ASSERTs that it runs on the D-Bus thread, which isn't checked in release
builds. If libdbus invokes the toggle callback from another thread, the
notifier change is refused with exactly this warning, and the connection's
read notifier could be left disabled. I haven't proven that this is the
warning's source, and it doesn't by itself explain why the 25 s libdbus
timeout also never fires. Do the other reporters have the same warning in
their journals around the start of the hang?

Separately from the root cause: QDBusPendingCallPrivate::waitForFinished()
waits on the condition variable with no deadline and depends entirely on
the D-Bus thread to deliver the reply or the timeout. Once that delivery is
lost, nothing can recover the call, so the GUI thread hangs forever instead
of for 25 s. Moving retrieveInitialProperties() (or its callers on the GUI
thread) to asyncCall() would avoid freezing the whole panel whatever the
underlying cause turns out to be.

Recovery for anyone hitting this: "systemctl --user kill -s KILL
plasma-plasmashell.service" (the unit has Restart=on-failure). A plain
restart waits for the 40 s stop timeout, because the hung main loop can't
handle SIGTERM.

-- 
You are receiving this mail because:
You are watching all bug changes.

Reply via email to