Follow-up from the #737 RCA (docs/planning/green-program/nic-bus/737-RCA-2026-09-04.md,
"What is still open" item 2). Noted in passing there, not investigated; filing
so it has an owner.
The specimen line
docs/planning/green-program/nic-bus/serials/702-rca/anomaly_exited_114/serial_kernel.log.txt,
line 2481:
unblock_for_signal: Thread 22 state is Ready, blocked_in_syscall=true
(The RCA doc cites this as "line 2483"; re-checked directly against the
in-repo file with grep -n 'Thread 22 state is Ready' and it is at 2481 —
2483 is the unrelated "Process 17 ... exited with code 0" line two rows
later. Correcting the citation here.)
Fuller context from the same file:
1426: [ INFO] kernel::process::creation: create_user_process: Scheduling user thread 22 ('loopback_wake_test')
2298: Thread 22 blocked waiting for child exit (blocked_in_syscall=true)
2299: [ INFO] kernel::interrupts::context_switch: Saved kernel context for blocked thread 22: RIP=0x800020d782 CS=0x8 RSP=0xffffc90000b962c8
2479: Thread 22 unblocked by child exit, queued to cpu 0
2480: unblock_for_signal: Checking thread 22 (current=Some(28))
2481: unblock_for_signal: Thread 22 state is Ready, blocked_in_syscall=true
2482: unblock_for_signal: Thread 22 not BlockedOnSignal, state=Ready
Thread 22 is loopback_wake_test's own thread (line 1426) — it has a
process. It blocks waiting for a child's exit with blocked_in_syscall=true
set (line 2298), gets woken onto the ready queue by the normal child-exit
path (line 2479), and by the time unblock_for_signal walks the thread
table it is already Ready — but blocked_in_syscall is still true.
unblock_for_signal itself takes the no-op branch here (it finds the thread
already Ready and not BlockedOnSignal), but the flag it observes is
stale for a Ready thread.
Why it matters
PR #787 fixed a related but distinct case: Scheduler::block_current_for_timer
and Scheduler::block_current_for_io_publish were unconditionally setting
blocked_in_syscall=true even for a process-less thread, and the x86
save path (interrupts/context_switch.rs) used that flag to route the save
into process.main_thread, silently dropping context for any thread with no
process. The fix derives the flag from thread.owner_pid.is_some() for
those two producers; block_current_in_syscall()'s own callers are syscall
handlers with a process by construction and were left unchanged (per #787's
description).
Thread 22 in this specimen has a process (loopback_wake_test), so it is
not the case #787 fixed. It also blocked "waiting for child exit," not via
block_current_for_timer or block_current_for_io_publish. So this is a
different code path carrying the same symptom shape (a stale
blocked_in_syscall=true observed on a thread that is no longer blocked).
What is not known
Whether this is the same producing defect as #787's, a different producer in
the same family (something on the child-exit wake path not clearing the flag
when transitioning a syscall-blocked thread to Ready), or benign (the flag
might be immaterial once unblock_for_signal finds state=Ready and takes
the no-op branch, since it's not on the from-userspace path #737 chases). Not
established here whether this is reachable from userspace-observable
behavior or is purely an internal bookkeeping residue.
Source
docs/planning/green-program/nic-bus/737-RCA-2026-09-04.md, "What is still
open," item 2.
Follow-up from the #737 RCA (
docs/planning/green-program/nic-bus/737-RCA-2026-09-04.md,"What is still open" item 2). Noted in passing there, not investigated; filing
so it has an owner.
The specimen line
docs/planning/green-program/nic-bus/serials/702-rca/anomaly_exited_114/serial_kernel.log.txt,line 2481:
(The RCA doc cites this as "line 2483"; re-checked directly against the
in-repo file with
grep -n 'Thread 22 state is Ready'and it is at 2481 —2483 is the unrelated "Process 17 ... exited with code 0" line two rows
later. Correcting the citation here.)
Fuller context from the same file:
Thread 22 is
loopback_wake_test's own thread (line 1426) — it has aprocess. It blocks waiting for a child's exit with
blocked_in_syscall=trueset (line 2298), gets woken onto the ready queue by the normal child-exit
path (line 2479), and by the time
unblock_for_signalwalks the threadtable it is already
Ready— butblocked_in_syscallis stilltrue.unblock_for_signalitself takes the no-op branch here (it finds the threadalready
Readyand notBlockedOnSignal), but the flag it observes isstale for a
Readythread.Why it matters
PR #787 fixed a related but distinct case:
Scheduler::block_current_for_timerand
Scheduler::block_current_for_io_publishwere unconditionally settingblocked_in_syscall=trueeven for a process-less thread, and the x86save path (
interrupts/context_switch.rs) used that flag to route the saveinto
process.main_thread, silently dropping context for any thread with noprocess. The fix derives the flag from
thread.owner_pid.is_some()forthose two producers;
block_current_in_syscall()'s own callers are syscallhandlers with a process by construction and were left unchanged (per #787's
description).
Thread 22 in this specimen has a process (
loopback_wake_test), so it isnot the case #787 fixed. It also blocked "waiting for child exit," not via
block_current_for_timerorblock_current_for_io_publish. So this is adifferent code path carrying the same symptom shape (a stale
blocked_in_syscall=trueobserved on a thread that is no longer blocked).What is not known
Whether this is the same producing defect as #787's, a different producer in
the same family (something on the child-exit wake path not clearing the flag
when transitioning a syscall-blocked thread to
Ready), or benign (the flagmight be immaterial once
unblock_for_signalfindsstate=Readyand takesthe no-op branch, since it's not on the from-userspace path #737 chases). Not
established here whether this is reachable from userspace-observable
behavior or is purely an internal bookkeeping residue.
Source
docs/planning/green-program/nic-bus/737-RCA-2026-09-04.md, "What is stillopen," item 2.