Skip to content

idle-pause: wake for an interrupt masked by a raised spl - #253

Merged
techomancer merged 1 commit into
techomancer:mainfrom
slaapliedje:idle-park-masked-interrupt
Oct 19, 2026
Merged

techomancer merged 1 commit into
techomancer:mainfrom
slaapliedje:idle-park-masked-interrupt

Conversation

@slaapliedje

Copy link
Copy Markdown
Contributor

An idle-park build can hang IRIX for good. We hit it on an IRIX 6.5.22 Indy (R4400, a nightly with lightning,jitv2,idle-pause) after some hours of light use: keyboard, serial console and telnet all dead, the MIPS-CPU thread at 0%. The monitor showed the CPU parked:

stopped pc=ffffffff880e3a98
CP0 Status: 0x00004001 (IM:_6______ K:K IE)

IE with IM6 alone is IRIX's splhi: on IP22, IP6 is the bus error, the one line left unmasked at high spl. The code at the PC is a loop that raises the spl, calls a function, drops it again (splx) and tests a flag an interrupt handler clears. Most of each pass is at high spl, so the detector's batch-end samples land there, the state repeats, and park waits for ip & im. The timer's interrupt then arrives masked. The guest would take it a few instructions later at splx, but a parked CPU never gets there, and nothing raises IP6. stop / step / cont on the monitor freed it: the first step went straight to the exception vector.

This is the sibling of idle-pause-must-not-park-with-interrupts-masked.md, with IM partly clear rather than zero.

The change

src/cpu/idle_park.rs. The mask update samples is the guest's at that moment, not the loop's, so:

  • update declines to park while any line is pending, masked or not: the guest is about to take it.
  • park returns when any line becomes pending, masked or not.

"Nothing pending, wait for anything" can always be satisfied by the guest's own timer, whatever spl the sample caught. A line held pending and masked for a long time would keep the CPU from parking (it spins, as without idle-pause), never from running. The IM == 0 guard stays.

Also: rules/perf/idle-pause-masked-interrupt-must-wake.md with the details, a pointer to it from the IM == 0 rule, and a CHANGELOG entry.

Tests

Each new test hangs until its deadline (and fails) without the fix:

  • update_declines_to_park_while_a_masked_interrupt_is_pending (idle_park.rs).
  • a_masked_interrupt_ends_the_park (idle_park.rs): parked with only IM6 set, IP4 raised from another thread.
  • idle_park_wakes_for_an_interrupt_masked_by_a_raised_spl (mips_exec_test.rs): the spl loop as guest code, run through step_int, 1000-step batches, update and park as MipsCpu::start does; an interrupt handler sets the flag; IP4 is raised from another thread once the CPU has parked; the loop must finish.

Tests that park now take PARK_TEST_LOCK. There is one PARKER slot, so two tests parking at once wake each other's threads. They also wait for parked() rather than a guessed sleep, so the lock is held only briefly.

  • cargo test --release --features idle-pause --lib: 1056 passed.
  • --features idle-pause,jitv2 --lib: 1530 passed. One existing test, an_interrupt_ends_the_park_without_waiting_out_the_slice, measures wake latency with a 300 µs limit while the whole suite runs, and goes over it now and then. That rate is unchanged by this PR: 1 run in 25 with this change, and 1 in 25 on main, run alternately on the same machine.
  • IRIX 6.5.22 on the Indy, a build with the nightly's features plus this change, no_idle = false:
    • Boots to login.
    • Idles at about 15% of a host core, against 95%+ with no_idle = true, so parking still pays.
    • A two-hour soak, a round every 20 s of disk (tar of /usr/include, find), NFS (cksum of a host file) and network (ping) work with the guest otherwise idle: all 347 rounds answered. Before the fix the same guest hung within hours.

Found while using iris as the test machine for an IRIX port of the Manx browser. Thanks for the emulator.

🤖 Generated with Claude Code

https://claude.ai/code/session_01APKCDaLfEv8mFqUmDtAruT

An IRIX 6.5.22 Indy (lightning,jitv2,idle-pause) went dead after hours:
keyboard, serial and telnet gone, the MIPS-CPU thread at 0%, parked at
Status 0x4001 - IE with IM6 alone, IRIX's splhi on IP22. The kernel was
in a loop that raises the spl, calls a function, drops it again and tests
a flag an interrupt handler clears; the detector sampled the repeated
state at high spl and park waited for ip & im. The timer's interrupt
arrived masked, to be taken at splx a few instructions on - which a
parked CPU never reaches - and nothing raised IP6.

The mask update sees is the guest's of that moment, not of the loop. Now
update declines to park while any line is pending, masked or not, and
park returns when any line becomes pending. The IM == 0 guard stays.

Tests (each hangs to its deadline without the fix):
- update_declines_to_park_while_a_masked_interrupt_is_pending
- a_masked_interrupt_ends_the_park
- idle_park_wakes_for_an_interrupt_masked_by_a_raised_spl: the spl loop
  run through step_int, 1000-step batches, update and park as
  MipsCpu::start does, IP4 raised from another thread once parked.
Tests that park take PARK_TEST_LOCK (one PARKER slot) and wait for
parked() rather than sleeping. rules/perf/idle-pause-masked-interrupt-
must-wake.md has the details.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01APKCDaLfEv8mFqUmDtAruT
@techomancer

Copy link
Copy Markdown
Owner

That's why I like my laptop to sound like turbo jet! I't makes it autentic fast fan sgi experience ;-)

@techomancer
techomancer merged commit a5cbc58 into techomancer:main Oct 19, 2026
14 checks passed
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.

2 participants