Skip to content

AICH sync thread concurrency — multiple unsynchronized shared-state accesses

Historical reference only: stale-v0.72a-experimental-clean and analysis\stale-v0.72a-experimental-clean are retired reference sources, not active branch targets or current baselines. Use them only as provenance or idea-extraction sources; landed status is determined against main. See Historical References.

Summary

The AICH sync thread (CAICHSyncThread) accesses shared state with insufficient synchronization in several dimensions:

1. UI deadlock + hash starvation (9770d3d)

CAICHSyncThread calls PostMessage and waits for completion from the main window while holding locks that the UI thread may also try to acquire. Under load this produces a deadlock cycle: hasher holds a file-list lock and waits for UI ack; UI processes other messages that also need the file-list lock.

A related starvation path exists where the AICH maintenance loop runs at higher-than-expected frequency and starves download/upload threads of I/O time.

Files affected: srchybrid/AICHSyncThread.cpp, srchybrid/EmuleDlg.cpp, srchybrid/DownloadClient.cpp, srchybrid/PartFile.cpp, srchybrid/UploadClient.cpp (+228/-27 in experimental, 13 files)

2. AICH sync thread concurrency — bounded maintenance wait (c3d0a47)

CAICHSyncThread performs AICH tree maintenance operations without a bounded wait before re-entering its main loop. The fix bounds the maintenance sleep, reduces lock hold time, and ensures the sync state machine is consistent.

Files affected: srchybrid/AICHSyncThread.cpp (+156/-39 lines), srchybrid/AICHSyncThread.h

3. Incomplete/duplicate AICH tree nodes (ad705b0, 10fdc85)

AICH tree serialization/deserialization can encounter: - Incomplete nodes (partial subtrees stored on crash/abort): ad705b0 normalize incomplete AICH tree nodes - Duplicate stored hash entries: 10fdc85 tolerate duplicate stored AICH hashes (CPP_032/CPP_035)

These cause AICH verification failures on reload even when the underlying file data is correct.

Files affected: AICH hash-set storage and loading paths (kademlia + PartFile vicinity)

Location

  • srchybrid/AICHSyncThread.cpp / AICHSyncThread.h
  • srchybrid/PartFile.cpp
  • srchybrid/EmuleDlg.cpp, srchybrid/DownloadClient.cpp, srchybrid/UploadClient.cpp
  • Seam headers in experimental: AICHSyncThreadSeams.h, DisplayRefreshSeams.h

Experimental Reference Implementation

Status: All four aspects fixed in experimental: - 9770d3d FIX: prevent runtime UI deadlocks and hash starvation (2026) - c3d0a47 FIX: harden AICH sync thread concurrency (2026) - ad705b0 BUG CPP_032 CPP_035 normalize incomplete AICH tree nodes (2026) - 10fdc85 BUG CPP_032 CPP_035 tolerate duplicate stored AICH hashes (2026)

The approach for the UI deadlock: replace blocking PostMessage+wait with the QueueDisplayUpdate / DISPLAY_REFRESH_* message pattern, allowing the AICH thread to post updates without waiting for UI ack. The AICH maintenance loop now uses a bounded interrupt-able sleep rather than WaitForSingleObject(INFINITE).

For duplicate/incomplete nodes: add skip-and-heal logic during tree load instead of hard failing; normalize subtrees to a known-valid empty state when partial data is detected.

Main Branch Port Status

Status: Done in main

The staged branch port was squash-merged to main as:

  • 6e466d2 BUG-019 harden AICH sync concurrency
  • 5d8346c BUG-019 add AICH sync hardening regressions
  • bfebdd2 BUG-019 update AICH sync hardening tracking

Current branch behavior:

  • Duplicate stored AICH hashes are tolerated during load instead of hard-failing the index.
  • Incomplete tree nodes are normalized to a safe invalid state during repair/load.
  • AICH maintenance waits are bounded and cooperative rather than effectively unbounded.
  • AICH worker-thread display updates are routed through queued QueueDisplayUpdate / DispatchQueuedDisplayUpdate handoff instead of waiting on synchronous UI acknowledgment.

Current branch implementation notes:

  • Shared-state and maintenance logic use the existing AICHMaintenanceSeams and AICHSyncThreadSeams seam vocabulary already present on main.
  • UI refresh routing now uses DisplayRefreshSeams, UM_PARTFILE_DISPLAY_UPDATE, and UM_CLIENT_DISPLAY_UPDATE to queue part-file/client refresh work back to the main thread.
  • The queued display-refresh path touches EmuleDlg, PartFile, DownloadClient, UploadClient, BaseClient, ListenSocket, and UploadQueue.

Regression coverage landed with the merge:

  • 5d8346c BUG-019 add AICH sync hardening regressions

Porting Note

The stale experimental branch remains the reference source for the original fixes, but the main branch now carries the staged ported behavior: isolated storage/tree-healing, bounded sync waits, and queued display refresh handoff.

Relationship to Existing Items

  • BUG-018 (part-file hash layout drift): BUG-018 covers the hasher thread; BUG-019 covers the AICH sync thread.
  • BUG-003 (AICH FIXME markers): BUG-003 tracks incomplete large-file AICH paths via FIXME markers; BUG-019 tracks runtime concurrency issues in the existing paths.