Skip to content

kernel: no kernel thread but the idle loop; the console UART is a userland driver's (K4, K6) - #1175

Merged
Japabu merged 9 commits into
mainfrom
no-kernel-threads
Nov 4, 2026
Merged

Japabu merged 9 commits into
mainfrom
no-kernel-threads

Conversation

@Japabu

@Japabu Japabu commented Nov 4, 2026 •

Copy link
Copy Markdown
Collaborator

Continues #1165, which GitHub would not reopen after a resync attempt; its review rounds r1–r3 and their responses are there.

Small-kernel track, stages K4 and K6, by the owner's ruling that the kernel creates no thread but each CPU's idle loop; and, in the same thread-lifecycle area, a yield that yields and detached threads that free themselves.

Problem

klogd (kernel/src/log/console.rs) was the last kernel thread: the console UART's one writer between the boot and the stop, draining the record ring and the lines logkeeper queued on the kernel console. Every kernel-thread provision existed for it: sched/kthread.rs and its row table, is_kernel_task/current_is_kernel_thread, quiesce's exemption, the scheduler's zero baseline, a kernel-space task and its reserved PCID/ASID. std's yield_now was a spin hint, and a detached thread's stack and table place waited for the process's next spawn.

Now

The kernel writes the UART only where no process can: inline as each record commits until log::console::hand_over (before userland can claim the UART), from the machine's stop once userland is stopped, and on every fatal path. Between them the UART is /system/bin/uart's.

The UART is a claim like any device: a new uart device class (toyos_abi::uart). On x86 it is an isa row, COM1's eight ports bound to the reading process and IRQ 4 as records; COM1 leaves pio::FIXED and is that row's (the ACPI mediation now answers ClaimedPort for it). On AArch64 the row is the SPCR's PL011: its register frame installed as an uncached aperture with the description, and its interrupt a level SPI routed to the row (irqchip::route_spi/set_spi_masked, arch::aarch64::pio::Wire), masked by the handler until the holder acknowledges.

One carrier serving, two channels (system/logkeeper/src/carrier.rs). The UART's driver asks on log-wire exactly as the virtio console's asks on log-carrier: admitted alone, fed from where its channel starts, says DELIVERED. The port's Carriage decides the UART's quiet as before; the UART's feed writes CARRIED_ELSEWHERE/BACK_ON_THE_UART on itself (the harness's merge keys on them, now toyos_logstream's) and skips what the port carries. Lines said while the machine stops reach the UART's carrier, held back from the file as before.

What the console has spoken is a read position per log shard, the kernel's drain position (log::console). The inline drain moves it. SYS_LOG_SPOKEN (replacing SYS_CONSOLE_CARRIED) moves it to at least the positions logkeeper's own read reached through the rounds a channel delivered whole, taking a cursor as SYS_LOG_READ does. It needs the new Rights::CONSOLE (the console syscap), which the build lets only logkeeper hold, because what it moves is left off every fatal path's output. logkeeper holds a round's positions back to each shard's first record still waiting for a later round, so a round speaks only for what it wrote, and a channel handed a gap in the replay speaks for nothing after it. The stop and every fatal path write every record past the mark: they may repeat what a channel delivered and had not said, and miss none of the kernel's records, whatever their stamps. The UART's first carrier is handed every line before the hand-over except the kernel records the kernel put on the UART itself (decided by position), so the boot is on the UART once. A carrier started again resumes where its channel left off, or where it passed over while the port carried the log.

The hand-over takes the boot drains' claim on the wire for good: a drain still walking on another CPU finishes first, and none starts after, so there is one writer by construction (bounded by a 60 s tripwire).

The supervisor's end is the machine's. The kernel ends the machine on the supervisor's end through its panic path, naming how it ended (the supervisor ended, code=101, and nothing starts it again). Before that, the supervisor's panic hook says the panic's message as its last words through SYS_LOG_LAST_WORDS. The call writes one alert record, accepts only the boot's first call (AlreadyExists after), needs the new Rights::LAST_WORDS, which the kernel mints on the supervisor's system capability and no manifest syscap name maps to, and takes one line of at most 512 bytes of UTF-8 with no control character, checked at the boundary (toyos_abi::log::last_words; the SDK fits text to it first). The fatal path puts both on the UART, the panel and the black box. A supervisor that fails before logkeeper runs therefore says why again, and a machine whose supervisor dies no longer idles.

