CNA-BUG-164: HttpNotificationChannel's listener spins without backoff on a persistent accept error
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
modules/phone/src/HttpNotificationChannel.cpp— Listen (continue on a failed accept while listening_), Close (keeps the descriptor until the worker joined)tools/phone/notification_lifecycle_test.cpp— Close against idle, partial and complete connections; no descriptor exhaustion
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.
Related pages
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