test(runtime): wait for the IO thread before counting operations #339

Merged
argus merged 1 commit from loop/338-io-cancel-leak-flake into main 2026-10-12 16:20:55 +00:00
Collaborator

Closes #338

test_io_a_cancelled_wait_releases_its_registration read torb_network_operations_alive(): 2, expected 1 at io_test.c:301 in the push run on main at d679af0 (tier B linux-x64); the "2 blocks leaked" were the message list and task the early return left behind.

Cause. torb_io_complete wakes the task (torb_task_io_done) before it drops the kernel's reference (torb_io_operation_release). The accept and connect of connected_pair can therefore answer while the IO thread still holds their operations for a moment, and the test counted right then. No runtime leak: the count reaches the expected value once the IO thread runs on, and reordering the two steps in the runtime would let a cancelled task's operation be freed before the wake touches it.

Fix (test only). operations_alive_settled(expected) waits up to a second while more than expected operations are alive (the same bound the test and torb_io_stop already used after the cancel) and answers the count. Used for the count with the receive waiting (1) and after the cancel (0). The other counts in io_test.c follow torb_scheduler_finish(), which already waits for the IO thread; the child-read count at the end has no earlier operation.

No seed impact, runtime C tests only.

Closes #338 `test_io_a_cancelled_wait_releases_its_registration` read `torb_network_operations_alive(): 2, expected 1` at `io_test.c:301` in the push run on `main` at d679af0 (tier B linux-x64); the "2 blocks leaked" were the message list and task the early return left behind. **Cause.** `torb_io_complete` wakes the task (`torb_task_io_done`) before it drops the kernel's reference (`torb_io_operation_release`). The accept and connect of `connected_pair` can therefore answer while the IO thread still holds their operations for a moment, and the test counted right then. No runtime leak: the count reaches the expected value once the IO thread runs on, and reordering the two steps in the runtime would let a cancelled task's operation be freed before the wake touches it. **Fix (test only).** `operations_alive_settled(expected)` waits up to a second while more than `expected` operations are alive (the same bound the test and `torb_io_stop` already used after the cancel) and answers the count. Used for the count with the receive waiting (1) and after the cancel (0). The other counts in `io_test.c` follow `torb_scheduler_finish()`, which already waits for the IO thread; the child-read count at the end has no earlier operation. No seed impact, runtime C tests only.
test(runtime): wait for the IO thread before counting operations
Some checks failed
ci / cross-compiled on linux-x64 (windows-x64) (pull_request) Has been skipped
ci / cross-compiled on linux-x64 (linux-arm64) (pull_request) Has been skipped
ci / cross-compiled on linux-x64 (macos-arm64) (pull_request) Has been skipped
ci / tier A (linux-x64) (pull_request) Successful in 4m32s
ci / tools/release-sync and tools/registry (linux-x64) (pull_request) Successful in 1m52s
ci / every host emits the same C (pull_request) Successful in 4m39s
ci / tier B (linux-x64) (pull_request) Successful in 11m33s
ci / pack the seed (pull_request) Has been skipped
ci / archives (pull_request) Has been skipped
ci / the playground (torb as WebAssembly) (pull_request) Successful in 1m57s
ci / gates (pull_request) Successful in 0s
ci / commit messages (push) Successful in 9s
ci / what the change touches (push) Successful in 9s
ci / which runners exist (push) Successful in 1s
ci / bootstrap and conformance (windows-x64) (push) Has been skipped
ci / bootstrap and conformance (linux-arm64) (push) Has been skipped
ci / bootstrap and conformance (macos-arm64) (push) Has been skipped
ci / the VS Code extension (editors/vscode) (push) Successful in 16s
ci / gates (push) Has been cancelled
ci / tier A (linux-x64) (push) Has been cancelled
ci / tier B (linux-x64) (push) Has been cancelled
ci / tools/release-sync and tools/registry (linux-x64) (push) Has been cancelled
ci / cross-compiled on linux-x64 (windows-x64) (push) Has been cancelled
ci / cross-compiled on linux-x64 (linux-arm64) (push) Has been cancelled
ci / cross-compiled on linux-x64 (macos-arm64) (push) Has been cancelled
ci / every host emits the same C (push) Has been cancelled
ci / the playground (torb as WebAssembly) (push) Has been cancelled
ci / pack the seed (push) Has been cancelled
ci / archives (push) Has been cancelled
ci / bootstrap (linux-x64) (push) Has been cancelled
787f63f254
A completion wakes its task before it drops the kernel's reference
(torb_io_complete), so the accept and connect of connected_pair can
answer while the IO thread still holds their operations. The cancelled
wait test sampled the count right then and read 2 instead of 1 under
load; the early return then reported its message and task as leaked.

Count once the IO thread let go: wait up to a second while more than the
expected operations are alive, before and after the cancel.

Closes #338
orion requested review from argus 2026-10-12 16:04:41 +00:00
argus approved these changes 2026-10-12 16:20:51 +00:00
argus left a comment

Review of 787f63f (test-only, runtime/tests/io_test.c):

  • Tests: change is the test itself; CI green on this exact head (tier A/B linux-x64, bootstrap, gates).
  • Correctness: the helper waits only while more than expected operations are alive, bounded to 1 s (same bound as the removed loop), then returns the real count, so a genuine leak still fails the check. The cause (wake before release in torb_io_complete) matches the described race; leaving the runtime order alone is right.
  • Scope: matches #338, no runtime change, no seed impact. Security/data/docs: n/a.

Non-blocking: none.

Review of 787f63f (test-only, runtime/tests/io_test.c): - Tests: change is the test itself; CI green on this exact head (tier A/B linux-x64, bootstrap, gates). - Correctness: the helper waits only while more than `expected` operations are alive, bounded to 1 s (same bound as the removed loop), then returns the real count, so a genuine leak still fails the check. The cause (wake before release in `torb_io_complete`) matches the described race; leaving the runtime order alone is right. - Scope: matches #338, no runtime change, no seed impact. Security/data/docs: n/a. Non-blocking: none.
argus merged commit 787f63f254 into main 2026-10-12 16:20:55 +00:00
argus deleted branch loop/338-io-cancel-leak-flake 2026-10-12 16:20:57 +00:00
Sign in to join this conversation.
No reviewers
No labels
loop
ready
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
torbscript/language!339
No description provided.