The kernel console object is gone, with its line queue, ConsoleLine, FileType::Serial and the 10 ms console repoll. The supervisor makes the console's input a pipe: its read end is every program's stdin (test-runner's commands arrive through it), and its write end is endowed to the UART's driver (toyos_logstream::CONSOLE_INPUT), which writes what the UART receives into it and refuses to start without it.

The log's origins and the console's input are grants, not names: a [programs] row says holds = ["log-origins"] or holds = ["console-input"] (the manifest's hold line), and the supervisor endows the row that holds each. The build refuses a row that holds either but its one holder (HOLDINGS, in held_by_their_holders_alone, on every rendered manifest), and every boot config that runs logkeeper must give it the origins and its UART driver the input.

The log's readiness without a thread: emit owes it (log::user::owe_readiness, one release store) and the next syscall's end or scheduler pass posts it.

K6: sched/kthread.rs, kthread::spawn, the row table, is_kernel_task, current_is_kernel_thread, kernel_start/kernel_thread_returned, Start::Kernel, the user-less kernel stack, Runs::Kernel, mm::space::kernel with PcidHandle::Kernel/Asid::Kernel, ElfInfo::none, quiesce's two exemptions and the scheduler's blocking_baseline are deleted; a task's image is no longer an Option. git grep -n 'kthread::spawn(' -- kernel/src finds nothing, and no kernel code creates a schedulable task but the idle loop.

Thread lifecycle: SYS_YIELD gives the CPU to another runnable thread of the band and is std's yield_now; osbench's time.yield now times it. SYS_THREAD_EXIT's detached form (thread_exit_detached) releases the thread's stack once it no longer runs on it, and proclife::leave_detached forgets the thread's place as it leaves (a teardown in progress keeps it). std's and libc's REAPED lists are gone.

Deleted with klogd: log/handoff.rs, kernel::carrier, the log waiter, the sleep lock (its one user), the three wire-holding actuators and the five tests that staged them (machine_shutdown_wire_held/_kept/_at_the_seal, virt_reboot_wire_held/_kept), the loom models console_handoff, log_wake and sleep_lock with their negative controls, and the metal row klogd_hosted, replaced by console_uart_driven.

Decisions to review

  • The kernel shares the UART with its driver, by time: before the hand-over, and after the stop or a fatal path. A holder the stop did not stop within its budget may write over the stop's lines, which the stop's own record names. A fatal path and the stop begin on a line of their own that says the kernel takes the UART, since the driver can be stopped mid-line or behind the log.
  • The spoken mark is exact by position, and its granularity is a round: the stop and a fatal path may repeat the kernel records of rounds a channel had not delivered whole, never miss one.
  • A kernel panic on the supervisor's end (by the owner's decision through the orchestrator): nothing restarts the supervisor, so the machine is over either way, and the fatal path is the one channel that reaches the UART, the panel and the black box.
  • AArch64 routes every SPI to the boot CPU (recorded at irqchip::init), as x86 routes every device line to one destination.
  • The console's input is a pipe the supervisor owns, endowed to the row that holds it, as the log's origins now are; bytes received with no reader's room are dropped and said once per spell.
  • AArch64 gets the PL011 claim now, because the virt job tests read their job output off the PL011.

Checks

Head 98d66179e on main 2c2f957cb.

  • Round 9, rebased onto main 2c2f957cb, at 98d66179e (evidence): --ci host exit 0, 108 green. The six console rows passed on the x86 guest host. issues/a-holders-queued-line-can-reach-the-console-after-the-last-word.md stays deleted: the kernel's holders' queue it describes is gone. issues: close the load-only records whose tests are deleted #1171's owner and K4 citation in it are accounted for in the K4 commit. The rest of sched: a waiter a kill ends passes on the bounded post it may hold #1168's and sched: a steal probe is a bit in its victim's word, which a thief can take back #1170's scheduler changes merged cleanly, and one comment naming the deleted watch::wait was fixed. Every log, patch and command, masked, with its revision, host and exit: round 1, round 3, rounds 4 and 5 round 6 and round 7 (README in each).

  • Round 7, at 152cae5d1: main's start plan (Supervisor times PCI claims: the declaration in the device set, and storage and homes before the rows that need them #1164) had put the UART's driver after the declaration, storage and the homes, leaving a UART-only machine silent from userland's start until storage was up. The plan now starts first the rows that carry the log, by what they hold (the log's origins and the console's input), beside the declaration's holder. Pinned by the_uart_starts_with_the_log_before_the_declaration, which the plan's old rule reds (exit 101). --ci host exit 0, 108 green. On the x86 guest host, 6 rows passed: the new supervisor row, both UART rows, machine_shutdown_short_stop, console_image_boots and session_lifecycle. The UART's claim is now pid 4's, beside logkeeper. Where nothing can declare, both still start with every row in main's storage order.

  • Round 6, review r2's fixes rebased onto main 783569506, at d4c43fd35: --ci host exit 0, 108 green; --build-only x86 and AArch64 exit 0; a_supervisor_that_fails_early_says_why_on_the_uart on the x86 guest host passed, with last words now gated by Rights::LAST_WORDS. The rebase resolved tests/images/acpicase.toml (main's storage rows beside this change's UART row) and spawn_thread (main's near placement beside the image expect); the r5 rows and metal at 8ac4f2187 cover what r6 leaves untouched.

  • Host, at 8ac4f2187: cargo run -- --ci host exit 0, 108 steps green; --build-only x86 and AArch64 exit 0. New host tests: the ABI's last-words rule and fitting; logkeeper's a_round_is_through_the_cursor_but_what_waits, what_the_uart_carried_is_told_by_position, a_uart_carrier_started_again_resumes_where_its_channel_left_off and the hub's positions; the build's console syscap gate; the harness filter's the_kernels_taking_the_uart_is_shown_from.

  • x86 guests on the x86 guest host (KVM), at 8ac4f2187: 10 passed: a_supervisor_that_fails_early_says_why_on_the_uart (new), the_uart_carries_the_boot_once_across_the_hand_over, the_uart_carries_the_log_again_once_the_console_carrier_goes, machine_shutdown_short_stop, std_threads_count_the_cpus_and_give_back_ended_threads, session_lifecycle, console_image_boots, acpi_lock_given_back_on_one_cpu, screen_fatal_halt_composited, nested_nmi_is_loud.

  • That host found a defect at 8678b19c7: machine_shutdown_short_stop stalled there twice and passed on main. The UART capture held the stop's lines and Shutting down., but they came after the UART driver's boot backlog and before the driver ever said the port carried the log. The harness shows a virtio machine's UART only from that line, so it never saw them. 8ac4f2187 has the kernel start its stop and fatal lines with console: the kernel writes the UART from here (toyos_abi::log::KERNEL_TAKES_THE_UART), and the harness filter shows the UART from it on. The failing runs are the control for that commit.

  • AArch64 guests, at 152cae5d1 on a quiet Mac: virt_jobs_at_el2 and virt_fatal_halts_the_others_first, exit 0, 2 passed (round 8): no other qemu, rustc or cargo process ran, and the one-minute load was under 4 for three minutes before the run.

  • Controls, each red as it should be:

    • the supervisor's panic saying no last words (the new row, exit 1);
    • the kernel letting a supervisor that exited with a code end nothing (the new row, exit 1: the boot never ends);
    • a round speaking through records still waiting (exit 101);
    • a restarted UART carrier beginning at the hand-over (exit 101).
  • Metal, the readbacks of 08e4bb8f0 judged. Both benches' testcases-watchdog boots are green: loader_watchdog_arms and watchdog_fed, the log whole to its stop. On both testcases boots std_threads exited 0. console_uart_driven held its own claim on both (uart: no console UART claim: neither bench has a COM1, so the 16550 and IRQ 4 paths reach no hardware we have). It is red only on must_be_clean finding another row's panic: on the AMD bench, counters_metal's wait for an EC query that machine never raises (metal: the ACPI rows wait from their own start, and counters admits the machine's own events #1163 fixes it); on the T14, usbd_spare's (issues/a-metal-row-names-no-machine-so-another-benchs-boot-carries-it.md). The other reds are the other bench's rows riding the boot, i219_msi's own record and, on the T14, rows needing its DATA, which an unrelated incident damaged.

  • Metal staged at 8ac4f2187, not run: boot:testcases per bench, which brings testcases-watchdog.

  • Earlier rounds' rows (rounds 1 and 3) stand for what later commits did not touch. The detached-thread, yield, stop and fatal-path controls of round 1 are unchanged in subject.

Kernel size, kernel/src: 233 files, 60,378 lines on the original base → 230 files, 58,979 lines at 8ac4f2187. All of kernel/ (pure, loom, proclife, sim): 380 files, 112,027 lines → 373 files, 110,056 lines.

Risks and gaps

🤖 Generated with Claude Code

@Japabu

Japabu commented Nov 4, 2026

Copy link
Copy Markdown
Collaborator Author

Review r4 of #1175 (follow-up to r1–r3 on #1165), head 152cae5

The fix is in the right place, and the rule that selects the rows is the right one. On a boot that can declare, plan's first now holds the rows that carry the log, chosen by what they hold. The UART driver needs neither the declaration nor a home, and its claim (uart, a kernel device kind) does not go through the PCI declaration. So nothing it depends on comes after the point where it now starts. That resolves the r3 blocker.

Selection by held grant. carries_the_log (system/supervisor/lifecycle/src/declaration.rs:39) matches log-origins or console-input in holds. Each of those can be held by exactly one row, and the build enforces this: HOLDINGS in build/build.rs:706-709 pairs ORIGINS with LOGKEEPER and CONSOLE_INPUT with WIRE_HOLDER, and held_by_their_holders_alone refuses any other row that holds either one "on every manifest rendered". The supervisor endows the same two objects on the same holds test (system/supervisor/src/main.rs:3270-3288). So the rule cannot pull in another row, and it uses the same key the supervisor uses to hand those rows their authority. That is better than the name match it replaces. Within first, start order still follows [boot] start (logkeeper before uart in images/system.toml:32). uart gets its state directory along with every other running row in storage_up, as logkeeper already did.

No-declarer path. first_here is still gated on comes, so when nothing can declare, first stays empty and the UART row goes to rest behind storage, as on main. nothing_waits_where_nothing_can_declare still asserts that first is empty. The comes && term makes it hold for the UART row too, which is clear from reading the code.

Test. the_uart_starts_with_the_log_before_the_declaration gives the expected result: first: [1, 2, 3]. Under the old rule, p.name == LOGKEEPER, row 2 would go to rest (first: [1, 3], rest: [2]), so the negative control the commit claims is real. The keeper() fixture now holds ORIGINS, so the existing tests exercise the new rule and no longer depend on the name. In the_log_and_what_the_declaration_comes_through_start_first, the runner and desktop rows still land in rest, which shows that rows holding neither grant are not swept in.

Comments and record. The new doc comments are short and accurate. The rewording in the issue and in serve.rs ("those it had already taken repeat") is more precise than before, and the record's exit paragraph is now wrapped.

Evidence. Host CI at 152cae5 exited 0. The console/session rows on the remote KVM host show the UART claim going to pid 4, next to logkeeper, which matches the new order. The two aarch64 rows still owed on a quiet Mac are outstanding as stated. They are not affected by this change, whose logic is architecture-independent and covered by the host test.

Findings

None.

LAND

@Japabu
Japabu marked this pull request as ready for review November 4, 2026 13:09
@Japabu
Japabu enabled auto-merge November 4, 2026 13:09
Japabu and others added 9 commits November 4, 2026 14:10
…rland driver's

The small-kernel track's K4 and K6, by the owner's ruling that the kernel
creates no thread but each CPU's idle loop. `klogd`, the one kernel thread, was
the console's writer. It is gone, and so is every provision kernel threads
had: `sched/kthread.rs` and its row table, `is_kernel_task` and
`current_is_kernel_thread`, quiesce's exemption, the scheduler's zero
baseline, `kernel_start`, `Start::Kernel`, a kernel stack without a user
area, `Runs::Kernel`, the kernel address space object with its reserved PCID
and ASID, `ElfInfo::none` and an `Option` on every task's image.

The console UART

- The kernel writes the UART only where no process can: inline as each
  record commits until `log::console::hand_over`, before userland runs; from
  the machine's stop, once userland is stopped; and on every fatal path.
- Between them it is `/system/bin/uart`'s, which holds a `uart` claim (a new
  device class: COM1's ports and IRQ 4 on x86, as an `isa` row; the SPCR's
  PL011 frame and its level SPI on AArch64, which needed SPI routing to a
  row) and carries the log `logkeeper` feeds it on `log-wire`, as the virtio
  console's driver carries it on `log-carrier`: one carrier serving in
  logkeeper, two channels. The UART is quiet while the port carries, says so
  on itself, and is fed again when the port goes, stalls or the machine stops.
- The kernel and logkeeper share one word: the newest stamp the console has
  spoken (`SYS_LOG_SPOKEN`, which replaces `SYS_CONSOLE_CARRIED`). The inline
  drain sets it; logkeeper advances it as a channel delivers whole rounds. The
  UART's driver starts after it, so the UART carries the boot once; the stop
  and a fatal path put every record after it on the UART.
- The kernel's console object is gone with its queue: the supervisor makes the
  console's input a pipe, whose read end is every program's stdin and whose
  write end the UART's driver writes what the UART receives into. Its read
  waits on the pipe's readiness, not a 10 ms repoll.
- Without a thread to post it, the log's readiness is owed by `emit` and
  posted at the next syscall's end or scheduler pass.

Thread lifecycle

- `SYS_YIELD`, and std's `yield_now` on it.
- A detached thread's place goes as it ends (`proclife::leave_detached`), and
  `SYS_THREAD_EXIT`'s detached form releases its stack once the thread no
  longer runs on it; std's and libc's `REAPED` lists are gone.

Deleted with the thread: `log/handoff.rs`, `kernel::carrier`, the
sleep lock (its one user was `klogd`), the wire-holding actuators and their
tests, the loom models of the handoff, the log waiter and the sleep lock, and
their negative controls.

Rebased onto main 2c2f957: #1171 added an owner and a citation of K4 (this
change, then #1165) to issues/a-holders-queued-line-can-reach-the-console-after-the-last-word.md,
which this change deletes. The record stays deleted: the kernel's holders'
queue and klogd's drain it describes are gone, so no holder's queued line
exists to follow the last word; the residual it named, a holder the stop did
not stop, is the stop's shortfall, which its record reports by name.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`images/diag.toml` is for a machine with no serial port and claims no device,
which `no_diag_program_claims_the_screen` holds; the check that every image
running logkeeper drives the console UART names it as the one exception.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`tests/images/virtpancase.toml` landed on main beside this branch and runs
logkeeper, so it starts the UART's driver as every such image does
(`every_boot_config_runs_logkeeper`). The UART's carrier records how far
it passed over the replay while the port carried it, so the stop's wait
reads where it stands rather than where it was muted.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…hat holds them

The supervisor endowed the log's origins acceptor to the row named
`logkeeper` and the console-input pipe's write end to the row named `uart`.
A name grants no authority: the holder of the origins names every line's
writer, and the holder of the console's input types at every program's
standard input.

A `[programs]` row now says `holds = ["log-origins"]` or
`holds = ["console-input"]`; the manifest carries it as a `hold` line, and
the supervisor endows the row that holds each. The build refuses a row that
holds either unless it is that object's one holder (`HOLDINGS`, checked with
`held_by_their_holders_alone` on every rendered manifest), and every boot
config that runs logkeeper must give it the origins and its UART driver the
console's input. The UART driver refuses to start without the console's
input rather than drop every byte it receives unsaid.

The issue on a supervisor that fails before logkeeper runs now records what
the kernel's inline drain can and cannot carry: holding it past the
hand-over would carry no line of the supervisor's, which is not a kernel
record.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… end says why

What the console has spoken was a stamp, compared across shards: a round
logkeeper delivered could carry a record stamped after one another CPU had
stamped and not yet committed, and every fatal path then left that record
off the UART. It is now a read position per shard. The kernel's drain
position is the mark: the inline drain moves it, SYS_LOG_SPOKEN moves it to
at least the positions logkeeper's read reached through the rounds a channel
delivered whole (taking a cursor, as SYS_LOG_READ does), and the stop and
the fatal paths write every record past it. logkeeper holds a round's
positions back to each shard's first record still waiting for a later
round, so a round speaks only for what it wrote, and a channel handed a gap
in the replay speaks for nothing after it. Where the UART's carrier starts
is decided by position too: every line of the rounds before the hand-over
but the kernel records the kernel put on the UART itself.

SYS_LOG_SPOKEN needs a new right, Rights::CONSOLE (the `console` syscap),
which the build gives logkeeper alone, since what it moves is kept off every
fatal path's output; a log reader can no longer mute it.

A UART carrier started again resumes where its channel left off, or passed
over while the port carried the log, rather than at the hand-over, which
replayed up to the whole replay at the UART's rate after every restart.

The hand-over takes the boot drains' claim on the wire and never gives it
back, so a drain still walking on another CPU finishes first and none
starts after: one writer by construction.

The supervisor's end is the machine's: the kernel ends the machine on it
through the panic path, naming how it ended. Before it does, the
supervisor's panic hook says the panic's message as its last words
(SYS_LOG_LAST_WORDS, one alert record, the boot's first call alone, gated by
Rights::LOG, one line of at most 512 bytes of text with no control
character, validated at the boundary). The fatal path puts both on the UART,
the panel and the black box, so a supervisor that fails before logkeeper
runs says why again. The test harness can stage a ROOT without one of its
files (Plan::root_omits), and a new QEMU row boots a /system without its
release file and finds the reason on the UART before the kernel's panic.

Also: AArch64 routes every SPI to the boot CPU, as the comments said, not to
whichever CPU made the claim; the SPCR's Interrupt Type is read, and a UART
whose interrupt is not a GIC's gets no interrupt row. On x86 COM1 stays the
kernel's, Kept, where no I/O APIC carries its line and no row is filled. A
thread spawn whose process has lost its image is an invariant violation, not
a silent None. The thread table's forget contract names the detached leave.
The guard-page record's hold on K6 is lifted.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The stop and every fatal path take the console UART back from its driver,
which may be behind the log: on a fast guest whose console port carried the
log, the UART's driver was still sending boot lines from its pipe when the
machine stopped, and had not yet said the log was carried elsewhere. The
harness shows a virtio machine's UART only from that word or a kernel's
death, so the stop's lines, which only the UART had, were hidden, and
machine_shutdown_short_stop stalled waiting for its last word under KVM.

