| Filename | Latest commit message | Latest commit date |
|---|---|---|
fastfetch reported 3 seconds of uptime after 15 real ones, `time` claimed
3.12s for a 20-second command, and ping's one-second interval was closer to
six. One cause, not three: `ticks` was advancing at ~14.5 Hz instead of 100.
It was not the timer. virtio-gpu-pci shares IRQ 11 with the e1000 and
registered no interrupt handler at all. PCI INTx is level-triggered, so the
device held the line asserted, the kernel signalled EOI, and it fired again
immediately -- 72,000 interrupts a second, 83% of CPU0, starving the tick.
The e1000's handler read ICR as zero half a million times, correctly
answering "not mine", which is what made it look like a network-free problem.
Reading virtio's ISR byte clears it and drops the line. That is the fix.
irq_dispatch now measures each line's rate against the TSC -- not ticks,
which is the first casualty of a storm -- and names the attached handlers
once above 20000/s. It reproduces the original fault as a single line.
Found along the way, and fixed because they were real:
- lapicinit loaded TICR with xv6's uncalibrated 10000000, whose own comment
admitted it was never measured. calibrate_timers() now measures the LAPIC
and the TSC against the 8254 PIT. (It came back at 999.9 MHz, so this was
not the bug -- but the next machine is not obliged to be 1 GHz.)
- microdelay() was an empty function body. Every microdelay(1000) in the
xHCI reset path and the USB hub power-on sequence returned instantly.
- HZ is a constant in param.h now, not the literal 100 written out at a
dozen ticks-to-seconds conversions. USER_HZ is separate and deliberately
does not follow it: musl answers sysconf(_SC_CLK_TCK) with 100 always, so
times() and /proc/stat scale at the syscall boundary the way Linux does.
- TIOCGWINSZ answered a hardcoded 24x80. gfx_cols()/gfx_rows() have known
the real geometry all along; at 1024x768 the console is 128x48, so every
program that lays out a screen was formatting for the wrong one.
- TCFLSH fell through to the catch-all `return 0`, claiming to discard
input without discarding any.
uptime now advances 5.01 seconds per 5 real seconds. schfs-check passes.
Full investigation, including the two wrong hypotheses and the measurement
flaw that protected them, in docs/history/kernel.md section 13.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VQ7Qx8E1q1M1bbCq8QLHS2
|
||
| .. | ||
| kernel.md | ||
| moving-to-linux.md | ||
| README.md | ||
| schfs.md | ||
History
Why SchOS is the way it is. Bugs whose cause was nowhere near their symptom, and the few write-ups that have nowhere better to live.
| kernel.md | The expensive ones. Boot, SMP, signals, ABI assumptions, /proc, input. |
| schfs.md | How the filesystem was built, and what each phase cost. |
| moving-to-linux.md | The Windows-to-Fedora move. |
What belongs in here
A bug whose cause is not visible from the code that fixed it.
That is the whole test. If reading the fix explains the problem, the fix is the documentation and nothing needs writing down. If the fix looks arbitrary — a constant moved by eight, a field reordered, a check inverted — then the strangeness is load-bearing and the next person to touch it deserves to know why before they change it back.
Every entry here is a thing that looked like a different problem than it was.
What does not belong
- A changelog.
git logis the changelog. - A bug that was found and fixed in an hour. Cost is the filter.
- How something works. That is ../architecture/, written in the present tense for somebody who does not care what it used to be.
- Anything still open. An unfinished investigation goes in ../plan/ or in the code as a comment. This directory is past tense.
How to write one
Symptom first, then diagnosis, then the fix, then the transferable part.
The transferable part is the reason the entry exists. __thread being wrong for
per-CPU data is worth more than the specific null dereference it caused;
"a layout constant that several artifacts must agree on wants a check that stops
the build, not a comment asking people to remember" is worth more than the
bootloader offset that taught it.
Say how it was found, when the technique was the hard part. A hardware
watchpoint through QEMU's gdb stub named an instruction on the first run after
three rounds of cprintf had narrowed it to nothing — that is reusable, and the
bug is not.
Do not clean up the embarrassing part. The near-miss where a change passed
every assertion green without having been applied at all is one of the most
useful entries in this directory, and it only works because it admits that a
grep returning three hits was read as confirmation without counting what they
were.