kernel: shared-fate review fixes — lock the shm/dma walks, contract edges
The adversarial review of the branch confirmed the big one: the shm/DMA page-table walks and their pmm/heap calls ran outside the big kernel lock — pre-existing, but fatal once the per-space cursors invited sibling threads to race them (two concurrent creates could orphan a page table: one thread's region silently unmapped, the frame leaked — a plausible root for the long-standing intermittent AP ring-3 fault at the shm base). All three paths now follow the mmap discipline: allocation, object build, record, and handle under one lock hold with full rollback; the map itself per-page under brief holds; dma_free's translate/unmap/free per-page likewise. Contract edges from the same review: thread_spawn into a dying group returns -ESRCH (was generic -1); process_kill during the condemned window answers from the latch's stashed supervisor (0 or -EPERM, was -ESRCH once the leader slot was reaped); exit derives the group reason from its own argument rather than the racy exit_code global; a worker's thread_exit no longer overwrites a concurrent group-kill stamp; checkGroupDead now asserts exactly-one notification via the drained ring. Full suite: 100/100.
This commit is contained in:
@@ -359,6 +359,34 @@ pub fn groupDyingLocked(root: u64) bool {
|
||||
return false;
|
||||
}
|
||||
|
||||
/// The stashed supervisor of `root`'s DYING group, or null if the group is not
|
||||
/// dying. Answers the process_kill authority question during the condemned
|
||||
/// window, when the leader's task slot may already be reaped. Lock held.
|
||||
pub fn groupSupervisorLocked(root: u64) ?u32 {
|
||||
for (&address_space_refs) |*entry| {
|
||||
if (entry.count != 0 and entry.root == root) {
|
||||
return if (entry.dying) entry.group_supervisor else null;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// Undo a `recordSpaceMappingLocked` — the rollback half for a caller whose
|
||||
/// later step failed. Removes one matching slot; the caller drops the reference
|
||||
/// it had transferred. Lock held.
|
||||
pub fn removeSpaceMappingLocked(root: u64, object: *anyopaque) void {
|
||||
for (&address_space_refs) |*entry| {
|
||||
if (entry.count == 0 or entry.root != root) continue;
|
||||
for (&entry.mappings) |*slot| {
|
||||
if (slot.* == object) {
|
||||
slot.* = null;
|
||||
return;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/// The whole static task pool, for process.zig's group fan-out — which must scan
|
||||
/// members under the lock it already holds. Slots may be `.free`/`.reaping`;
|
||||
/// callers filter by state and must not hold pointers past the lock.
|
||||
|
||||
Reference in New Issue
Block a user