On Linux the client opens its tray window during startup, and that window takes an X11 pointer and keyboard grab. Immediately afterwards the same (GUI) thread goes into FolderMan::setupFolders(), which opens the sync journal and creates the inotify watches synchronously. If the sync folder lives on slow storage that takes a while, and the grab just sits there for the whole time.
Effect is that the entire desktop stops accepting input. No clicks, no keystrokes, in any application. Everything keeps rendering β videos keep playing, the compositor and the shell are perfectly fine β they just never see any input events. Looks exactly like the machine has locked up.
My sync folder is on a 4-disk btrfs raid10 of spinning disks, 395 MB .sync_*.db, ~71k directories. Cold start gives me around 22 seconds of dead input. On an SSD it's probably short enough that people just see a flicker and never report it.
Steps to reproduce
- Put a large-ish sync folder on slow storage. To simulate a cold boot without rebooting, drop the journal from the page cache first:
posix_fadvise(fd, 0, 0, POSIX_FADV_DONTNEED) on .sync_*.db.
- Start the client.
- Try to click or type anywhere while it starts up.
Expected behaviour
Startup shouldn't take an input grab at all, and certainly shouldn't hold one across blocking I/O.
Client version / environment
nextcloud-client-git 34.0.1.r315.g8aaf6d1, Arch Linux, KDE Plasma on X11.
What I measured
The grab lines up exactly with the account restore:
14:56:36.060 [info] nextcloud.gui.account.manager accountmanager.cpp:719 Restored: 0 unknown certs.
14:56:57.889 [warning] nextcloud.gui.application application.cpp:722 Account(s) setup result: AccountsRestoreSuccess
I polled XGrabPointer/XGrabKeyboard from a separate process every 250 ms across startup. 87 of 252 samples came back AlreadyGrabbed for pointer and keyboard, covering 14:56:36 to 14:56:57 β the same window as above.
At the same time I polled /proc/<pid>/stat for Xorg, kwin_x11 and plasmashell: none of them ever left S state, so nothing was actually hung. Only the client sat in D/filemap_get_pages the whole time. Input simply had nowhere to go.
That also means a D-Bus based responsiveness check shows nothing β plasmashell answered introspection calls in 2 ms throughout. Took me a while to figure out I was measuring the wrong thing.
Cause
Systray::Systray() wires the popup to accountAdded:
https://github.com/nextcloud/desktop/blob/df75cd874/src/gui/systray.cpp#L170-L172
The comment above it says this is meant for the wizard, so that adding an account opens the tray centered rather than wherever the cursor happens to be. But accountAdded is also emitted by AccountManager::restore() during startup, so the popup opens on every single launch. Application::setupAccountsAndFolders() then continues into FolderMan::setupFolders() on the same thread and blocks there.
Suggested fix
Only open the popup for accounts added at runtime. I have a small patch here that adds a startupFinished flag to Systray, sets it at the end of setupAccountsAndFolders(), and returns early from the lambda before that point. Keeps the wizard behaviour, drops the startup grab. Happy to open a PR if that direction looks right.
The bigger issue underneath is that setupFolders() does blocking disk I/O on the GUI thread at all, but that's a much larger change and the grab is what turns it into a system-wide freeze.
On Linux the client opens its tray window during startup, and that window takes an X11 pointer and keyboard grab. Immediately afterwards the same (GUI) thread goes into
FolderMan::setupFolders(), which opens the sync journal and creates the inotify watches synchronously. If the sync folder lives on slow storage that takes a while, and the grab just sits there for the whole time.Effect is that the entire desktop stops accepting input. No clicks, no keystrokes, in any application. Everything keeps rendering β videos keep playing, the compositor and the shell are perfectly fine β they just never see any input events. Looks exactly like the machine has locked up.
My sync folder is on a 4-disk btrfs raid10 of spinning disks, 395 MB
.sync_*.db, ~71k directories. Cold start gives me around 22 seconds of dead input. On an SSD it's probably short enough that people just see a flicker and never report it.Steps to reproduce
posix_fadvise(fd, 0, 0, POSIX_FADV_DONTNEED)on.sync_*.db.Expected behaviour
Startup shouldn't take an input grab at all, and certainly shouldn't hold one across blocking I/O.
Client version / environment
nextcloud-client-git34.0.1.r315.g8aaf6d1, Arch Linux, KDE Plasma on X11.What I measured
The grab lines up exactly with the account restore:
I polled
XGrabPointer/XGrabKeyboardfrom a separate process every 250 ms across startup. 87 of 252 samples came backAlreadyGrabbedfor pointer and keyboard, covering 14:56:36 to 14:56:57 β the same window as above.At the same time I polled
/proc/<pid>/statforXorg,kwin_x11andplasmashell: none of them ever leftSstate, so nothing was actually hung. Only the client sat inD/filemap_get_pagesthe whole time. Input simply had nowhere to go.That also means a D-Bus based responsiveness check shows nothing β plasmashell answered introspection calls in 2 ms throughout. Took me a while to figure out I was measuring the wrong thing.
Cause
Systray::Systray()wires the popup toaccountAdded:https://github.com/nextcloud/desktop/blob/df75cd874/src/gui/systray.cpp#L170-L172
The comment above it says this is meant for the wizard, so that adding an account opens the tray centered rather than wherever the cursor happens to be. But
accountAddedis also emitted byAccountManager::restore()during startup, so the popup opens on every single launch.Application::setupAccountsAndFolders()then continues intoFolderMan::setupFolders()on the same thread and blocks there.Suggested fix
Only open the popup for accounts added at runtime. I have a small patch here that adds a
startupFinishedflag toSystray, sets it at the end ofsetupAccountsAndFolders(), and returns early from the lambda before that point. Keeps the wizard behaviour, drops the startup grab. Happy to open a PR if that direction looks right.The bigger issue underneath is that
setupFolders()does blocking disk I/O on the GUI thread at all, but that's a much larger change and the grab is what turns it into a system-wide freeze.