aboutsummaryrefslogtreecommitdiffstats
path: root/src/socket.asm
diff options
context:
space:
mode:
authoruser <user@clank>2026-09-22 19:20:53 +0200
committeruser <user@clank>2026-09-22 19:20:53 +0200
commit5f872435e61fc489606b13ba33ba6f258af574b5 (patch)
treecdc0933f6b1b55e2cc8ebc5c37837aa702c3632b /src/socket.asm
parentusr: httpd - the Game Boy serves its filesystem over HTTP (diff)
downloadgbos-5f872435e61fc489606b13ba33ba6f258af574b5.tar.gz
gbos-5f872435e61fc489606b13ba33ba6f258af574b5.tar.xz
gbos-5f872435e61fc489606b13ba33ba6f258af574b5.zip
sched: SchedYield must preserve HL - link-less boots warm-rebooted every ~11s
Reported by an outside agent (BUG-schedyield-clobbers-hl.md) while putting gbos in a browser, where there is no link port at all. Verified here, fixed, and re-verified. SchedYield had two exits. The switch path preserved registers because hSwitchTo saves and restores the full context. The "nobody else is runnable" path was a bare `ret c` straight out of FindNextReady, which leaves HL pointing into wProcTable (PcbPtr puts it there). Two callers - net_op_recv's timeout loop and tcp_connect's - keep a pointer in HL across that call: ld hl, wNetTO inc [hl] jr nz, .wait call SchedYield ; HL now = &wProcTable, not &wNetTO inc hl inc [hl] ; stray increment into a PCB With no DHCP server the boot-time `dhcp` spins in that loop for ~10s, and with the shell blocked on tty input nothing else is PS_READY - so *every* yield took the no-switch path and corrupted a byte, until a saved return address rolled from $00xx to $01xx and RET landed on the cart entry $0100. A clean-looking warm reboot, every ~11s, forever. It never happens with tools/gbhub running, which is why it survived this long. Fixed in the scheduler rather than at the two call sites, so the contract holds for every present and future caller: SchedYield now preserves AF/BC/DE and HL on both paths. On the switch path the pushes sit on the task's own stack and are popped when it is rescheduled. Evidence, with the link port unconnected (no --serial-sock; note --headless bypasses the emulator's breakpoints, so these run on the display path): before: breakpoint $0100 hit 5x in 40s, first at cycles=46,286,496 (matching the report), deltas ~45.5M cycles apart; HL at the `inc hl` after the call read $C000 instead of $C9D1 after: 0 hits in 60s, HL reads $C9D1 every time, and a 60s screen watch shows no spontaneous reboot (it reproduced at 9.9s before) No regression: 34/34 across the tool, httpd and client suites.
Diffstat (limited to 'src/socket.asm')
0 files changed, 0 insertions, 0 deletions