The kernel now starts its own lines there with a line that says it writes
the UART from here and that what its driver had not sent is in /log
(toyos_abi::log::KERNEL_TAKES_THE_UART), and the harness's UART filter shows
the UART from it on.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…keover line says only what is true

SYS_LOG_LAST_WORDS was gated by Rights::LOG, which logkeeper and test-runner
hold to read the log: either could write a record every fatal path shows,
or spend the boot's one slot and leave the supervisor's real reason refused.
It now needs Rights::LAST_WORDS, which the kernel mints on the supervisor's
system capability and no manifest syscap name maps to.

The kernel's takeover line claimed what its driver had not sent was in
/log; at the stop the held program lines are not, and a fatal path can come
where no /log exists. It now says only "console: the kernel writes the UART
from here".

A refused stop's lines reach the UART twice; the test's comment said once.
The comment says so, and the console-loss record records it with its exit.
The IOMMU event SPI's comment names the boot CPU, and the guard-page record
drops the history.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…before the declaration

Main's start plan (#1164) put every row that neither keeps the log, holds
the acpi claim nor may mint it after the declaration, storage and the
homes, and the UART's driver among them. The kernel lets go of the UART at
its hand-over, before userland runs, so a machine whose only console is its
UART said nothing from userland's start until storage was up, and nothing at
all where storage hung. The driver needs neither the declaration nor a
home.

The plan starts first the rows that carry the log, by what they hold: the
log's origins (logkeeper) and the console's input (the UART's driver), in
place of logkeeper's name. A host test pins the UART's driver in `first`;
the plan's old rule reds it.

The refused-stop comment and record now say only the lines the UART had
already taken repeat, and the record's exit paragraph is wrapped.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`watch::wait` went with klogd; the cancellable wait is `watch::wait_until`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Japabu
Japabu force-pushed the no-kernel-threads branch from 152cae5 to 98d6617 Compare November 4, 2026 13:10
@Japabu
Japabu added this pull request to the merge queue Nov 4, 2026
Merged via the queue into main with commit e7907fb Nov 4, 2026
5 checks passed
@Japabu
Japabu deleted the no-kernel-threads branch November 4, 2026 13:33
@Japabu

Japabu commented Nov 4, 2026

Copy link
Copy Markdown
Collaborator Author

Orchestrator verification of the rebase, recorded after the merge.

I armed auto-merge while the PR still conflicted, so it merged through the queue as soon as the rebased head passed the required checks. That happened before this record was posted.

git range-diff of 152cae5d1 (reviewed, r4 LAND) against 98d66179e (merged):

  • commits 2–8 are identical (=);
  • commit 1 differs only in the modify/delete resolution of issues/a-holders-queued-line-can-reach-the-console-after-the-last-word.md, which stays deleted and is explained in its message, and in issues: close the load-only records whose tests are deleted #1171's added hunk being accounted for;
  • the new commit 9 changes one comment line in kernel/pure/sched/cpu.rs (watch::wait → watch::wait_until).

No code changed relative to the reviewed head. At 98d66179e: host CI exit 0 (108 steps), six console rows green on the remote KVM host, and the aarch64 rows green at 152cae5d1.

Japabu added a commit that referenced this pull request Nov 4, 2026
Merged rather than rebased: a linear rebase replays #1144's and #1141's
merged-in history onto a main they were never written for, and stopped at
the sixth of 69 commits on a syscall a later commit here supersedes.

Conflicts, each kept to what neither side deleted:
- ObjectKind: this branch removed File, K4 removed Console. Neither is
  kept and the kinds after them renumber densely (SysCap 9 .. DeviceSet
  19), as `from_word` indexes `ALL` by the word.
- object/mod.rs and object/ops.rs: the kobject list and every match arm
  lose both Console and File; ops.rs drops the serial import that only the
  console object used.
- Syscalls: main's SYS_YIELD 168 and SYS_LOG_LAST_WORDS 169 stay;
  SYS_NAMESPACE_NAMES moves to 170, the profile to 172 bins, its bound
  asserted on the new top. pread/pwrite stay deleted with the kernel
  file objects; thread_exit takes main's doc.
- kernel/CLAUDE.md: main's direction-flag/AC and BackendGuard rules; the
  blocking-syscall pattern keeps this branch's paged-object reads, as
  SYS_FSYNC went with the file objects.
- libccase.toml: main's uart beside this branch's MEMORY file server.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Japabu added a commit that referenced this pull request Nov 4, 2026
…origins

K4 (#1175) moved the UART to a userland driver fed by logkeeper's wire and
made `log-origins` logkeeper's to hold; `every_boot_config_runs_logkeeper`
refuses an image without it. datacase.toml and formatcase.toml, which this
branch added, take designatecase.toml's rows.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant