Skip to content

Core thread should never block indefinitely on a synchronous accessibility call when an application hangs #20169

@heath-toby

Description

@heath-toby

Problem

When a single application stops responding, NVDA's core thread blocks on synchronous cross-process accessibility calls into it, freezing NVDA itself — sometimes until the app is killed or NVDA is restarted. This is the deeper, architectural layer behind #16749 and the long-standing #1408.

Evidence (observed blocking call sites, all on the core thread)

  • UIA client: IUIAutomation::ElementFromHandleBuildCache / getFocusedElementBuildCache; UiaHasServerSideProvider (per-winEvent, cache-miss).
  • MSAA: IAccessible::accParent during the focus ancestor walk; oleacc.AccessibleObjectFromEvent for shell/ghost windows entangled with a hung UIA app (observed ~65s freeze).
  • Word object model: nvdaInProcUtils_winword_getTextInRange on a huge "select-all → delete".
  • The generic NVDAObject property pipeline (_getPropertyViaCache → app getters): e.g. isProtected, name, states.

Root cause

NVDA's object model fetches data by calling synchronously into the application from the core thread; the only backstop is the watchdog's multi-second cancel, which is slow and repeats — so a single hung application serialises NVDA.

Proposed approach (incremental, in-pattern)

  • Add an optional bounded timeout to the existing watchdog.cancellableExecute / CancellableCallThread (default unchanged) — a small, reusable primitive: the core waits at most N seconds, then abandons the call exactly like a watchdog cancel.
  • Adopt it at the blocking chokepoints (UIA client calls, AccessibleObjectFromEvent, winword text retrieval), with a per-subsystem "client jammed" breaker plus exponential backoff.
  • A near-zero-cost shared "hung mode" signal gating a central NVDAObject._getPropertyViaCache guard so that, only for a not-responding application's own objects, properties serve cached-or-None instead of blocking. Normal operation is byte-identical.

Scope / known limitations

This keeps NVDA responsive and self-recovering when an application hangs. It does not make UIA-only surfaces (e.g. the Windows 11 Alt+Tab switcher) readable while a UIA application jams the shared UIA client — that is an inherent Microsoft UI Automation limitation, present in stock NVDA too. Known pre-existing trade-offs amplified by the short timeout (abandoned-worker thread/handle churn under a permanent hang; byref buffers handed to an abandoned worker) are called out for discussion in the accompanying pull request.

Relates to

#16749, #1408

A pull request implementing this incrementally (stacked on #20168) will follow.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bug/freezep3https://github.com/nvaccess/nvda/blob/master/projectDocs/issues/triage.md#prioritytriagedHas been triaged, issue is waiting for implementation.

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions