Skip to content

Yield from dispatcher more eagerly during shutdown - #22240

Merged
MrJul merged 1 commit into
mainfrom
fixes/dispatcher-eager-shutdown
Sep 15, 2026
Merged

MrJul merged 1 commit into
mainfrom
fixes/dispatcher-eager-shutdown

Conversation

@kekekeks

Copy link
Copy Markdown
Member

WPF:

  • dispatcher op calls Shutdown, ShutdownStarted called frames are cancelled
  • dispatcher yields back to WndProc<-DispatcheMessage<-PushFrameImpl
  • PushFrame sees that frame is cancelled and exits
  • once all frames exited -> all pending dispatcher ops are aborted
  • ShutdownFinished called

Avalonia:

  • dispatcher op calls Shutdown, ShutdownStarted called frames are cancelled
  • dispatcher drains any jobs in the queue before yielding (we do this because on some platforms yielding on every op has prohibitive costs on some platforms)
  • dispatcher yields back to WndProc<-DispatchMessage<-Win32DispatcherImpl::RunLoop
  • Win32DispatcherImpl::RunLoop sees that frame is cancelled and exits
  • once all frames exited -> all pending dispatcher ops are aborted
  • ShutdownFinished called

This PR makes dispatcher to yield on every operation once shutdown has started.

@kekekeks kekekeks added backport-candidate-11.3.x Consider this PR for backporting to 11.3 branch backport-candidate-12.1.x Consider this PR for backporting to 12.1 branch labels Sep 15, 2026
@MrJul MrJul added the bug label Sep 15, 2026
@avaloniaui-bot

Copy link
Copy Markdown

You can test this PR using the following package version. 12.2.999-cibuild0069978-alpha. (feed url: https://nuget-feed-all.avaloniaui.net/v3/index.json) [PRBUILDID]

@MrJul

MrJul commented Sep 15, 2026

Copy link
Copy Markdown
Member

Note: it's possible for users to see some slight differences in behavior after this PR.

For example:

if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktopLifetime)
    desktopLifetime.Exit += (_, _) => Dispatcher.Post(() => Console.WriteLine("Saving"));

If the shutdown was initiated from a dispatcher job, e.g. Dispatcher.Post(() => desktopLifetime.Shutdown()), this printed "Saving" before, while this isn't the case anymore after this PR.

However, in the sample above, the operation's execution has never been guaranteed. That code doesn't print anything today on main for a shutdown initiated outside an operation, for example by simply closing the main window.

@MrJul MrJul left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@MrJul
MrJul added this pull request to the merge queue Sep 15, 2026
Merged via the queue into main with commit 8797083 Sep 15, 2026
11 checks passed
@MrJul
MrJul deleted the fixes/dispatcher-eager-shutdown branch September 15, 2026 16:58
MrJul pushed a commit to MrJul/Avalonia that referenced this pull request Sep 22, 2026
@MrJul MrJul added backported-12.1.x and removed backport-candidate-12.1.x Consider this PR for backporting to 12.1 branch labels Sep 22, 2026
@coffeemuse coffeemuse mentioned this pull request Sep 23, 2026
1 of 6 tasks
grokys pushed a commit to Evan260/Avalonia that referenced this pull request Oct 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backport-candidate-11.3.x Consider this PR for backporting to 11.3 branch backported-12.1.x bug

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants