Skip to content

Main thread deadlock in is_zoomed() on macOS 26.x (Tahoe) via NSPerformVisuallyAtomicChange #1193

@axpnet

Description

@axpnet

Description

On macOS 26.2 (25C56) and 26.3 (25D125), the application window launches but becomes completely unresponsive. The main thread is stuck in a permanent deadlock during window initialization. All UI interaction (including traffic light buttons) is frozen.

Reproduced on two separate Apple Silicon machines (Mac Studio, MacBook Air) with tao 0.34.5.

Call stack (from /usr/bin/sample)

Both samples show the same deadlock:

main thread
  tao::platform_impl::platform::event_loop::EventLoop<T>::run
    -[NSApplication run]
      tao::platform_impl::platform::observer::control_flow_end_handler
        tao::platform_impl::platform::app_state::AppState::cleared
          EventLoopHandler<T>::handle_user_events
            handle_user_message
              tao::..::UnownedWindow::is_zoomed
                tao::..::util::async::set_style_mask_sync
                  -[NSWindow setStyleMask:]
                    NSPerformVisuallyAtomicChange   <-- blocked here

The NSPerformVisuallyAtomicChange call recurses 8+ levels deep through the view hierarchy:

NSPerformVisuallyAtomicChange  (setStyleMask)
  [NSWindow _setFrameCommon:display:fromServer:]
    _layoutViewTree
      NSPerformVisuallyAtomicChange  (level 2)
        _layoutSubtreeIfNeededAndAllowTemporaryEngine
          NSPerformVisuallyAtomicChange  (level 3)
            _layoutSubtreeWithOldSize
              NSPerformVisuallyAtomicChange  (level 4)
                ... up to level 8+

The main thread never returns to the run loop.

Root cause

is_zoomed() calls set_style_mask_sync(), which temporarily modifies and restores the window style mask via [NSWindow setStyleMask:]. In macOS 26, Apple added heavy WindowServer synchronization inside NSPerformVisuallyAtomicChange, making this save/modify/restore pattern deadlock on the main thread due to recursive layout passes.

This is a known breaking change in macOS 26. Other projects hit the same issue:

Suggested fix

Avoid calling [NSWindow setStyleMask:] inside is_zoomed(). The kitty/GLFW fixes use alternative approaches that don't trigger style mask changes.

Related

Possibly related to #1171 (crash on macOS 26 in did_finish_launching), though the symptom there is a panic rather than a deadlock.

Environment

  • macOS: 26.2 (25C56), 26.3 (25D125)
  • Hardware: Apple Silicon (M1, M3 Pro)
  • tao: 0.34.5
  • Rust: stable

Sample files

Full /usr/bin/sample outputs from two machines are available in aeroftp#47.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions