Skip to content

Failed refresh completion can synchronously block worker on UI thread

Summary

The background refresh completion path attempts async UI delivery with PostMessage, but falls back to SendMessage when posting fails while the window still appears valid. That lets a worker synchronously enter UI-owned completion handling during shutdown or queue pressure.

This is a critical Beta 0.7.3 blocker because it can deadlock the application when the UI thread is blocked waiting for shutdown progress, or it can run UI-affine state transitions from an unexpected worker call stack.

Evidence

  • srchybrid/GeoLocation.cpp:59-61 calls SendMessage from the worker after a failed PostMessage if IsWindow still returns true.
  • srchybrid/IPFilterUpdater.cpp:95-97 has the same worker-thread synchronous fallback.
  • The completion handlers mutate refresh/UI state that is intended to be owned by the UI thread.

Execution Plan

  1. Revalidate every GeoLocation and IPFilter completion path that can run from a background thread.
  2. Remove worker-thread SendMessage fallback for refresh completion.
  3. Define one asynchronous ownership transfer rule: successful post transfers context ownership to the UI thread; failed post performs terminal non-UI cleanup without calling UI handlers synchronously.
  4. If cleanup must touch UI-owned state, route it through a safe owner-owned cancellation/join mechanism from BUG-092 rather than a blocking worker call.
  5. Add a focused seam for failed PostMessage, blocked UI, and shutdown with a live worker.
  6. Verify refresh can be retried after failed delivery and after shutdown-safe cleanup.

Acceptance Criteria

  • No refresh worker calls SendMessage to deliver completion to the main UI.
  • Failed post delivery cannot deadlock on a blocked or shutting-down UI thread.
  • Completion context ownership is deterministic for post success and post failure.
  • GeoLocation and IPFilter manual/automatic refresh behavior remains compatible.
  • The item has commit evidence and targeted validation in this file before Beta 0.7.3.

Validation

  • 2026-05-08: Done in app commit 2823a5c.
  • python -m emule_workspace validate --workspace-root . passed.
  • python -m emule_workspace build app --workspace-root . --config Release --platform x64 --variant main passed; log root workspaces\v0.72a\state\build-logs\20260508-101728.
  • python -m emule_workspace build app --workspace-root . --config Debug --platform x64 --variant main passed; log root workspaces\v0.72a\state\build-logs\20260508-101749.
  • Code validation: GeoLocation and IPFilter refresh workers no longer call SendMessage when PostMessage fails. Failed completion delivery clears the shared refresh state and logs the dropped completion without blocking on the UI thread.