Repository navigation
ffi: a cancellation wakes its target, and no cancellable wait polls - #33
Draft
SnowCheetos wants to merge 8 commits into
Draft
SnowCheetos wants to merge 8 commits into
SnowCheetos wants to merge 8 commits into
Conversation
…wake
## Why
kore-ffi's cancellable waits slice their parks, because no wake names a
thread. Kore `a4ab7234` adds the wait and the wake that remove the slice.
They arrive here through the exporter rather than as edits to the snapshot.
## What
- `native/` is re-exported byte for byte at
`a4ab7234e2fe60b43a1df42f12be8f636255fc7a` with `tools/sync-native.py`,
one commit past MicroPerceptron/kore#1494's branch head (`76fddb9f`). Two of
the six commits since `0018956a` reach the closure, which keeps its 26
packages and 382 files:
- `kore-rt`: `futex::wait_unless`, a wait another thread can end;
`futex::wake_thread`, the wake that ends it; and `futex::current_thread`,
now public. The thread controller adds `Controller::slice`,
`Controller::wakes_threads`, and a public `UNREACHED_SLICE`.
- The services' `boot.toml` digests, #1494's reseal over the parking
controller.
- No exported manifest changed, so `native/Cargo.lock` did not.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ACHC7hXQ3xRtyu6Yt31jXQ
A cancellation request was a flag that no wake carried, so a cancellable `kore_thread_join` or managed-thread `kore_futex_wait` parked one millisecond at a time to notice it. An idle cancellable waiter woke a thousand times a second. - A managed thread records its band when it starts. `kore_thread_cancel` stores the request (`SeqCst`, was `Release`) and then wakes that band with `futex::wake_thread`. The wake is relayed through the controller, the one owner of a send into each managed thread's doorbell. - `kore_thread_join` and a managed thread's `kore_futex_wait` wait with `futex::wait_unless`. It reads the request again once the waiter is registered, and the wake reads that registration, so neither misses the other. Neither wait sets a timeout of its own. `CANCEL_SLICE_NS` is gone. - Only a thread the controller cannot wake parks in bounded slices, now the controller's own rule and cadence (`Controller::slice`, `UNREACHED_SLICE`). That also bounds a joiner the controller cannot reach, which before parked with no bound and no wake. - A canceller whose wake cannot reach the controller's threads is refused with EAGAIN and records nothing, as create refuses it: a thread that neither started the controller nor was created through it. A request a parked target never saw would be a silent loss. A host test drives the refusal. - `kore.h` is regenerated with doc changes only, so the ABI is unchanged. `docs/runtime.md` says how a cancellation reaches a parked thread, and drops two statements the parking controller had made stale: a 1 ms controller scan, and controller threads without doorbells. `docs/provenance.md` records the export. The thread guest fixture's comment describes both ways a cancellable worker waits. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ACHC7hXQ3xRtyu6Yt31jXQ
… first wait Kore `40de2582` closes a managed thread's founding window. The controller sets a child's reach bit only after `spawn_with_arg` returns, and the child ran its callback at once. A cancellable `kore_futex_wait` the child entered before that bit took `Controller::slice`'s unreached bound, and `sliced` kept it until the wait's first real wake. `child_entry` now settles on its record until its founding is published, which follows the reach bit. A thread the controller founds with a doorbell is therefore reached from its first wait, and only a thread it cannot wake keeps the slice. The export is byte-exact. Two commits since `a4ab7234` reach the closure, which keeps its 26 packages and 382 files: `40de2582`'s `thread_controller.rs`, and the `services/swap/boot.toml` digest of Kore's reseal over the cancellation wake (`bfecfd17`). No manifest changed, so `native/Cargo.lock` did not. `docs/provenance.md` records the export, and `docs/runtime.md` says why a founded thread never takes the slice. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ACHC7hXQ3xRtyu6Yt31jXQ
`ft/fervent-shannon-egp5pt` moved to `0460f5c`. It carries three native re-exports, at Kore `2a0730dd`, `6c57f344` and `2d4998ba`: founder arenas for founding threads, a founding's staged space waiting for the reap, and Kore's C library. It also carries stdio for C programs. Both sides changed `native/`, which is never merged by hand. It is re-exported here by `tools/sync-native.py` at Kore `61877290`, the merge of #1494's branch into this change's. The closure is now 27 packages and 401 files. Against #1494's export, only kore-rt's `futex.rs` and `thread_controller.rs` and the record differ. Everything outside `native/` merges cleanly, and `docs/provenance.md` records the export. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ACHC7hXQ3xRtyu6Yt31jXQ
`ft/fervent-shannon-egp5pt` moved to `98186bf`, with three changes: - a native re-export at Kore `10c7b400`, where kore-rt names the link window's free span once; - descriptors and mmap over the capabilities a C program holds; - rustix 1.1.6. `native/` is re-exported by `tools/sync-native.py` at Kore `4a56f827`, the merge of #1494's branch into this change's. The closure stays at 27 packages and 401 files. Against #1494's export, only kore-rt's `futex.rs` and `thread_controller.rs`, the record, and five services' `boot.toml` digests differ. The digests come from #1494's reseal `f2644e5b`, which followed its export. Everything outside `native/` merges cleanly. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ACHC7hXQ3xRtyu6Yt31jXQ
Contributor
Author
|
No fix exists in the repository yet. The step could stop depending on Ubuntu's mirrors by taking Generated by Claude Code |
Kore's #1494 merged main `f2dc8309` and resealed over it (`e6b108d1`). MicroPerceptron/kore#1534 merges that into the cancellation wake at `eb59823a`, and this re-exports the closure there with `tools/sync-native.py`. Main reaches the closure through the seat clipboard and Cmd chords (kore-abi, kore-window), Files' DagFS watch plane and kore-rt's owed service wakes, DagFS's cwd anchor and path folding, and #1494's reseal digests in five services' `boot.toml`. The closure is 27 packages and 406 files. Against Kore `e6b108d1`, only kore-rt's `futex.rs` and `thread_controller.rs` differ. `native/Cargo.lock` is unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ACHC7hXQ3xRtyu6Yt31jXQ
`ft/fervent-shannon-egp5pt` moved to `2ce41f1`: a C program's `main` receives its arguments (`crates/c`), and `native/` is re-exported at Kore `dfece644`, where the process page carries the name a program was run by. Both sides changed `native/`, which is never merged by hand. `tools/sync-native.py` re-exports it at Kore `5c09f155`, the merge of #1494's round into MicroPerceptron/kore#1534's. The closure is 27 packages and 407 files. Against Kore `4b236fbe`, only kore-rt's `futex.rs` and `thread_controller.rs` differ. Against libkore#32's export, five services' `boot.toml` digests from #1494's later reseals differ too. `docs/provenance.md` records the export. Everything outside `native/` merges cleanly. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ACHC7hXQ3xRtyu6Yt31jXQ
Kore's #1494 moved to `fe9603e3`: the kernel offers a function to drivers only on positive evidence, and a claim names its holder. MicroPerceptron/kore#1534 merges that at `7c0be6e8`, and this re-exports the closure there with `tools/sync-native.py`. libkore#32's branch has not moved, so nothing else changes. kore-abi's device state changes and gains its device classes (`device/class.rs`). The closure is 27 packages and 408 files. Against Kore `fe9603e3`, only kore-rt's `futex.rs` and `thread_controller.rs` differ, and `services/swap/boot.toml`, whose digests are this change's reseal over the ioctl round. `native/Cargo.lock` is unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ACHC7hXQ3xRtyu6Yt31jXQ
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
A cancellation request now wakes its target, and no cancellable wait polls.
Before,
kore_thread_cancelonly set a flag that nothing woke the targetfor, so a managed thread's cancellable
kore_thread_joinorkore_futex_waitparked in 1 ms slices (CANCEL_SLICE_NS) to re-read it.An idle cancellable waiter woke a thousand times a second.
The native half lands in Kore first, as
AGENTS.mdrequires. It isMicroPerceptron/kore#1534, stacked on MicroPerceptron/kore#1494, and
arrives here through
tools/sync-native.py. This PR is stacked on#32 (
ft/fervent-shannon-egp5pt, the libkore half ofMicroPerceptron/kore#1494), which adds
kore-cand the parking threadcontroller this builds on.
What
native: re-export at Kore a4ab7234: a byte-exact export. Two of thesix Kore commits since
0018956areach the closure, which keeps its 26packages and 382 files:
a4ab7234, this change's kore-rt half:futex::wait_unless, a wait whose caller condition is read once thewaiter is registered;
futex::wake_thread, which kicks one thread's doorbell and reads itsregistration first;
futex::current_thread, now public;Controller::slice,Controller::wakes_threadsand apublic
UNREACHED_SLICE.76fddb9f, MicroPerceptron/kore#1494's reseal, which moves fiveservices'
boot.tomldigests.native/Cargo.lockis unchanged.ffi: a cancellation wakes its target:kore_thread_cancelstores the request (SeqCst) and then wakes thatband, relayed through the controller, the one owner of a send into
each managed thread's doorbell.
kore_thread_joinand a managed thread'skore_futex_waitwait withwait_unlessand set no timeout of their own.CANCEL_SLICE_NSisgone.
slices, now the controller's own rule. That also bounds a joiner the
controller cannot reach, which before parked with no bound and no wake.
neither started the controller nor was created through it) is refused
with
KORE_THREAD_EAGAINand records nothing, as create refuses it. Arequest a parked target never saw would be a silent loss. In a C
program, the only such caller is thread 0 running a
kore_fs_runstep.kore.hchanges in doc comments only; the 85-symbol ABI is the same.docs/runtime.mdsays how a cancellation reaches a parked thread, anddrops two statements the parking controller had made stale.
docs/provenance.mdrecords the export.native: re-export at Kore 40de2582: closes a thread's foundingwindow. The controller sets a child's reach bit only after
spawn_with_argreturns, andchild_entryran the callback at once. Acancellable
kore_futex_waitthe child entered before that bit tookController::slice's unreached bound, andslicedkept it until thewait's first real wake.
child_entrynow settles on its record until thefounding is published, which follows the reach bit. A thread the
controller founds with a doorbell is therefore reached from its first
wait, and only a thread it cannot wake keeps the slice.
a4ab7234reach the closure, still26 packages and 382 files:
40de2582'sthread_controller.rs, and theservices/swap/boot.tomldigest of Kore's reseal over thecancellation wake (
bfecfd17).native/Cargo.lockis unchanged.docs/provenance.mdrecords the export.docs/runtime.mdsays why afounded thread never takes the slice.
A merge of c: libkore.so, the runtime and host of an independent C program #32's newer branch (
0460f5c),which brings three native re-exports (founder arenas, a founding's
staged space waiting for the reap, Kore's C library) and stdio for C
programs.
native/, which is never merged by hand.tools/sync-native.pyre-exports it at Kore61877290, the merge of#1494's branch into MicroPerceptron/kore#1534's. The closure is now 27
packages and 401 files.
futex.rsandthread_controller.rsand the record differ.native/merges cleanly.A merge of libkore#32's next round (
98186bf): descriptors and mmapover the capabilities a C program holds, kore-rt naming the link window's
free span once (exported at Kore
10c7b400), and rustix 1.1.6.native/is re-exported at Kore4a56f827, the merge of #1494's nextround into MicroPerceptron/kore#1534's. It is still 27 packages and 401
files.
futex.rsandthread_controller.rs, the record, and five services'boot.tomldigests differ. The digests come from #1494's reseal
f2644e5b, whichfollowed its export.
native/merges cleanly.native: re-export at Kore eb59823a: Kore's #1494 merged mainf2dc8309and resealed over it (e6b108d1), andMicroPerceptron/kore#1534 merges that at
eb59823a. libkore#32's branchhad not moved, so this commit is a re-export alone.
(kore-abi, kore-window), Files' DagFS watch plane and kore-rt's owed
service wakes, and DagFS's cwd anchor and path folding. Five services'
boot.tomldigests come from #1494's reseal over the merge.e6b108d1,only kore-rt's
futex.rsandthread_controller.rsdiffer.native/Cargo.lockis unchanged.docs/provenance.mdrecords the export.A merge of libkore#32's arguments round (
2ce41f1): a C program'smainreceives its arguments (crates/c), and libkore#32's export atKore
dfece644, where the process page carries the name a program wasrun by.
native/is re-exported at Kore5c09f155, the merge of #1494'sround into MicroPerceptron/kore#1534's: 27 packages and 407 files.
4b236fbe, only kore-rt'sfutex.rsandthread_controller.rsdiffer. Against libkore#32's export, fiveservices'
boot.tomldigests from #1494's later reseals differ too.native/merges cleanly.native: re-export at Kore 7c0be6e8: #1494's platform round, wherethe kernel offers a function to drivers only on positive evidence and a
claim names its holder. MicroPerceptron/kore#1534 merges it at
7c0be6e8. libkore#32's branch has not moved, so this commit is are-export alone.
closure is 27 packages and 408 files.
fe9603e3, only kore-rt'sfutex.rsandthread_controller.rsdiffer, andservices/swap/boot.toml: swaplinks kore-rt's futex, so its digests are MicroPerceptron/kore#1534's
reseal over the ioctl round.
native/Cargo.lockis unchanged.docs/provenance.mdrecords theexport.
Why the order is lossless
The canceller stores, then reads the target's registration, before it
kicks or relays. The relaying controller's sweep reads it again before it
kicks. The target registers, then reads the request. All of these accesses
are
SeqCst, so one of the two sides sees the other:read, so the target does not park.
because the target armed before it registered. That kick resolves the
park.
Kore's host suite pins the stop-after-registration order. One test checks
the order directly, and another runs the writer at each of the five points
it can meet a waiter. With the stop read moved before the registration,
both fail, the second with the lost wake itself.
Verification
On this head (
cbe7b0a),AGENTS.md's set passes:make fmt test check docs owners cross miri bindings-check.make test: 674 Rust tests pass and none fail, and the 7 tool testspass. The 10 ignored are kore-rt's 6
ignoredoc examples and kore-vol's4 loop-device tests, which need root. kore-rt's suite (471) runs here
through the export, including:
futex::a_stop_is_read_only_once_the_waiter_is_registeredandfutex::a_stop_published_before_its_wake_is_never_missed, the ordertests;
futex::off_metal_a_stoppable_wait_refuses_before_reading_its_stop;futex::a_thread_wake_kicks_only_a_registered_waiter_and_relays_a_refusal;thread_controller::an_unstarted_controller_wakes_no_thread_and_bounds_every_wait;thread_controller::a_child_runs_its_callback_only_once_its_founding_is_published,which fails with the founding wait removed.
kore-ffi's suite (31) includes
thread::a_cancel_no_wake_can_announce_is_refused_and_never_recorded.make check: clippy with-D warnings, andtools/check-native.py:the export is the exact recorded bytes of Kore
7c0be6e8.make docs: rustdoc with-D warnings.make cross: the Kore user targets for x86_64, aarch64 and riscv64.tools/check-program.pylinkslibkore.soon each: 130 exportedsymbols, the declared ABI exactly. The added symbols are #1494's: Kore's
C library, descriptors and mmap, and
__kore_program_arguments.make miri: 94 tests.make ownersandmake bindings-check:kore.hregeneratesexactly, and its C and Zig declarations check on every ISA.
This head passes this repository's CI (run 43163880067):
host,miri,and
targetsfor x86_64, aarch64 and riscv64gc. So dida940932and33ba95cbefore it (runs 43151521652 and 43139759911).c839547before them, the threetargetsjobs died atsudo apt-get install -y llvm, because the hosted runner could notresolve Ubuntu's mirrors (see the comment below). Every check before
that step passed.
was the runners', not this PR's.
MicroPerceptron/kore#1534 pins this head. There,
make keytest-tcc-x86passes on the resealed production image, run with a 1200 s session budget
because #1494's new steps carry the session past 600 s under TCG (that PR
says how):
tccat Kore's shell against thisrevision's
libkore.so.sum. The keytest also runs #1494's
hello.candmemory.cthrough the Clibrary, and its
argsprogram, whosemainreceives its name and thewords of its command line.
(
CANCEL_PARKS, exit 28). The controller therefore reached each onebefore its callback ran, and neither wait has a slice.
pthread_join, then the one parked inkore_futex_waitwith no timeout, on a word nothing wakes. Each joinswith
PTHREAD_CANCELEDwithin a second, and the tour ends withexit 42.run-boot-gate-x86passes there too: 19/19 services founded. That PR liststhe rest of Kore's image matrix. This repository's checks are compiler,
host and Miri evidence, not boot evidence.
Not run:
tools/check-thread-guest.py. Korefc2a5685reshapedhello'sentry, so the runner's injection hook no longer exists there, and neither
does the
ExitCode::appits replacement calls. The runner needs its ownupdate.
🤖 Generated with Claude Code
https://claude.ai/code/session_01ACHC7hXQ3xRtyu6Yt31jXQ