feat(jobs): real OS threads - Job.parallel_for, fn name, thread-safe Sync
- `fn name` names a top-level function as a value (E_FNREF, lowers to @fn_<name>); the worker entry point for Job.parallel_for, which checks it takes (int, pointer-like) and returns void. - runtime/native/threads.ll (pthreads) and threads_win.ll (Win32 SRWLOCK/CONDITION_VARIABLE): a pool of one worker per core but one, parked between batches; every thread claims chunks by compare-and-swap. Linked only into programs that use Job/Promise/Sync, by `ludicc -o`, `ludic build` and the test suite's build helper. - Sync.* is real: native mutexes, atomics as cmpxchg retry loops (neither clang takes atomicrw, the PC's rejects seq_consistent), mutex-guarded channels, Sync.cpu_count from the OS. - spawn/despawn on a pool thread stop the program with a located panic. - examples/library/threads.ludic and its test; docs for fn, Job.parallel_for, Job.is_worker. - Reseeded (bootstrap-cfree: out.ll == seed.ll). 141/141 on macOS; jobs, threads and the guard pass on Windows from the reseeded Windows seed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
f5d1a62ccf
commit
c10abd9f9f
22 changed files with 57464 additions and 55794 deletions
|
|
@ -4,4 +4,4 @@ title: Job
|
|||
order: 37
|
||||
---
|
||||
|
||||
Background work that stays out of the frame. A <code>Job</code> is a future — a handle to a result that lands later. Kick one off with <code>Job.run</code> (a background compute that advances a little each <code>Job.pump</code> and finishes after enough frames, so heavy work never hitches) or <code>Job.defer</code> (a future you resolve yourself with <code>Job.fulfill</code> / <code>Job.fail</code>). Poll it with <code>done</code> / <code>ok</code> / <code>failed</code> / <code>cancelled</code>, read <code>result</code> / <code>error</code>, and always collect on the main thread — a Job must never touch the ECS world directly. The scheduler is deterministic and cooperative, so the same jobs and the same budget reproduce byte-for-byte, every run and every target. Arguments are positional. Spliced in only when a program mentions <code>Job.*</code>.
|
||||
Background work that stays out of the frame. A <code>Job</code> is a future — a handle to a result that lands later. Kick one off with <code>Job.run</code> (a background compute that advances a little each <code>Job.pump</code> and finishes after enough frames, so heavy work never hitches) or <code>Job.defer</code> (a future you resolve yourself with <code>Job.fulfill</code> / <code>Job.fail</code>). Poll it with <code>done</code> / <code>ok</code> / <code>failed</code> / <code>cancelled</code>, read <code>result</code> / <code>error</code>, and always collect on the main thread — a Job must never touch the ECS world directly. The scheduler is deterministic and cooperative, so the same jobs and the same budget reproduce byte-for-byte, every run and every target. For work that should use every core now, <code>Job.parallel_for(count, fn work, ctx)</code> runs <code>work(i, ctx)</code> across a pool of real OS threads and returns when all of it is done; a worker computes on what it was handed and never changes the world. Arguments are positional. Spliced in only when a program mentions <code>Job.*</code>.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue