CNA-BUG-164: HttpNotificationChannel's listener spins without backoff on a persistent accept error

CNA snapshot 3b43bd86  ·  Known Issues › Current bugs  ·  source links pinned to 3b43bd86

✓

Evidence basis: source-verified at the pinned commit; tests exist (not executed for this page). Claims on this page were checked by reading the CNA source at commit 3b43bd86; unless a sentence says otherwise, nothing here was built or executed. Nothing on this page was executed unless the Evidence section says so.

When accept fails while the channel is still listening (EMFILE or ENFILE when descriptors run out, ENOBUFS), the listener thread retries at once with no delay, so a persistent failure makes it loop at full speed.

Identifier
CNA-BUG-164
Category
Bug
Subsystem
Networking & gamer services
Status
Narrowed (partially fixed; describes only what survives)
Verified against
CNA 3b43bd86 (3b43bd8687ed46523d873f9bec4b32bd8481dcb5)
Severity
Low (a triage suggestion, not a project priority)
Evidence basis
Source-verified: read at TARGET, not executed
Tests touching this area
Yes: see Current tests
Affected contract
HttpNotificationChannel::Close() and the channel's internal listener thread

Expected behaviour

A failure the listener thread cannot recover from by retrying immediately should not consume a core: the worker should back off, or report the failure and stop.

Actual behaviour at TARGET

When accept returns an invalid socket while listening_ is still true, Listen continues its loop at once. EMFILE leaves the pending connection queued, so the next accept fails the same way and the loop spins at full speed until the condition clears. Not part of this entry: Open's plain if (listening_) check, which is not a compare-exchange; the header promises no thread safety for Open, and the Development page tells callers to keep Open and Close on one owning thread.

Source locations

Evidence

Checked by reading HttpNotificationChannel.cpp at 3b43bd86. Not executed.

Narrowed at c6dec91f: 20fe6efd2 (MUSEUM-PHONE-001, 2026-10-22) removed the data race this entry also described: the worker now receives the listening socket by value when it starts, and Close keeps that descriptor open until the worker has joined, so it can no longer be reused for an unrelated socket while the worker still uses it. The accept-error loop is unchanged.

Focused reproduction

No focused reproduction is known. Nothing has been invented here; the evidence above is what exists.

Current tests

notification_lifecycle_test.cpp exercises Close against idle, partial and complete connections (instrumented too when CNA is configured with CNA_SANITIZE=thread); descriptor exhaustion is not tested.

Regression test

A test that lowers RLIMIT_NOFILE while a channel is open, connects to it and checks that the worker backs off instead of spinning.

Blast radius

Processes with an open channel under descriptor or kernel buffer exhaustion; a normal channel is unaffected.

Workaround

No workaround is known.

The same subject is explained at several altitudes. These are the neighbouring pages at each one.

Maintainer workflow
Thread and callback map
Known issues
Bug index