Skip to content

x86: Ready thread still carries blocked_in_syscall=true (specimen 737 line 2481 unblock_for_signal) #792

Description

@ryanbreen

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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions