Repository navigation
Conversation
Review r1 of #1269 at f85ec67 (step 2 only:
|
… read, and a touch past a mapped file's end is SIGBUS B3. A visit no longer runs its shootdown and futex revocation inside the pager's lock. It reads the object's revoking pages, lowest first, 64 at a time (`Pages::revoking_from`, unit-tested), under the pager's lock alone; then, under its space's lock alone, clears every leaf of its ranges that maps one of those frames, shoots the span down, and only then ends the futex waits on the frames, as `revoke_frames`' contract says. It touches only the revoked pages, not every leaf of every range of the object. Each batch still walks the object's resident pages under the pager's lock; the memory track records that cost with the row that prices it. The orchestrator's ruling on S1: a touch of a mapped page wholly past the object's end ends the program with `Fault::Mapping` (POSIX's `SIGBUS`) and its record (`Why::PastEnd`); a copy from one stays `BadAddress`, as POSIX's `EFAULT`. The manual's memory page says so, and `mapprobe`'s `shrunk` case expects it. S3: a fault's request run is `vm::AROUND` in pages, not a second 16. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
B5. The manual says a copying system call answers an I/O error for a mapped file's lost page. Fifteen sites flattened a failed copy to `BadAddress`: the argument records of spawn, message send and receive, namespace build, `vm_map` and the paged op, a port's badge, an affinity mask and a thread's name, the namespace build's two vectors, the three PCI grants' zeroing, a device acknowledgement and the log cursor's words. Each now answers the copy's own `SyscallError` (`BadAddress` or `Io`), as `user_ptr` makes it. A window refused for its bounds stays `BadAddress`. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…d the range count's control runs B2. `vm_map`'s contract gains a paged holder's: `Read` only, needing `READ`; a pager's process refused; a range past the object's end; a mapping counts as a holder; a touch of an unsupplied page waits and is reported overdue; a lost page or one wholly past the end ends the process with `Fault::Mapping`, and a copy from a lost one answers `Io`; `Gone` for an object already gone. `NOTICE_NO_HOLDERS` counts a mapping as a holder, the paged section says its objects are mapped too, and a withdraw, fail or shrink returns once no mapping reaches what it removed. B1. `ranges-less-relaxed` is registered in `build/ci.rs`'s `CONTROLS`, so `--ci host` runs it red and `every_model_control_is_run` holds. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…per rows, and a guest row for it The orchestrator's ruling: the owed S4 and S5 rows are written now, so the batched main boot can run them. The mapping rows move from `files` into a `map` group of their own (in `all`'s order after `files`, a job of the benchcase image): `touch_16m`, `read_4k`, `threads_touch_16m` (eight threads faulting one mapping, each its eighth) and `truncate_255` (a 1 MiB file 255 `osbench map-hold` helpers map and touch whole, truncated to nothing, the truncate alone timed). `osbench_map_group_exits_0` runs the group in a guest and requires each row measured; what they measure is owed on metal. B6: `map_file` sits above `unmap`'s safety contract again, which names it. S5: the QEMU row matches the overdue report of the probe's own stalled run, pages 16+16, not any pager's. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
B4. The memory track's step 2 bullets name every boot and group owed on metal and what main must show: the shared boots with `mapped_file` and the pager-end test, the A/B of the groups the fault and copy paths run under with the process-exit cost every end now pays, and the `map` group beside Linux with each row's ratio. It records the pager-wide wakes (a departure from §3/S4) and the revocation visit's cost with the rows that price them, names step 3 as R4's, keeps the cold DATA miss as a row still to write, and records the pinned-copy test owed with #1258. libc's `msync` reason is what is true: a file is mapped read-only only. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…c, and the loom model clones once The full host suite found two defects step 2 brought in. `MapNode`'s hand-written `Send` and `Sync` (its link is reached only under its pager's lock) were not declared in `build/sourcegate.rs`'s table of them, so `every_hand_written_auto_trait_impl_is_declared` was red. And `paged_ranges.rs` cloned its counts and leaf for a second thread that could take the originals, which the workspace's clippy denies as a redundant clone. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Review r1 answered at 9d82143 (commits 70e1bea..9d82143 over c64e8fd). Blockers
The orchestrator's rulings
Suggestions
PR description: "a node linked exactly while…" is now listed as holding by construction, and the host evidence names Guest: run 43099497824 at 9d82143 (the mapped-file rows, the copy rows, the spawn row, |
Review r2 of #1269 at 9d82143 (
|
… lock at a time, and ends their futex waits before any goes back B3. Each object keeps the walk's set: its revoking slots in a list, appended when a page is marked and emptied only by the walk's end, which now gives out the set's frames and nothing else (O(R), not O(S)). The walk splits into `next_visit` and `finish`. A visit reads the set a batch of 64 at a time by a cursor, under the pager's lock alone, drops it, and has the space clear and shoot down that batch's leaves under the space's lock alone (`Space::clear_paged`): one lock at a time, and a one-page truncate of a large file costs one page's work. B8. After every mapper's visit and before any frame goes back, the walk ends every futex wait on a revoking frame, read under the pager's lock and ended outside it. No leaf maps a revoking frame by then and none can be made to, so no wait arms on one afresh; and an unmap, `discard`, `protect` to none or a space's end that cleared a leaf of a paged frame earlier, revoking only frames it owns, can no longer leave a waiter keyed to a frame that is reissued. The visit's own per-leaf revocation is gone. B7. The page a pager names is placed by `vm::page_at`, whose every step is checked: a page near the last a pager may name, offset 0, is no place rather than an overflow. Its unit test caught the first form, whose `then_some` added before the guard. The pure model's visit is the kernel's rule with batches of one: it reads the next page of the set and clears the space's leaf where it maps that frame, with every other step free to run between. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…the shrink case reaches a second batch A touch past a mapped object's end is `Populated::PastEnd`, `Faulted::PastEnd` and `Missing::PastEnd`, not a `Why` two consumers had to test: a touch ends the process with its record, and a copy, and now a futex word, answers `BadAddress`, since nothing is there (B9's wording; no credit to POSIX for a copy's answer). The futex word's comment says how a mapped file's frame keeps the futex contract. `mapprobe`'s `shrunk` case shrinks an object of 80 pages, every one touched by two mappers, to one: the 79 revoked pages take two batches, and the mappers touch the first and the last of them, each ended `Fault::Mapping`, whichever batch cleared it. The harness names the map row's QEMU machine and says each of its rows is required measured. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rue reason B4a: the pager-wide wakes are recorded as unpriced, since `threads_touch_16m` faults pages that are never absent; owner map7b with step 3, exit a many-threads cold-fault row on a DATA file past its pager's capacity. The index-read departure is gone with the O(R) visit. B4b: `msync` answers `ENOSYS` because no call answers which pages of a range are mapped, which POSIX's `ENOMEM` needs; the record and `refused.rs` both say so. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Review r2 answered at 5f9f6fe (f3d5710, dec827f, 5f9f6fe over 9d82143), on the orchestrator's decisions.
Suggestions, all three taken.
Checks at 5f9f6fe: Guest: run 43104273025 at 5f9f6fe ( |
Review r3 of #1269 at 5f9f6fe (
|
… lock at a time, and a page past the end is a variant of its own B3. Each object keeps the walk's set: its revoking slots in a list, appended when a page is marked and emptied only by the walk's end, which now gives out the set's frames and nothing else (O(R), not O(S)). The walk splits into `next_visit` and `finish`. A visit reads the set a batch of 64 at a time by a cursor, under the pager's lock alone, drops it, and has the space clear and shoot down that batch's leaves under the space's lock alone (`Space::clear_paged`): one lock at a time, and a one-page truncate of a large file costs one page's work. B8, in part. After every mapper's visit and before any frame goes back, the walk ends every futex wait on a frame of its set, read under the pager's lock and ended outside it; the visit's own per-leaf revocation is gone. A page marked during that sweep is not yet covered here; the next commits' rule is. B7. The page a pager names is placed by `vm::page_at`, whose every step is checked: a page near the last a pager may name, offset 0, is no place rather than an overflow. Its unit test caught the first form, whose `then_some` added before the guard. A touch past a mapped object's end is `Missing::PastEnd`, `Populated::PastEnd` and `Faulted::PastEnd`, not a `Why` two consumers had to test: a touch ends the process with its record, and a copy, and now a futex word, answers `BadAddress`, since nothing is there. The futex word's comment says how a mapped file's frame keeps the futex contract. The pure model's visit is the kernel's rule with batches of one. `mapprobe`'s `shrunk` case shrinks an object of 80 pages, every one touched by two mappers, to one: the 79 revoked pages take two batches, and the mappers touch the first and the last of them, each ended `Fault::Mapping`, whichever batch cleared it. The harness names the map row's QEMU machine and says each of its rows is required measured. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rue reason B4a: the pager-wide wakes are recorded as unpriced, since `threads_touch_16m` faults pages that are never absent; owner map7b with step 3, exit a many-threads cold-fault row on a DATA file past its pager's capacity. The index-read departure is gone with the O(R) visit. B4b: `msync` answers `ENOSYS` because no call answers which pages of a range are mapped, which POSIX's `ENOMEM` needs; the record and `refused.rs` both say so. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… its last sweep B10. The sweep could miss a page marked while it had the pager's lock dropped: the removal set `again`, the new pass found no mapper, and the walk gave the page's frame back unswept, with a waiter keyed on it through a leaf an unmap had already cleared. The rule is now the pure crate's: `next_visit` answers `Visit(node)`, `Sweep` or `Finish`, the object records the epoch it was swept at, and it answers `Sweep` again whenever a pass has begun since; `finish` asserts the sweep is current. So every frame the walk gives back was swept after the last pass's visits, and no wait can arm on it after: no leaf maps a revoking frame once its pass's visits are done, and no fault installs one. An unmap, `discard`, `protect` to none or a space's end that cleared a paged leaf, revoking only frames it owns, leaves the frame in the index until a removal's walk sweeps it. The kernel loop is a plain match on that answer. The model takes the sweep as a step of its own, a frame at a time with every other step free to run between, and refuses a frame given back that the current sweep did not reach. `a_page_marked_during_the_sweep_is_swept_before_its_frame_goes_back` drives the pure API through r3's sequence: it passes, and under the old rule (sweep once per walk, a checked one-line patch) it is red, with both model runs. `Pages::walk` has no production caller left and moves into the test module. Suggestions: the `vm` test sits after the test module's imports, and `REVOKE_BATCH` names `mapprobe`'s `shrunk` case, which needs two batches. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Review r3 answered at 156878e, on the orchestrator's decisions. The branch was rewritten for B11 (force-pushed; my own branch).
Checks at 156878e: Guest: run 43108977664 at 156878e ( |
Review r4 of #1269 at 156878e (
|
… read, and a touch past a mapped file's end is SIGBUS B3. A visit no longer runs its shootdown and futex revocation inside the pager's lock. It reads the object's revoking pages, lowest first, 64 at a time (`Pages::revoking_from`, unit-tested), under the pager's lock alone; then, under its space's lock alone, clears every leaf of its ranges that maps one of those frames, shoots the span down, and only then ends the futex waits on the frames, as `revoke_frames`' contract says. It touches only the revoked pages, not every leaf of every range of the object. Each batch still walks the object's resident pages under the pager's lock; the memory track records that cost with the row that prices it. The orchestrator's ruling on S1: a touch of a mapped page wholly past the object's end ends the program with `Fault::Mapping` (POSIX's `SIGBUS`) and its record (`Why::PastEnd`); a copy from one stays `BadAddress`, as POSIX's `EFAULT`. The manual's memory page says so, and `mapprobe`'s `shrunk` case expects it. S3: a fault's request run is `vm::AROUND` in pages, not a second 16. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
B5. The manual says a copying system call answers an I/O error for a mapped file's lost page. Fifteen sites flattened a failed copy to `BadAddress`: the argument records of spawn, message send and receive, namespace build, `vm_map` and the paged op, a port's badge, an affinity mask and a thread's name, the namespace build's two vectors, the three PCI grants' zeroing, a device acknowledgement and the log cursor's words. Each now answers the copy's own `SyscallError` (`BadAddress` or `Io`), as `user_ptr` makes it. A window refused for its bounds stays `BadAddress`. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…d the range count's control runs B2. `vm_map`'s contract gains a paged holder's: `Read` only, needing `READ`; a pager's process refused; a range past the object's end; a mapping counts as a holder; a touch of an unsupplied page waits and is reported overdue; a lost page or one wholly past the end ends the process with `Fault::Mapping`, and a copy from a lost one answers `Io`; `Gone` for an object already gone. `NOTICE_NO_HOLDERS` counts a mapping as a holder, the paged section says its objects are mapped too, and a withdraw, fail or shrink returns once no mapping reaches what it removed. B1. `ranges-less-relaxed` is registered in `build/ci.rs`'s `CONTROLS`, so `--ci host` runs it red and `every_model_control_is_run` holds. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…per rows, and a guest row for it The orchestrator's ruling: the owed S4 and S5 rows are written now, so the batched main boot can run them. The mapping rows move from `files` into a `map` group of their own (in `all`'s order after `files`, a job of the benchcase image): `touch_16m`, `read_4k`, `threads_touch_16m` (eight threads faulting one mapping, each its eighth) and `truncate_255` (a 1 MiB file 255 `osbench map-hold` helpers map and touch whole, truncated to nothing, the truncate alone timed). `osbench_map_group_exits_0` runs the group in a guest and requires each row measured; what they measure is owed on metal. B6: `map_file` sits above `unmap`'s safety contract again, which names it. S5: the QEMU row matches the overdue report of the probe's own stalled run, pages 16+16, not any pager's. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
B4. The memory track's step 2 bullets name every boot and group owed on metal and what main must show: the shared boots with `mapped_file` and the pager-end test, the A/B of the groups the fault and copy paths run under with the process-exit cost every end now pays, and the `map` group beside Linux with each row's ratio. It records the pager-wide wakes (a departure from §3/S4) and the revocation visit's cost with the rows that price them, names step 3 as R4's, keeps the cold DATA miss as a row still to write, and records the pinned-copy test owed with #1258. libc's `msync` reason is what is true: a file is mapped read-only only. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The count of a space's ranges holding its node moves to `object/paged/ranges.rs`, which the loom crate compiles as it does `shootdown.rs`. `paged_ranges.rs` races an unmap, which clears its leaf and lets its range go, against a parked fault letting its hold go with no space lock: whichever is last must see the leaf cleared before the node leaves its object's list, since the walk then stops visiting the space and frees the frame. It passes with the count's release and acquire, and the negative control `ranges-less-relaxed` reds it with loom's "Causality violation: Concurrent read and write accesses". The SDK's last-holder notice says a mapping is a holder. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Two rows of every file target, on its 16 MiB file once its pages are cached: `map_touch_16m` maps the file read-only and shared, touches each page once and unmaps it (20 after 2), so its time is the faults fault-around leaves; `map_read_4k` copies 4 KiB out of a page of one mapping whose every page was touched (2,000 after 100), the read path a mapping replaces. Linux maps with `mmap(PROT_READ, MAP_SHARED)`; ToyOS opens the file through the SDK and maps its holder, since its std `File` names no descriptor. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
libc maps a file read-only, shared or private; other protections still answer `ENODEV`, now for what is not built (step 5's write faults, R4's private copy ranges of a file). The memory track says step 2 is built but for R4's copy ranges, which its item 5 owes; that only a pager's pages are revoked, so ROOT stays non-reclaimable until a pager serves it; and which mapping measurements remain owed after the two osbench rows step 2 adds. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The memory track records step 2's metal for one batched boot of main when a bench returns: the whole testcases boot with `mapped_file`, shared-debug and proctreecase on both benches, every job exiting 0; osbench's fs, pipe, ipc, mem and proc groups before and after, no slower; and the two mapping rows beside Linux's `mmap`, unmeasured until then. The rows step 2 did not write stay owed by map7b. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… read, and a touch past a mapped file's end is SIGBUS B3. A visit no longer runs its shootdown and futex revocation inside the pager's lock. It reads the object's revoking pages, lowest first, 64 at a time (`Pages::revoking_from`, unit-tested), under the pager's lock alone; then, under its space's lock alone, clears every leaf of its ranges that maps one of those frames, shoots the span down, and only then ends the futex waits on the frames, as `revoke_frames`' contract says. It touches only the revoked pages, not every leaf of every range of the object. Each batch still walks the object's resident pages under the pager's lock; the memory track records that cost with the row that prices it. The orchestrator's ruling on S1: a touch of a mapped page wholly past the object's end ends the program with `Fault::Mapping` (POSIX's `SIGBUS`) and its record (`Why::PastEnd`); a copy from one stays `BadAddress`, as POSIX's `EFAULT`. The manual's memory page says so, and `mapprobe`'s `shrunk` case expects it. S3: a fault's request run is `vm::AROUND` in pages, not a second 16. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
B5. The manual says a copying system call answers an I/O error for a mapped file's lost page. Fifteen sites flattened a failed copy to `BadAddress`: the argument records of spawn, message send and receive, `vm_map` and the paged op, a port's badge, the affinity mask read and written, a thread's name, the three PCI grants' zeroing, a device acknowledgement and the log cursor's two reads. Each now answers the copy's own `SyscallError` (`BadAddress` or `Io`), as `user_ptr` makes it. A window refused for its bounds stays `BadAddress`. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…d the range count's control runs B2. `vm_map`'s contract gains a paged holder's: `Read` only, needing `READ`; a pager's process refused; a range past the object's end; a mapping counts as a holder; a touch of an unsupplied page waits and is reported overdue; a lost page or one wholly past the end ends the process with `Fault::Mapping`, and a copy from a lost one answers `Io`; `Gone` for an object already gone. `NOTICE_NO_HOLDERS` counts a mapping as a holder, the paged section says its objects are mapped too, and a withdraw, fail or shrink returns once no mapping reaches what it removed. B1. `ranges-less-relaxed` is registered in `build/ci.rs`'s `CONTROLS`, so `--ci host` runs it red and `every_model_control_is_run` holds. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…per rows, and a guest row for it The orchestrator's ruling: the owed S4 and S5 rows are written now, so the batched main boot can run them. The mapping rows move from `files` into a `map` group of their own (in `all`'s order after `files`, a job of the benchcase image): `touch_16m`, `read_4k`, `threads_touch_16m` (eight threads faulting one mapping, each its eighth) and `truncate_255` (a 1 MiB file 255 `osbench map-hold` helpers map and touch whole, truncated to nothing, the truncate alone timed). `osbench_map_group_exits_0` runs the group in a guest and requires each row measured; what they measure is owed on metal. B6: `map_file` sits above `unmap`'s safety contract again, which names it. S5: the QEMU row matches the overdue report of the probe's own stalled run, pages 16+16, not any pager's. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
B4. The memory track's step 2 bullets name every boot and group owed on metal and what main must show: the shared boots with `mapped_file` and the pager-end test, the A/B of the groups the fault and copy paths run under with the process-exit cost every end now pays, and the `map` group beside Linux with each row's ratio. It records the pager-wide wakes (a departure from §3/S4) and the revocation visit's cost with the rows that price them, names step 3 as R4's, keeps the cold DATA miss as a row still to write, and records the pinned-copy test owed with #1258. libc's `msync` reason is what is true: a file is mapped read-only only. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…c, and the loom model clones once The full host suite found two defects step 2 brought in. `MapNode`'s hand-written `Send` and `Sync` (its link is reached only under its pager's lock) were not declared in `build/sourcegate.rs`'s table of them, so `every_hand_written_auto_trait_impl_is_declared` was red. And `paged_ranges.rs` cloned its counts and leaf for a second thread that could take the originals, which the workspace's clippy denies as a redundant clone. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… lock at a time, and a page past the end is a variant of its own B3. Each object keeps the walk's set: its revoking slots in a list, appended when a page is marked and emptied only by the walk's end, which now gives out the set's frames and nothing else (O(R), not O(S)). The walk splits into `next_visit` and `finish`. A visit reads the set a batch of 64 at a time by a cursor, under the pager's lock alone, drops it, and has the space clear and shoot down that batch's leaves under the space's lock alone (`Space::clear_paged`): one lock at a time, and a one-page truncate of a large file costs one page's work. B8, in part. After every mapper's visit and before any frame goes back, the walk ends every futex wait on a frame of its set, read under the pager's lock and ended outside it; the visit's own per-leaf revocation is gone. A page marked during that sweep is not yet covered here; the next commits' rule is. B7. The page a pager names is placed by `vm::page_at`, whose every step is checked: a page near the last a pager may name, offset 0, is no place rather than an overflow. Its unit test caught the first form, whose `then_some` added before the guard. A touch past a mapped object's end is `Missing::PastEnd`, `Populated::PastEnd` and `Faulted::PastEnd`, not a `Why` two consumers had to test: a touch ends the process with its record, and a copy, and now a futex word, answers `BadAddress`, since nothing is there. The futex word's comment says how a mapped file's frame keeps the futex contract. The pure model's visit is the kernel's rule with batches of one. `mapprobe`'s `shrunk` case shrinks an object of 80 pages, every one touched by two mappers, to one: the 79 revoked pages take two batches, and the mappers touch the first and the last of them, each ended `Fault::Mapping`, whichever batch cleared it. The harness names the map row's QEMU machine and says each of its rows is required measured. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rue reason B4a: the pager-wide wakes are recorded as unpriced, since `threads_touch_16m` faults pages that are never absent; owner map7b with step 3, exit a many-threads cold-fault row on a DATA file past its pager's capacity. The index-read departure is gone with the O(R) visit. B4b: `msync` answers `ENOSYS` because no call answers which pages of a range are mapped, which POSIX's `ENOMEM` needs; the record and `refused.rs` both say so. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… its last sweep B10. The sweep could miss a page marked while it had the pager's lock dropped: the removal set `again`, the new pass found no mapper, and the walk gave the page's frame back unswept, with a waiter keyed on it through a leaf an unmap had already cleared. The rule is now the pure crate's: `next_visit` answers `Visit(node)`, `Sweep` or `Finish`, the object records the epoch it was swept at, and it answers `Sweep` again whenever a pass has begun since; `finish` asserts the sweep is current. So every frame the walk gives back was swept after the last pass's visits, and no wait can arm on it after: no leaf maps a revoking frame once its pass's visits are done, and no fault installs one. An unmap, `discard`, `protect` to none or a space's end that cleared a paged leaf, revoking only frames it owns, leaves the frame in the index until a removal's walk sweeps it. The kernel loop is a plain match on that answer. The model takes the sweep as a step of its own, a frame at a time with every other step free to run between, and refuses a frame given back that the current sweep did not reach. `a_page_marked_during_the_sweep_is_swept_before_its_frame_goes_back` drives the pure API through r3's sequence: it passes, and under a once-per-walk rule (a checked one-line patch; the rule before r3 swept again after any visit) it is red. Both model runs red too, but only through `finish`'s assert, not their own oracle. `Pages::walk` has no production caller left and moves into the test module. Suggestions: the `vm` test sits after the test module's imports, and `REVOKE_BATCH` names `mapprobe`'s `shrunk` case, which needs two batches. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…r is its oracle
S1, required. `Pages::walk` is the one step of a walk: it answers
`Visit(node)` or `Sweep`, or ends the walk itself and answers `Finished`, the
set's frames given out to its caller's closure. `finish` is private, so no
caller can give frames back off the rule, and its assert goes. The kernel's
loop builds the waiters and the give-back closure from disjoint fields of the
same `State` each step and breaks on `Finished`; the test-only helper is gone.
S2, required. The model's oracle is the property itself: a `Wait(s, page)`
step keys a futex waiter on the frame the space's leaf maps, only a sweep's
read ends it (a visit or an unmap revokes no frame it does not own), and the
walk's end refuses a frame a waiter is keyed on. The `swept` set it replaces
was a proxy. `a_waiter_an_unmap_left_is_never_on_a_frame_given_back` explores
five steps from a waiter an unmap left and a walk begun with no mapper, which
reaches r3's sequence.
Controls, each a checked patch, the source restored byte-identical:
- sweeping before the pass's visits (B8's defect): both model runs red on the
oracle, "frame N given back with a futex waiter keyed on it", and four
scripted tests on their expected order;
- the rule before r3 (a sweep's flag reset by a visit, sweep while unset):
the no-mapper exploration red on the oracle, and
`a_page_marked_during_the_sweep_is_swept_before_its_frame_goes_back` red
("a pass began since the sweep").
B12: `swept` is the epoch the walk was last told to sweep at; `revoked` sweeps
as `Pages::walk` directs; `end_futex_waits` says what it does and why, not
when, which is the walk's rule alone; the module header names the sweep
before the walk's end, and its `Pages::walk` links name a production function
again.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e model's futex wait translates and arms apart B13. `clear_paged` shot its span down through the tables directly, which leaves the space's count of changes where it was; #1253's `Translation::holds` trusts an unmoved count, so a futex wait that translated before a visit cleared its leaf could arm after the walk's sweep, keyed on a frame the walk then gave back. The visit now shoots down through the space's own `shoot_down`, which counts the change under the space's lock before the sweep can run. `clear_paged`'s and `futex_word`'s docs say so. The model's futex wait is two steps, as the kernel's is: `Translate(s, page)` notes the frame and the space's count; `Arm` keys the waiter on the frame where the count has not moved and otherwise looks at the leaf again. A visit's clear and an unmap move the count. The reviewer's sequence is `a_wait_translated_before_a_visit_does_not_arm_on_a_frame_given_back`; with the visit's clear uncounted (a checked patch, the source restored byte-identical) it is red on the model's oracle, "frame 101 given back with a futex waiter keyed on it". B14: `Unmapped`'s doc says only that no space maps anything, and the double blank line above it is gone. Teardown takes the space out of the process data, as the handles line above it does, before ending it, so the process data's lock is not held across the space's shootdowns and pager calls. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…frame after any step The model's oracle refused a futex waiter on a given-back frame only inside the walk's end, so a wait that armed after the walk ended went unseen. Its `check`, run after every step, now asserts no waiter is keyed on a given-back frame. `a_wait_translated_before_a_removal_never_arms_on_a_frame_given_back` explores six steps from a wait translated before its page was withdrawn and a walk begun, holding B13's class rather than one sequence. With the visit's clear uncounted (a checked patch, the source restored byte-identical), that exploration and the scripted sequence are both red on the oracle, "frame 101 given back with a futex waiter keyed on it". Test code only. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… mapper ever linked Main's #1223 took the walk of all 64 futex buckets off unmaps. Step 2's revocation walk put it back on every removal of present pages from any paged object: once per 64 frames on each withdraw, fail, shrink and release. That covered `/tmp` deletes and the cache's withdraws, nearly all of whose objects were never mapped. Only a mapping's leaf can key a futex wait on a frame of a paged object. A pager may not map its objects, and a supply copies into fresh frames. An `Object` now records whether a mapper ever linked. `Object::link` sets the bit under the pager's lock and answers the epoch the new node is seen at, in place of the `epoch` getter, so no node links without setting it. The bit never resets, because an unmap clears its leaves without ending a wait keyed through them (B8's case). `Pages::walk` asks for `Next::Sweep` only where the bit is set, by the same rule as before: again whenever a pass began since the last sweep. The last sweep's epoch is now a `u64`, 0 before the first, in place of an `Option<u64>` reset at each walk's start. Every walk's epoch is at least 1, so the reset was redundant. This keeps `Object` at 88 bytes with the new bit, so the gate costs no slot space (`Entry` 120 bytes, slot 136, on both kernel targets). The model's `a_walk_begun_before_any_mapping_gives_back_no_frame_a_waiter_is_keyed_on` explores five steps from a walk begun on an object no mapper has linked. A mapper links during that walk, maps, waits, and queues another pass. The futex oracle stays green. Each control is a checked patch with the source restored byte-identical (https://github.com/ToyOSOrg/evidence/tree/a5fe696e711c2715f4a1bdc0dfa952c1759993fe/r9/controls): - Gating on a mapper linked now rather than ever is red on the oracle in four tests, among them `a_waiter_an_unmap_left_is_never_on_a_frame_given_back` and `every_interleaving_…`. - A bit never set is red in eleven tests. - A link during a walk left uncounted is red in the new exploration and in `long_runs_…`. - The faithful pre-r3 rule under the `u64` epoch is red in the same two tests as r4's control. B16: `end_futex_waits` names `revoke_sorted`, which walks every bucket, rather than the gated per-space `revoke_frames`. `holders` says it counts the spaces mapping the object. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…bytes B17. A pager's object slot grew with step 2, from 72 bytes to 136. `Entry` is now 120 bytes rather than 56: the walk state and the list of mappers take the extra 64. The record's charge per `/tmp` file, and its million-file figure, said 72. They now say 136 and about 136 MB. The sizes were measured by the compiler for `x86_64-unknown-none` and `aarch64-unknown-none-softfloat` with a compile-time probe, applied as a patch and reverted. The same probe gives 72 at main d1cefba: https://github.com/ToyOSOrg/evidence/tree/a5fe696e711c2715f4a1bdc0dfa952c1759993fe/r9/sizes Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…record says who measures again B19. The `Mappers` doc pointed at `Object::epoch`, which r8 replaced with `Object::link`. `Pages::object` said a released object's id may be reused because `release` takes its pages, but `release` went in the composition with #1273. The docs now say a node is seen at the epoch `link` answers, and an id is reused once its object is empty: `invalidate` marks its pages and the walk's end takes them. B20. The /tmp record now says that whichever of #1269 and #1258 lands second measures the combined slot again, updates the figures and deletes the sentence. #1258 rewrites the same paragraph for its own slot growth. S1, S2: `Entry.refs` says only what it keeps: the slot, free with the last reference. It also counts mappings, walks, queued removals and writes, which the old list missed. The record says every entry carries the 64 bytes of mapping state, not only a mapped object's. Doc comments and a record only. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Rebased onto main 302fb36 (#1252); head ecfb224. The resolution only keeps both sides, so run 43152933746 stays queued at 41f0e11. That head is held on The conflicts. Both were in one commit, B5's
#1252's own copies. It added two: the spawn's endowment list read, and its copy-out. Both already answer Range-diff
Checks at ecfb224, exit 0 each:
Evidence, including the range-diff: https://github.com/ToyOSOrg/evidence/tree/5a210f12d3bfcb0a205c0a8b967f718030cf2d17/r11 |
|
Orchestrator verification of the rebase onto main 302fb36 (#1252) at ecfb224. I read
No line of #1269 means anything different. #1252's two new copies, the endowment-list read and its copy-out, already answer So run 43152933746 at 41f0e11 (held on |
#1258) #1258 gave a paged object a write side, holders' writes against credit, a seal, a pager's record and a notice of holders' dirtying. This branch makes a removed page revoking until no mapping reaches it. The resolution keeps both sides, and makes them meet where a page is revoking: - A revoking page takes no write. `admit` refuses it as it refuses an absent page. `holder_fits` finds it `Absent`, so a holder's write over it goes to the pager and `admit_fresh`'s checked install never meets it. - The room a holder's credit paid for a page comes back as the page is marked revoking, as #1258 gives it back for a page gone before its write-back. The marking resets the page's state, so the walk's end gives nothing back twice. `a_revoking_page_takes_no_write_and_gives_its_credit_back_once` holds this. - `resize` keeps #1258's seal and its trimming of the dirtied range, and marks the pages past the size revoking rather than giving their frames out. `fail` and `invalidate` keep this branch's revocation. #1258's tests of shrinks, fails and releases settle their walks as this branch's do. - `Want::anew` is #1258's, a fresh `NONE`. The model's fault that asks afresh asks its run after it. - The slot table's two lists: a release unmarks both, and a mapping's end goes through `say_no_holders`, which waits out holders' writes too. - `PagedHolderObject::write` and `stat` sit beside `maps` and `link`, and `Paged::map` beside `write`, `append` and `stat`. A map takes the holder through `syscall::paged::holder` with `READ`. #1258's ABI range of dirtied pages is named `abi::PagedRange` beside the kernel's `PagedRange`. - libc's map of a served file goes through `on_fd_held`, whose holder closure #1258 made answer a `Result` of the call's own: `toyos_fs_map`'s does. - A truncation and the pager's writes need its hold now. `mapprobe` holds around its write in `coherent` and its shrink in `shrunk`, mints its holders to read, and makes its pager with a dirty ceiling of 2. At 0, the `coherent` case's own write was refused `DirtyFull`. - The kernel's overdue report says "wait overdue" since #1258, and the mapped-file row reads it so. The `/tmp` record measures the combined slot, since this lands after #1258: - A slot is 272 bytes: a 248-byte entry and two 12-byte marks. - The object's 152 bytes include the 48 of mapping's walk state. - It was 216 on main. - The sentence on whichever lands second goes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rames while it waits #1258's holder write copies its bytes from user memory into frames it drew from its pager's core, before it takes the write side. The source may be a page of a mapping that is absent. The copy then parked on the page's pager while it still held the frames, and frames are what that pager's supply draws. If holders' writes sourced from a mapping of the same pager drew the core dry, the pager could not supply the page they wait for, and none would end. This is the orchestrator's ruling for pinned copies, that no wait holds what its pager needs, and the staging copy now takes the same mode. It runs under `user_ptr::Pinned`, so an absent page stops it. The write gives every frame back and waits for the source pages holding nothing (`wait_in`). It then draws and copies again, against the object as it stands then. A copy that faults answers its own cause, `BadAddress` or `Io`, as every other copy since B5 does, where #1258 flattened it to `BadAddress`. `Pinned`, `Copies` and the fault handler's docs say what the mode guards: a copy that holds what no wait may hold, page pins or a pager's frames. `mapprobe`'s `written` case is the duty the memory record kept for whichever of #1258 and #1269 landed second. The case: - endows a mapper with a write holder of an empty object granted a page of credit; - the mapper writes it from the first page of its mapping, which no one has supplied; - the pager hears the request and supplies the run; - the mapper's write lands whole, and the pager reads the page back as the supplied bytes. The record's paragraph on the owed test goes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
#1258 gave the pager one wait that reports itself overdue past the report time, `wait_changed`, and one draw of frames, `draw` with `materialize`. A fault's wait and a touched hole's zeroed frame each had a copy of those. They now call the pager's. The wait still requests the fault's run and lasts until the page is no longer absent, the version moved or the pager is gone. The hole's frame still comes from the pager's core, with the same refusal where there is no room. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…he switch carries FS and GS (#1264) No conflicts. #1227 removed libc's `refuse_files`: every refusal now goes through `set_errno`, which reads `toyos::Failure`'s one table. A refused map of a file answers through it too. A file its server maps no pages of still answers `ENODEV`, as POSIX names that refusal of `mmap`. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Composed with #1258 and main 29c5f2d; head 202566e. The composition changes kernel behaviour, so I cancelled 43152933746 and deleted A merge, not a rebase.
The merge's resolution (
B20's duty: the combined slot. It is 272 bytes, against 216 on main:
The memory record's duty: the pinned-copy test (9a29a35).
ea33f5a: a fault's wait and a touched hole's frame call #1258's 202566e merges main 29c5f2d (#1227, #1264, #1280), with no conflicts. #1227 removed libc's Checks, full logs: https://github.com/ToyOSOrg/evidence/tree/431cbdf36e6c555c96eff50611959023437a6520/r12
|
Review r12 of #1269 at 202566eScope: the four first-parent commits after ecfb224. 6e43e99 was read with ArchitectureThe composition keeps each design whole and joins them at one rule: a revoking page is no longer the file's. So:
This is #1258's "gone before its write-back" rule, applied at the moment the bytes stop counting. Marking resets the page's state, so the walk's The pinned-copy change applies the existing ruling to one more copy that holds pager resources, for about 26 net kernel lines. ea33f5a deletes 25 lines that duplicated the wait and the draw. A merge in place of a rebase is the orchestrator's call, which I don't revisit. The walk, finish, visit, sweep and link/unlink code is unchanged from ecfb224, so B8's and B10's rules stand as reviewed. Each requested check:
Growth: the pinned-copy loop adds +65/−39 kernel lines, the dedup −25, and the merge resolution's credit-at-marking a few lines plus a 23-line pure test. FindingsB1 —
B2 —
S1 — S2 — PR description (the orchestrator's)
Neither blocker is a code change: one is a record line, the other comment text. Neither needs another host or guest run. SEND BACK |
…say what holds B1. In the combined layout, the walk state mapping needs adds 40 bytes to the object: 152 against main's 112. The record's 48 was r9's figure on the layout before #1258. The record now says 40 to the object, and with the list of mappers 56 to a slot. It also says that main's 216 was measured on x86-64. B2. `draw`'s doc no longer says its frames are completed outside the lock: `Index::zeroed` materializes its frame under it. The module header says a holder's write copies into frames drawn first, not held aside. S1. The comment over the holder write's staging copy repeated its doc and the module header, so it goes. `faulted()`'s doc and panic name a copy outside `Pinned`, which is what they mean now that `Pinned` guards a pager's frames as well as pins. S2. `mapprobe`'s `written` case says what it establishes: the write stops at the absent page, waits, draws and copies again, and lands whole with the supplied bytes. That the frames go back while it waits is the code's to show. Doc comments, a panic message and a record only. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Review r12 answered; head 63f18b2. It is one text commit on 202566e: doc comments, one panic message's text and a record. Run 43170820169 at 202566e is unchanged and still queued.
|
|
Orchestrator verification at 63f18b2, from 202566e. I read the diff: doc comments in
The body corrections are in. Run 43170820169 at 202566e, which is code-identical, is the landing run, and #1269 is queued when it is green. |
Draft. On main 29c5f2d. The branch was rebased onto 302fb36 (#1259, #1273, #1271 and #1252 among it). Main with #1258 is merged in (6e43e99), followed by 9a29a35 and ea33f5a. Main 29c5f2d (#1227, #1264, #1280) is merged in after them (202566e), and review r12's text follows (63f18b2). Every commit here is step 2's, composed with #1273's slot table, #1223's per-space futex revocation and #1258's holder writes. Review r1 was answered in acff199..5eadbcd, r2 in 5513d27 and 6455b27, r3 in d594827, r4 in 76bcaa5, r5 in eb7deec, r6 in d1ad82e, r8 in 54c90cc and 54d6a6a, and r9 in ecfb224;
populatekeeps main's hoisted fault-around shape in every commit. For r8 the branch was rebuilt to restore a line of its first commit's message, andmapprobe'spipe_endtakes its endowed pipe end typed, as main's typed handles (#1239, #1242) require, in the probe commit and every later one; nothing else differs from fd13c11's trees.What changes
Step 2 of mapped paged objects (memory stage 7b, design rev 5): a file's pages are mapped read-only and shared through its holder. A mapping maps the pager's own frames, so a mapper sees a write as it lands; nothing is copied and the file's length is never committed.
mmap,close, unlink keeps the file until the last mapping goes.revoke_sorted), since such a frame is no one space's. An object no mapper ever linked, as nearly every/tmpfile and cache withdraw is, skips that sweep: only a mapping's leaf keys a futex wait on its frames. The object's bit is set byObject::link, the only way a node learns its epoch, and never resets, since an unmap clears its leaves without ending a wait keyed through them. The walk's steps:Pages::walkanswersVisitorSweep, or ends the walk itself (Finished, its privatefinishgiving the frames out), and sweeps again whenever a pass began since it was last told to, so a page marked while a sweep had the lock dropped is swept too and no caller can give frames back off the rule. No wait arms on a frame once its pass's visits are done: no leaf maps a revoking frame, no fault installs one, and a visit's shootdown is counted, so a futex wait that translated before the visit looks at its leaf again (A futex wait translates its word once and checks it with one load #1253'sTranslation::holds) rather than trust the translation; so a waiter keyed on a frame through a leaf an unmap,discard,protectto none or a space's end cleared earlier, which revoke only frames they own, is ended before the frame is reissued. A page a pager names is placed by checked arithmetic, so no pager input can overflow it. One walker per object; pager end never waits (a removal during a walk is taken by the walker's next pass). A walk's end names again every waiter whose page ended absent.Fault::Mapping(SIGBUS) and one record naming the pager, object, page and cause. A kernel copy answersIoinstead ofBadAddress(a per-thread stop word the copy's fault leaves); pipes and paged calls carry it. A touch of a page wholly past the object's end ends the process withFault::Mappingtoo (the orchestrator's ruling); nothing is there, so a copy from it, or a futex word in it, answersBadAddress. A futex wait or wake on a mapped page that is absent or lost is a spurious wake, as the manual says of swapped words./tmp) gets a zeroed frame of its pager's, drawn and charged as a supply's frame is (pmm::alloc_promisedfrom the pager's core, or a held-aside frame zeroed assupplyalready does), installed clean under the pager's lock; with no room, the fault is refusedNoRoom(N4). There is one draw: spawnperf's first-touch shared memory uses the samealloc_promised, and A draw of many promised frames takes the allocator's lock once #1268's batch draws are not needed by a fault, which draws one frame.AddressSpace::end), so a revoker's last reference to a space frees nothing;Dropasserts no paged range is left.Paged::map,files::map(through the descriptor's holder;NotSupportedwithout one); libcmmapof a filePROT_READ, shared or private (B5: a private read-only mapping shares the pages until written). Other protections still answerENODEV(record updated).Decision: no wait holds a pin (the orchestrator's ruling)
A kernel copy that holds a page pin never parks on an absent mapped page. Such a copy runs under
user_ptr::Pinned; its fault on an absent paged page stops the copy (Stopped::Absent) instead of waiting, and the call lets its pins go, waits for the window's pages holding nothing (wait_in), and copies the rest of the chunk again. Three copies use it. Two are pinned copies, a holder's read into user memory and the pager's write from user memory, and no process reaches them: a pager's process may not map, and every mapping is read-only, so no pinned copy's window can be an absent paged page. The third is #1258's holder write (9a29a35), which stages its bytes into frames drawn from its pager before it takes the write side. Those frames are what that pager's supply draws, so the staging copy stops at an absent page too, gives every frame back, waits holding nothing and draws again.mapprobe'swrittencase shows a holder write sourced from a mapped page not yet supplied landing whole.Manual
Memory page: a mapping maps the cache's own pages and holds its file; a page leaves the cache only once no mapping reaches it; a wait for a file's page behaves like swapped memory's (D6); a lost page ends the program with a diagnostic and a copy answers an I/O error; a touched RAM-file hole is resident within its server's capacity. Files and services pages: a file server's end revokes every mapping of its files (D1, in the ruling's words).
Checks and evidence
What each check covers, and why it suffices (the owner's testing policy: touched modules only):
cargo test -p kernel --lib paged::, 45 tests with An open file is written and stated through its paged object, one write at a time, against credit #1258's merged in, r8's exploration from a walk begun on an object no mapper has linked, which a mapper links during, among them, the walk's set, r3's sweep sequence, r5's futex wait translated before a visit, and explorations from a waiter an unmap left and from a wait translated before a removal among them, the model's check refusing a waiter keyed on a given-back frame after every step; its visit and its sweep are the kernel's rules with batches of one, each a step others run between, and its oracle includes a futex waiter that translates and arms apart as the kernel's does, keyed through a leaf and ended only by a sweep): the index's revocation with two spaces mapping one object, every interleaving at depth, invariants at every step (each leaf maps the index's frame or a revoking slot's; a frame goes back only after every mapper's visit). That a node is linked exactly while its space has a range holds by construction, since the model's map and unmap are each one step;checkdoes not test it; parked faults all complete once removals stop; a fault answered, shrunk and grown asks afresh. Current controls, each a checked patch: the reviewer's (r3) cursor that reads only the first batch reds both model runs ("maps given-back frame") and the walk's-set test; sweeping before the pass's visits (B8's defect) reds both model runs on the model's own oracle, a futex waiter keyed through a leaf ("frame N given back with a futex waiter keyed on it"); the rule before r3, a visit resetting the sweep flag, reds the exploration from a waiter an unmap left with no mapper on the same oracle, anda_page_marked_during_the_sweep_is_swept_before_its_frame_goes_back("a pass began since the sweep"). A visit whose clear is not counted (B13 as the rebase left it) redsa_wait_translated_before_a_visit_does_not_arm_on_a_frame_given_backand the exploration from a wait translated before a removal on the same oracle ("frame 101 given back with a futex waiter keyed on it"). The sweep gate's controls (r8, https://github.com/ToyOSOrg/evidence/tree/a5fe696e711c2715f4a1bdc0dfa952c1759993fe/r9/controls): gating on a mapper linked now rather than ever reds four tests on the oracle, among them the exploration from a waiter an unmap left; a bit never set reds eleven; a link during a walk left uncounted reds r8's exploration andlong_runs_…on the oracle; and the pre-r3 rule under r8'su64sweep epoch reds the same two tests as before.kernel/loom/tests/paged_ranges.rs, the kernel's ownobject/paged/ranges.rs): an unmap clearing its leaf races a parked fault letting its hold go; the last to let go sees the leaf cleared. Passes; the negative controlranges-less-relaxedreds with loom's "Causality violation". Park against supply is not modelled separately: its lost-wake freedom is the watch's register-check-park protocol, whichloom_watch.rs'sa_post_racing_a_registration_leaves_nobody_parkedchecks with the real watch, and the ready check isPages::wait_overunder the pager's lock, whose liveness the pure model checks. I judged a second loom model would re-check the same edge; say if you want it.cargo test -p kernel --lib --features sched-check(525 passed), the kernel's four clippy shapes with-D warnings,cargo test --test toyos-checks(55),cargo run -- --ci host lint(5 of 5 green),cargo run -- --ci host models(93 of 93 green), andcargo run -- --build-onlyoftestcases,benchcase, AArch64'svirtjobcaseand both default images, exit 0 each (https://github.com/ToyOSOrg/evidence/tree/431cbdf36e6c555c96eff50611959023437a6520/r12). The merge with An open file is written and stated through its paged object, one write at a time, against credit #1258 and 9a29a35 each compile on both kernel targets, with the SDK and the kernel's tests. The first run of these at ea33f5a was red in lint and every image ontoyos_fs_map's closure, which only a target build of the SDK compiles; the fix is folded into the merge. Earlier rounds' host evidence is in r8 to r11 beside these.tests/guest/mapprobe, launched bymapped_file), each case needing two processes and real tables: a mapper sees the pager's write; its mapping holds the object after its handle closed; a fault parks and is supplied; a withdrawn page is asked for again and comes back with its bytes; a supply held past the report time is reported overdue and waited out (the x86-64 row reads the kernel's report off the serial line); unmap under a parked thread; kill of a thread parked in a fault and in a pipe write's copy, which writes nothing; a hole reads zero with no request and costs one page, and with no room ends the mapperFault::Mapping; an 80-page object every page of which two mappers touched is shrunk to one, and a touch of the first and of the last revoked page, one of them cleared by the walk's second batch, ends each mapperFault::Mapping(SIGBUS, the orchestrator's ruling); a holder's write whose bytes come from a mapped page not yet supplied lands whole once the pager supplies it (An open file is written and stated through its paged object, one write at a time, against credit #1258's write, staged under the pinned-copy mode); the pager's end answers a write from the mappingIoand ends the mapper. Rows:a_mapped_file_follows_its_pager(x86-64 QEMU),virt_mapped_file(AArch64, a fault that parks there), and themapped_filemember of thetestcasesshared boot, which The shared boots run as guest rows, each member judged by its own exit #1271 runs under QEMU astestcases_members_exit_0and which runs on both benches. The x86-64 row keeps its own boot under The shared boots run as guest rows, each member judged by its own exit #1271:testcases_members_exit_0judges each member by its exit alone, and the row also asserts the kernel's report on serial that a mapper's fault waited past its pager's report time and then no longer did (D6), which the job cannot see; the job's cases are judged in both. Run 43170820169 at 202566e:a_mapped_file_follows_its_pager virt_mapped_file osbench_map_group_exits_0 a_user_copy_faults_in_mid_copy_or_ends_as_bad_address virt_user_copy_faults a_spawn_from_an_image_frees_it_when_the_child_ends testcases_members_exit_0,a_spawn_from_an_image_frees_it_when_the_child_endsbeing the census of a process's end, which every end now empties throughAddressSpace::end, andtestcases_members_exit_0everytestcasesmember, this PR's included. Results are added here when they arrive; no guest row can reach the sweep race, which the host model holds. No guest result exists yet at this head. 43143902443 at fd13c11 failed at its build step:mapprobedid not compile against main's typed handles (A receive reports what each handle names, and a typed handle is made of a received one only where the kernel said so #1239, Every server admits its clients through one table, toyos::admission #1242), whoseEndowments::takeanswers the type asked for, so no row ran. The fix,pipe_endtaking its pipe end typed, is folded into the probe commit and every later one, and the images the six rows boot,testcases,benchcaseand AArch64'svirtjobcase, and both default images now build, exit 0 each (https://github.com/ToyOSOrg/evidence/tree/059774f5291f145d1d01e560d2c6fe737ddecd1f/r9/images); the host checks build no guest crate, which is how it was missed. 43148792191 at 25a2030, which carried the same compile error, was cancelled unrun, 43150183855 at f3e456f was cancelled while queued once r9's doc and record commit made 4a4d3fe the head, and 43150337391 at 4a4d3fe was cancelled while queued once the branch conflicted with The shared boots run as guest rows, each member judged by its own exit #1271; the earlier runs at 26d1920 (43119443467, 43121654422) were cancelled unrun once the composition with A pager's objects are charged as they are made, and /tmp holds its files by that #1273 changed it. 43084281934 and 43093955847 were cancelled unrun, and 43099497824 while it built, as superseded.The guest run's head, 202566e, is the head's code: 63f18b2 changes only doc comments, a panic message's text and a record. 43152933746 at 41f0e11 was cancelled unrun once the composition with #1258 changed the kernel's behaviour (the holder write's staging mode); its hold branch is gone. No guest row has yet passed
mapprobe: every earlier run that built it was cancelled or failed its build.Owed on metal (both benches are down; recorded in the memory track record, and run on main in one batched boot when a bench returns):
testcasesboot, whosemapped_filemember maps a paged object from a second process and whosea_pager_s_end_answers_its_waiting_holders_goneexercises the rewritten pager end, and theshared-debugandproctreecaseboots. Main must show every job of each boot exit 0.system(its pipe rows),files,ipc,procsandmemgroups, main before this PR against main after, four boots a side. Main after must show no row worse than noise: every fault and pinned copy changed, and every process exit now empties its space through the full clear.mapgroup on main beside Linux'smmap, recorded with each row's ratio:touch_16m,threads_touch_16m,read_4kandtruncate_255. Their correctness runs in a guest (osbench_map_group_exits_0). How a mapping's faults, reads and revocation compare with Linux's is not measured on metal.Evidence (host checks, loom model and control, pure-model controls): https://github.com/ToyOSOrg/evidence/tree/d40d65f0b7c1853a833b368862df13b0b50a7497/r1
Owed, and risks
mmapormprotect) as a copy range of the paged object. libc refuses thoseENODEV; step 3 builds it (recorded in the memory track's item 5).threads_touch_16mfaults a RAM file's pages, which are never absent. Owner map7b with step 3; exit a many-threads cold-fault row on a DATA file past its pager's capacity, with the cold DATA miss in stages beside it.mm/space.rs; whoever lands second resolves./tmprecord's charge per file now says so (https://github.com/ToyOSOrg/evidence/tree/94fd400ddab5d9c2ff776ac9df66f1b0bb88b768/r12/sizes).🤖 Generated with Claude Code