Skip to content

Flaky: testAnAlreadyCompleteSlotIsAwaitedWithoutParking fails ~1 in 4 full-suite runs on a cooperative-path timing race #33

Description

@lisachenko

Observed during the #17 idle-preemption work (PR #28's verification notes) and flagged there as worth its own issue; filing it so it does not stay buried in a merged PR body.

Observation, as measured

  • testAnAlreadyCompleteSlotIsAwaitedWithoutParking.phpt failed once in four full-suite runs on PHP 8.4.19 (-d ffi.enable=1 -d opcache.jit=off).
  • 12/12 green in isolation, with and without the idle-timer change — so the race predates feat(preemption): stop the slice clock while the poller blocks #28's branch and needs the rest of the suite (or its process churn) to surface.
  • The failure was on the cooperative path — no preemption involved.

Why this shape of race is plausible

The test promises that a slot which is already settled is awaited without parking. That promise has a window: the waiter must observe "already complete" through the same path (SlotTable::refresh() / local view) that a fresh settlement travels through. Under suite load, the wake event and the settle can land close enough together that the await neither finds the slot locally complete nor receives the level-triggered poke it would have parked on — or the test's own observable ("did it park?") reads a scheduler state that is one tick stale. Since #29/#31 the slot's local view is also claim-counted and forgettable, which adds one more ordering to hold (adopt-then-settle is already pinned by #31's adopt() fix — this may be a sibling of that bug on the open-then-await path).

Constraints on the fix

  • Not a retry and not a sleep: AGENTS.md — bound everything, wait on the primitive, and a Coroutine::yield() busy-loop starves the very timers under test.
  • The fix should make the "already complete ⇒ no park" claim true by construction (settle-before-publish ordering, or the test asserting the real invariant it means: no kernel wait happened, e.g. by wakeup count as testTheWakePipeIsDrainedSoThePollerDoesNotSpin.phpt does), rather than widening the window until CI stops noticing.

Reproduction guidance

Run the full suite in a loop (for i in $(seq 20); do ... vendor/bin/phpunit; done) rather than the single test; the 1-in-4 figure was under full-suite conditions only. A run under --repeat of just this file has not reproduced it.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions