Repository navigation
Conversation
A nested run loop started from inside an event handler (a modal NSAlert or NSOpenPanel, a drag-tracking session) runs the main run loop's sources and queued blocks re-entrantly. Two of them called the application handler there and panicked with "tried to handle event while another event is currently being handled": - the event loop proxy's source, which is in the common modes and so fires in a modal panel's run loop when another thread calls wake_up(); - the blocks maybe_queue_with_handler queues while the handler is in use, which a nested run loop in the default mode runs. Keep such calls and make them, in order, once the outer handler has returned; several proxy wake-ups are delivered as one. As they may come after about_to_wait, the run loop is woken so another pass follows and the application still hears about_to_wait last before it waits. Fixes rust-windowing#3992.
alesproch
force-pushed
the
appkit-nested-run-loop-reentrancy
branch
from
October 24, 2026 17:06
f4c2d52 to
f820012
Compare
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #3992.
The problem
A nested run loop started from inside an event handler (a modal
NSAlertorNSOpenPanel, e.g.rfd's synchronous dialogs, or a drag-tracking session)runs the main run loop's sources and queued blocks re-entrantly. On
master,two of them call the application handler there, and
EventHandler::handlepanics with "tried to handle event while another event is currently being
handled":
so it also fires in a modal panel's run loop
(
NSModalPanelRunLoopMode). Any thread that callsEventLoopProxy::wake_upwhile a modal panel opened from a handler is upcrashes the application.
maybe_queue_with_handlerqueues an event AppKit reports while the handleris in use as a block in the default mode. A nested run loop in the default
mode, such as the one a drag-tracking session runs
(
-[NSRunLoop runUntilDate:]underNSCoreDragTrackingProc, as reported inMacOS panic: "tried to handle event while another event is currently being handled" #3992), runs that block and calls the handler.
(The default-mode-only queueing already keeps modal panels out of the second
path since #1779; the first path, and nested loops in the default mode, were
still open.)
The fix
AppStatekeeps a call that arrives while the handler is in use, instead ofmaking it, and makes the kept calls in order once the outer handler has
returned (
with_handlerdrains them). Several proxy wake-ups are delivered asone. Because the kept calls may be delivered after
about_to_wait, the runloop is woken afterwards, so another pass follows and the application still
hears
about_to_waitlast before the loop waits.This is direction (a) of the analysis posted in #3992 on 2026-10-21.
Tests
Two regression tests in
winit-appkit/tests(harness = false, as they needthe main thread), run by the existing
cargo test -p winit-appkitCI step:proxy_wake_in_nested_run_loop: another thread callswake_upwhile ahandler runs the run loop in
NSModalPanelRunLoopMode;queued_event_in_nested_run_loop: a handler resizes its window (AppKitreports the resize, winit queues
SurfaceResized) and then runs the runloop in the default mode.
Both panic on
masterand pass with the fix; each also checks that theapplication hears
about_to_waitafter the deferred call.Tested on macOS 26.6.2 (Apple silicon):
cargo test -p winit-appkit,cargo clippy -p winit-appkit --all-targets -- -Dwarnings(one findingalready on
master,clippy::let_and_returninevent_loop.rs:331withclippy 1.93, unrelated),
cargo +nightly fmt --all -- --check.changelogmodule if knowledge of this changecould be valuable to users
notes of platform-specific behavior (no API change)
this functionality (the tests are the reproductions)