Skip to content

fix: base LatestFrameReader liveness on segment magic (namespace-safe)#3

Merged
DanielKow merged 1 commit into
masterfrom
fix/latest-frame-liveness-namespace-safe
Jul 9, 2026
Merged

fix: base LatestFrameReader liveness on segment magic (namespace-safe)#3
DanielKow merged 1 commit into
masterfrom
fix/latest-frame-liveness-namespace-safe

Conversation

@DanielKow

Copy link
Copy Markdown
Contributor

What

Fixes a cross-PID-namespace bug in LatestFrameReader::is_writer_alive() — the same container/host class as the read-only-open fix (#2).

The reader validated the producer with platform::process_exists(writer_pid). But writer_pid is the producer's pid in its own PID namespace — a displaysink producer runs as root inside a container, while the native-player consumer runs on the host. On the host, that container pid is a different process (or none), so process_exists() always returns false → is_writer_alive() reports the producer dead on every poll → the consumer's run loop churns into RECONNECTING between every frame (picture holds, but the status flickers).

Fix

Liveness is now the segment magic alone — the writer publishes LATEST_FRAME_MAGIC on create and invalidates it on clean close, both directly in the shared segment, so it's namespace-independent:

bool LatestFrameReader::is_writer_alive() {
    if (!_header) return false;
    return atomic_ref<uint32_t>(_header->magic).load(acquire) == LATEST_FRAME_MAGIC;
}

The process_exists/get_process_start_time pid checks are removed from the reader. The writer-side stale-segment reclaim (reclaim_stale_or_throw) still uses process_exists — that runs in the writer's own namespace (a new producer reclaiming a dead producer's segment), where pids are comparable, so it's unchanged. writer_pid/writer_start_time stay in the header for that path.

Trade-off (conscious)

Magic detects a clean close (writer invalidates magic) but not a producer that crashes without a clean close (magic stays valid). The old pid check nominally caught that — but it was already broken across the namespace boundary, so nothing is lost in the deployment that matters. Crash/hang detection for a non-cleanly-closed producer belongs in the consumer via frame staleness (frames stop advancing), which is likewise namespace-independent — a separate follow-up if needed.

Verification

  • cpp/build.sh green; test_latest_frame 18/18 pass — including WriterGoneReportedNoCrash (clean writer destruction → magic invalidated → correctly reports gone) and WriterRestartReaderRecovers.
  • Honest limit: the cross-UID/namespace case can't be reproduced in same-process CI (same as fix: LatestFrameReader opens the segment read-only (cross-privilege consumer) #2); validated by the live run — the reconnecting-status flicker is gone and the kiosk holds a steady stream. latest_frame.h untouched → wire-compatible; streamer's pinned zerobuffer needs no rebuild, only native-player.

🤖 Generated with Claude Code

@DanielKow
DanielKow merged commit d4bd402 into master Jul 9, 2026
4 of 5 checks passed
@DanielKow
DanielKow deleted the fix/latest-frame-liveness-namespace-safe branch July 9, 2026 17:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant