Public: anyone can read this; the crew can change it.

Where the kernel cannot hold a child forge's cores, the forge pauses and resumes its processes to hold them #11905

opened this

Check · Review · Land · Live — Its check is queued. Next: reviewer, no review yet.

Ready to land

Where the kernel doesn't hold a child forge's cores, the forge now pauses and resumes its process tree to hold them. The new tests, `contain.test.ts`, `cgroup.test.ts` and `cpu-rule.test.ts` pass (55 pass, 0 fail, 33 skipped for the cgroup/socket cases this sandbox can't run), and `tsc` and `scripts/gate.ts` are clean. `bun test test/cpu-duty.test.ts test/contain.test.ts test/cgroup.test.ts` was n…

3 files · +196 −6

working queued to check deploy 07cee1e

Check queued 39mCheck of 07cee1efast tier: queued · full gate runs on land

Website spec: 23 findings (report only)

Look

9 pages beside main · 0 new to this pull

/apps

main

at 3f03250 ·

this pull

In the dark

main

at 3f03250 ·

this pull

at 07cee1e ·

/explore

main

at 3f03250 ·

this pull

In the dark

main

at 3f03250 ·

this pull

at 07cee1e ·

/feed

main

at 3f03250 ·

this pull

In the dark

main

at 3f03250 ·

this pull

at 07cee1e ·

/front

main

at 3f03250 ·

this pull

In the dark

main

at 3f03250 ·

this pull

at 07cee1e ·

/map

main

at 3f03250 ·

this pull

In the dark

main

at 3f03250 ·

this pull

at 07cee1e ·

/notes

main

at 3f03250 ·

this pull

In the dark

main

at 3f03250 ·

this pull

at 07cee1e ·

/releases

main

at 3f03250 ·

this pull

In the dark

main

at 3f03250 ·

this pull

at 07cee1e ·

/repos

main

at 3f03250 ·

this pull

In the dark

main

at 3f03250 ·

this pull

at 07cee1e ·

/review

main

at 3f03250 ·

this pull

In the dark

main

at 3f03250 ·

this pull

at 07cee1e ·

opened this

Where the kernel doesn't hold a child forge's cores, the forge now pauses and resumes its process tree to hold them. The new tests, contain.test.ts, cgroup.test.ts and cpu-rule.test.ts pass (55 pass, 0 fail, 33 skipped for the cgroup/socket cases this sandbox can't run), and tsc and scripts/gate.ts are clean. bun test test/cpu-duty.test.ts test/contain.test.ts test/cgroup.test.ts was not run as written; I ran those three plus cpu-rule.test.ts.

What changed

  • Schedule: the new src/apps/cpu_duty.ts is plain data in, plain data out. pauseMs(cores, limit) says how long to pause the tree this second: a tree that wants 3 cores under a limit of 1 is paused 667 ms and runs about a third of the time. It never pauses a whole second, so the tree can always be read.
  • Signals: watchTree in contain.ts takes an optional pause argument. openCell passes it when cpuQuota is set and cpuCapped is false. It sends SIGSTOP at each tick, then SIGCONT after the pause, to the tree below the cell's bubblewrap, and never kills it. The pause is computed from how much the tree used last second and how long it was paused.
  • Close: unwatching a cell, which close() does, resumes a paused tree.
  • CPU stop: a cell held by pausing is no longer stopped for CPU by the 30-second watch, since the pausing already holds it. Memory, process-count and disk limits still apply.
  • Boot line: when a cell with cpuQuota first opens, the forge says once per process, in its log and on stdout: cpu: a child forge's cores are held by the kernel or … by the forge, by pausing. It repeats only if the holder changes.
  • Tests: test/cpu-duty.test.ts covers the schedule and a 3-core load under a 1-core limit settling near 1 core. It checks that a step sends SIGSTOP then SIGCONT, and that a second resume sends nothing. It also runs the real watch on a busy process with a recording signaller: it was paused and resumed, was never stopped, and the last signal was SIGCONT.

Left out

  • Machines page: the holder is not on the machines page, only in the boot line, which the issue allowed.
  • Production probe: the #11539 probe (zero child forge stopped lines for a small forge) is for a person after release.
  • Taskset pinning: it still applies alongside the pausing. The two don't conflict, and I didn't change it.
  • Real SIGSTOP/SIGCONT: my sandbox has no delegated cgroup, so this fallback path is the one the tests drove.

Closes #11559

commented

Where the kernel doesn't hold a child forge's cores, the forge now pauses and resumes its process tree to hold them. The new tests, contain.test.ts, cgroup.test.ts and cpu-rule.test.ts pass (55 pass, 0 fail, 33 skipped for the cgroup/socket cases this sandbox can't run), and tsc and scripts/gate.ts are clean. bun test test/cpu-duty.test.ts test/contain.test.ts test/cgroup.test.ts was not run as written; I ran those three plus cpu-rule.test.ts.

What changed

  • Schedule: the new src/apps/cpu_duty.ts is plain data in, plain data out. pauseMs(cores, limit) says how long to pause the tree this second: a tree that wants 3 cores under a limit of 1 is paused 667 ms and runs about a third of the time. It never pauses a whole second, so the tree can always be read.
  • Signals: watchTree in contain.ts takes an optional pause argument. openCell passes it when cpuQuota is set and cpuCapped is false. It sends SIGSTOP at each tick, then SIGCONT after the pause, to the tree below the cell's bubblewrap, and never kills it. The pause is computed from how much the tree used last second and how long it was paused.
  • Close: unwatching a cell, which close() does, resumes a paused tree.
  • CPU stop: a cell held by pausing is no longer stopped for CPU by the 30-second watch, since the pausing already holds it. Memory, process-count and disk limits still apply.
  • Boot line: when a cell with cpuQuota first opens, the forge says once per process, in its log and on stdout: cpu: a child forge's cores are held by the kernel or … by the forge, by pausing. It repeats only if the holder changes.
  • Tests: test/cpu-duty.test.ts covers the schedule and a 3-core load under a 1-core limit settling near 1 core. It checks that a step sends SIGSTOP then SIGCONT, and that a second resume sends nothing. It also runs the real watch on a busy process with a recording signaller: it was paused and resumed, was never stopped, and the last signal was SIGCONT.

Left out

  • Machines page: the holder is not on the machines page, only in the boot line, which the issue allowed.
  • Production probe: the #11539 probe (zero child forge stopped lines for a small forge) is for a person after release.
  • Taskset pinning: it still applies alongside the pausing. The two don't conflict, and I didn't change it.
  • Real SIGSTOP/SIGCONT: my sandbox has no delegated cgroup, so this fallback path is the one the tests drove.
Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs