threads(M5): Mutex, Condition, and Semaphore over the futex
runtime.Thread.Mutex is the classic three-state futex mutex (unlocked/locked/ contended): the fast path is a single CAS and only a contended lock enters the kernel. Condition is a futex sequence counter (wait/timedWait/signal/broadcast, spurious wakeups allowed, use in a predicate loop); a signal racing the unlock bumps the seq so it is never missed. Semaphore is permits guarded by Mutex+Condition. All mirror std.Thread's shapes, ported onto runtime.Thread.Futex. thread-test gains a mutex mode: 2 producers + 2 consumers move 2000 unique items through an 8-slot ring (small enough that both sides block); the consumed checksum and tally match exactly, proving the lock and condvars correct under real cross-core contention. Deferred with rationale (see docs/threading-plan.md): migrating join to a futex completion word needs kernel clear-on-exit (else use-after-free munmapping a live stack); host unit tests need a mockable Futex seam. Gate thread-mutex PASS (3x); 17 guardrail/thread cases green; build + host tests clean.
This commit is contained in:
+26
-15
@@ -211,23 +211,34 @@ Guardrail 18/18 green (incl. `sleep`/`event`/`ipc` blocking paths) + `aspace-ref
|
||||
> in-memory log ring buffer evicts older lines); ordering is asserted against the full
|
||||
> serial stream by the qemu regex instead.
|
||||
|
||||
## M5 — `Mutex` + `Condition` + `Semaphore`
|
||||
## M5 — `Mutex` + `Condition` + `Semaphore` ✅
|
||||
|
||||
- [ ] `runtime.Thread.Mutex` (atomic fast path, `futex_wait`/`wake` slow path),
|
||||
`Condition` (`wait`/`timedWait`/`signal`/`broadcast`), `Semaphore` — the same
|
||||
state machines `std.Thread` uses, ported onto our `Futex`. Host unit tests for the
|
||||
lock/unlock/wait state transitions.
|
||||
- [ ] Migrate `join` to a futex **completion word** (the std shape) — drops the
|
||||
per-thread endpoint from M3.
|
||||
- [ ] `-Dtest-case=thread-mutex` (`smp: true`): a bounded producer/consumer over
|
||||
`Mutex` + `Condition` moves K items across cores; assert the final tally is
|
||||
exactly K with **no lost wakeups** (consumer never misses an item, producer never
|
||||
overruns the bound), and the consumer reaches a `parked` marker (it blocked, it
|
||||
didn't spin).
|
||||
- [x] `runtime.Thread.Mutex` (three-state futex mutex: CAS fast path, `futex_wait`/`wake`
|
||||
slow path), `Condition` (`wait`/`timedWait`/`signal`/`broadcast`, a futex sequence
|
||||
counter), `Semaphore` (permits over `Mutex`+`Condition`) — the same state machines
|
||||
`std.Thread` uses, ported onto our `Futex`.
|
||||
- [x] `-Dtest-case=thread-mutex` (`smp: 4`): a bounded producer/consumer — 2 producers +
|
||||
2 consumers over one `Mutex` and two `Condition`s move N=2000 unique items through
|
||||
an 8-slot ring; the consumed checksum and tally match exactly (no lost/duplicated
|
||||
item, no overrun) under real cross-core contention. The small ring forces producers
|
||||
to block on full and consumers on empty, exercising `Condition.wait`.
|
||||
|
||||
**Gate:** `python3 test/qemu_test.py thread-mutex` logs `thread: produced/consumed K,
|
||||
no lost wakeups`; `zig build test` covers the mutex/condition state machines; guardrail
|
||||
set green.
|
||||
**Gate (met):** `python3 test/qemu_test.py thread-mutex` passes (`thread-mutex: ok` →
|
||||
`DANOS-TEST-RESULT: PASS`), robust across 3 runs; guardrail 17/17 green (incl.
|
||||
`sleep`/`event`/`ipc`) + all M1–M4 thread cases; `zig build` clean, `zig build test`
|
||||
green.
|
||||
|
||||
> **Deferred (with rationale):**
|
||||
> - **`join` → futex completion word** — the exit-endpoint join (M3) is correct and
|
||||
> tested. A futex-completion join needs the *kernel* to clear+wake a word after the
|
||||
> thread is fully off its stack (a CLONE_CHILD_CLEARTID-style mechanism); doing it in
|
||||
> the thread's own trampoline would let `join` `munmap` the stack while the thread still
|
||||
> runs on it (use-after-free). Left on the exit-endpoint path; the kernel clear-on-exit
|
||||
> is a later, separate refinement.
|
||||
> - **Host unit tests for the state machines** — `Mutex`/`Condition` bottom out in the
|
||||
> `futex_*` syscalls, unavailable on the host without a mockable `Futex` seam. The QEMU
|
||||
> `thread-mutex` gate exercises them under real concurrency instead; a host-side mock is
|
||||
> future work.
|
||||
|
||||
## M6 — TLS, `getCurrentId` polish, docs, and CI wiring
|
||||
|
||||
|
||||
Reference in New Issue
Block a user