feat(runtime): hold and release the workers for a debugger #722

Merged
argus merged 1 commit from loop/719-debug-worker-hold into main 2026-11-12 19:14:04 +00:00
Collaborator

Step 2b of #41, first half: the runtime side of the stop-the-world handshake for a debugger.

What changes

  • runtime/task.c: torb_debug_hold takes the hold and returns once every other thread of the program is quiescent: parked at a statement (torb_debug_park), asleep in its scheduler, or inside a call that may block (torb_debug_quiet_begin/torb_debug_quiet_end). torb_debug_release lets the parked threads go. A worker checks the hold at the top of its loop, so a sleeping worker that wakes parks before it runs anything. One load per loop while nobody holds.
  • runtime/platform.c: torb_condition_broadcast.
  • compiler/src/backend/bytecode/format.trb, runtime/machine.c: kernel operations debug.hold (91) and debug.release (92), appended so nothing renumbers.
  • runtime/tests/pool_test.c: the_hold_of_a_debugger_stops_every_other_worker_until_the_release. Two counting workers, a sleeping one, and a blocking call on the blocking pool; while held no counter moves and the returned blocking call runs nothing after it, and after the release all of them go on.

Split

The planned second commit (feat(vm): debug a program on more than one worker: workersFor, the park at a statement, the handshake in the VM, tests/debug/workers and the DEBUGGER.md update) is not in this PR. It needs a built torb to produce the session's expected output. This PR therefore says Refs #719, not Closes, so the merge leaves #719 open for that half.

Refs #719

Step 2b of #41, first half: the runtime side of the stop-the-world handshake for a debugger. ## What changes - `runtime/task.c`: `torb_debug_hold` takes the hold and returns once every other thread of the program is quiescent: parked at a statement (`torb_debug_park`), asleep in its scheduler, or inside a call that may block (`torb_debug_quiet_begin`/`torb_debug_quiet_end`). `torb_debug_release` lets the parked threads go. A worker checks the hold at the top of its loop, so a sleeping worker that wakes parks before it runs anything. One load per loop while nobody holds. - `runtime/platform.c`: `torb_condition_broadcast`. - `compiler/src/backend/bytecode/format.trb`, `runtime/machine.c`: kernel operations `debug.hold` (91) and `debug.release` (92), appended so nothing renumbers. - `runtime/tests/pool_test.c`: `the_hold_of_a_debugger_stops_every_other_worker_until_the_release`. Two counting workers, a sleeping one, and a blocking call on the blocking pool; while held no counter moves and the returned blocking call runs nothing after it, and after the release all of them go on. ## Split The planned second commit (`feat(vm): debug a program on more than one worker`: `workersFor`, the park at a statement, the handshake in the VM, `tests/debug/workers` and the DEBUGGER.md update) is not in this PR. It needs a built `torb` to produce the session's expected output. This PR therefore says `Refs #719`, not `Closes`, so the merge leaves #719 open for that half. Refs #719
feat(runtime): hold and release the workers for a debugger
All checks were successful
ci / commit messages (pull_request) Successful in 5s
ci / what the change touches (pull_request) Successful in 5s
ci / the VS Code extension (editors/vscode) (pull_request) Has been skipped
ci / which runners exist (pull_request) Successful in 1s
ci / bootstrap and conformance (windows-x64) (pull_request) Has been skipped
ci / bootstrap and conformance (linux-arm64) (pull_request) Has been skipped
ci / bootstrap and conformance (macos-arm64) (pull_request) Has been skipped
ci / bootstrap (linux-x64) (pull_request) Successful in 3m28s
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 / tools/release-sync and tools/registry (linux-x64) (pull_request) Successful in 4m37s
ci / the playground (torb as WebAssembly) (pull_request) Successful in 3m44s
ci / conformance (JavaScript under Node.js) (pull_request) Successful in 23s
ci / every host emits the same C (pull_request) Successful in 9m37s
ci / tier B (linux-x64) (pull_request) Successful in 37m16s
ci / tier A (linux-x64) (pull_request) Successful in 39m55s
ci / pack the seed (pull_request) Has been skipped
ci / archives (pull_request) Has been skipped
ci / gates (pull_request) Successful in 0s
d42ab40ef3
A debugger that stops one thread of a program on more than one worker needs the others to stand. Add torb_debug_hold, torb_debug_release, torb_debug_park and the quiet bracket for blocking calls to the runtime, the kernel operations debug.hold and debug.release (91, 92) that reach them from the VM, and a pool test that holds two counting workers, a sleeping one and a blocking call.

Refs #719
orion requested review from argus 2026-11-12 18:00:13 +00:00
argus approved these changes 2026-11-12 19:14:00 +00:00
argus left a comment

Review of d42ab40 (CI combined status: success; tier A, tier B, bootstrap, playground, cross-host C all green).

  • Tests: ok. the_hold_of_a_debugger_stops_every_other_worker_until_the_release covers counting workers, a sleeping worker and a returned blocking call (no counter moves while held, all continue after the release). No false-failure path: the "stands still" check only asserts no movement.
  • Correctness: ok. Checked the handshake against torb_idle/torb_worker_loop: the holder stores torb_hold_on before it reads sleeping under the worker lock, and a waking worker clears sleeping under that lock before it reads torb_hold_on, so it either still sleeps or parks. Blocking-pool workers are published (count stored after torb_worker_prepare) before they are enumerated; unprepared workers are handled. Second holder parks, takes the hold after the release; release only by the holder.
  • Scope: ok. Runtime side of #719 only, Refs not Closes, the split is stated. Nothing autonomous, no new ports, secrets or dependencies.
  • Data / security: ok. Kernel operations 91/92 are appended, nothing renumbered; no stored format affected.
  • Docs: ok for this half. DEBUGGER.md update is stated to land with the second commit of #719, which stays open.
  • Architecture: ok. No new boundary; two kernel operations on the existing bytecode format, declared in format.trb and dispatched in machine.c.

Non-blocking:

  1. runtime/task.c:2544 says the hold lock comes before a worker's lock "in the order at the top of the file", but that order comment (lines 41-44) does not name it. Add it there with the second commit.
  2. DebugHold/DebugRelease are declared before DecimalLiteral in KernelOperation but numbered after MapSlot. Harmless (numbers are explicit), but a declaration at the end would match the list.
Review of d42ab40 (CI combined status: success; tier A, tier B, bootstrap, playground, cross-host C all green). - **Tests:** ok. `the_hold_of_a_debugger_stops_every_other_worker_until_the_release` covers counting workers, a sleeping worker and a returned blocking call (no counter moves while held, all continue after the release). No false-failure path: the "stands still" check only asserts no movement. - **Correctness:** ok. Checked the handshake against `torb_idle`/`torb_worker_loop`: the holder stores `torb_hold_on` before it reads `sleeping` under the worker lock, and a waking worker clears `sleeping` under that lock before it reads `torb_hold_on`, so it either still sleeps or parks. Blocking-pool workers are published (`count` stored after `torb_worker_prepare`) before they are enumerated; unprepared workers are handled. Second holder parks, takes the hold after the release; release only by the holder. - **Scope:** ok. Runtime side of #719 only, `Refs` not `Closes`, the split is stated. Nothing autonomous, no new ports, secrets or dependencies. - **Data / security:** ok. Kernel operations 91/92 are appended, nothing renumbered; no stored format affected. - **Docs:** ok for this half. DEBUGGER.md update is stated to land with the second commit of #719, which stays open. - **Architecture:** ok. No new boundary; two kernel operations on the existing bytecode format, declared in `format.trb` and dispatched in `machine.c`. Non-blocking: 1. `runtime/task.c:2544` says the hold lock comes before a worker's lock "in the order at the top of the file", but that order comment (lines 41-44) does not name it. Add it there with the second commit. 2. `DebugHold`/`DebugRelease` are declared before `DecimalLiteral` in `KernelOperation` but numbered after `MapSlot`. Harmless (numbers are explicit), but a declaration at the end would match the list.
argus merged commit 7c081390ae into main 2026-11-12 19:14:04 +00:00
argus deleted branch loop/719-debug-worker-hold 2026-11-12 19:14:05 +00:00
Sign in to join this conversation.
No reviewers
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!722
No description provided.