fix(fspy): replace the IPC file lock with an in-mapping close gate - #577
Open
wan9chi wants to merge 1 commit into
Open
fix(fspy): replace the IPC file lock with an in-mapping close gate#577wan9chi wants to merge 1 commit into
wan9chi wants to merge 1 commit into
Conversation
Member
Author
|
Warning This pull request is not mergeable via GitHub because a downstack PR is open. Once all requirements are satisfied, merge this PR as a stack on Graphite.
This stack of pull requests is managed by Graphite. Learn more about stacking. |
This was referenced Jul 28, 2026
wan9chi
force-pushed
the
fspy-sparse-file-shm
branch
from
July 28, 2026 11:06
4f029ee to
cfb9f15
Compare
fspy benchmarklinuxmacoswindows |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: eb42117817
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
wan9chi
force-pushed
the
fspy-sparse-file-shm
branch
from
July 28, 2026 11:18
cfb9f15 to
e67d3fa
Compare
wan9chi
force-pushed
the
fspy-sparse-file-shm
branch
from
July 28, 2026 11:20
e67d3fa to
b0ab415
Compare
wan9chi
force-pushed
the
fspy-sparse-file-shm
branch
from
July 29, 2026 01:22
b0ab415 to
73b40b8
Compare
wan9chi
force-pushed
the
fspy-sparse-file-shm
branch
from
July 29, 2026 02:14
73b40b8 to
941a231
Compare
wan9chi
force-pushed
the
fspy-sparse-file-shm
branch
from
July 30, 2026 01:42
941a231 to
5e527ad
Compare
wan9chi
force-pushed
the
fspy-sparse-file-shm
branch
from
July 30, 2026 02:14
5e527ad to
f572f0d
Compare
wan9chi
force-pushed
the
fspy-sparse-file-shm
branch
from
July 30, 2026 03:24
f572f0d to
ca1932a
Compare
wan9chi
force-pushed
the
fspy-sparse-file-shm
branch
from
July 30, 2026 03:43
ca1932a to
dcb74d7
Compare
wan9chi
force-pushed
the
fspy-sparse-file-shm
branch
from
July 30, 2026 03:48
dcb74d7 to
54dbb9b
Compare
wan9chi
force-pushed
the
fspy-sparse-file-shm
branch
from
July 30, 2026 03:51
54dbb9b to
126f02b
Compare
wan9chi
force-pushed
the
fspy-sparse-file-shm
branch
from
July 30, 2026 04:11
126f02b to
c86913c
Compare
wan9chi
force-pushed
the
fspy-close-gate
branch
2 times, most recently
from
July 30, 2026 04:36
38e7f20 to
5d642d1
Compare
wan9chi
changed the base branch from
graphite-base/577
to
agent/reapply-runner-fifo
July 30, 2026 06:12
wan9chi
force-pushed
the
agent/reapply-runner-fifo
branch
from
July 30, 2026 07:12
6499a5c to
32eaa5b
Compare
wan9chi
force-pushed
the
agent/reapply-runner-fifo
branch
from
July 30, 2026 07:35
32eaa5b to
ee3a214
Compare
wan9chi
force-pushed
the
agent/reapply-runner-fifo
branch
2 times, most recently
from
July 30, 2026 07:50
42ac131 to
fb19d42
Compare
wan9chi
force-pushed
the
fspy-close-gate
branch
2 times, most recently
from
July 30, 2026 08:10
652efbd to
b933a1f
Compare
wan9chi
force-pushed
the
agent/reapply-runner-fifo
branch
from
July 30, 2026 08:10
fb19d42 to
b6aa5bb
Compare
wan9chi
force-pushed
the
agent/reapply-runner-fifo
branch
from
July 30, 2026 08:18
b6aa5bb to
5a99844
Compare
wan9chi
force-pushed
the
agent/reapply-runner-fifo
branch
2 times, most recently
from
July 30, 2026 09:03
3ca6460 to
e8ea982
Compare
The old quiescence protocol attached "may write" to the shared mapping but "is still writing" to a file-lock descriptor. A descendant that closes descriptors it does not recognize released the lock while keeping full write access to the mapping, so the receiver could read frames while a straggler was mutating them. Put the gate in the shared memory itself, where a writer cannot drop it while still being able to write: one atomic word admits and counts claims, and the runner's close is a single `fetch_or` at root-process exit that fences all future claims and reports whether any write was in flight. Zero in flight proves every admitted claim ran to completion and the memory is frozen; anything else means the run is conservatively not cached. Tracking now stops when the root process exits instead of waiting for lingering descendants, so a task that leaks a daemon no longer blocks the read step, and post-exit accesses are treated as what they are: racy with respect to the task's contract. Closes #544. Closes #396. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
wan9chi
force-pushed
the
agent/reapply-runner-fifo
branch
from
July 30, 2026 09:06
e8ea982 to
82f986f
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Motivation
The current quiescence protocol attaches "may write" to a shared mapping but "is still writing" to a file-lock descriptor. A descendant that closes descriptors it does not recognize releases the lock while it keeps write access to the mapping, so the receiver can read frames while a straggler mutates them. The #544 investigation pinned this as the root cause.
This PR replaces the lock with a gate stored in the shared memory itself, where a writer cannot lose it while it can still write. One atomic word admits and counts each claim. The runner closes with one
fetch_orat root-process exit, which fences all future claims and reports whether a write was still in flight. A zero count proves every claim ran to completion: the memory is frozen, and the runner reads and caches. A nonzero count means the run is not cached. In-flight windows last microseconds and the runner closes milliseconds afterwaitreturns, so a nonzero count is rare. The closed bit and the count share one word on purpose; with two atomics, a writer could check the flag before the close and publish its count after it, which is the file lock's race in new clothes.The close drops the shared memory's keeper, so the attach window ends with the close: a process that starts later fails at
open, and a sender that attached earlier has its claims refused. On Linux, the seccomp supervisor'sstopalso returns without waiting: each listener task hands over what it recorded and a detached task keeps answering notifications, so a live filtered process keeps working while its later accesses go unrecorded. Draining those listeners to EOF used to mean waiting for every filtered descendant to exit, which reintroduced the daemon hang this PR removes.A process may also call
exitwhile another of its threads is mid-send, which would abandon a gate guard and mark the whole run incomplete. The preload now interposesexitand_exitand waits the few microseconds until in-flight sends finish before the process dies. Signals and crashes still skip this, and the runner handles those by not caching the run. Windows parity is a follow-up.Semantics change: fspy no longer waits for lingering descendants after the root process exits, and it does not track accesses made after that exit. Collecting the trace no longer delays
vp run; a task that leaks a daemon no longer blocks the read step. This fixes #396, where the receiver's exclusive flock waited on shared flocks inherited by Playwright/Chromium'ssetsidtree. Stdio pipe draining can still hold a run open and is tracked separately in #485.Closes #544
Closes #396
🤖 Generated with Claude Code