DocsEngine design

Threading model

Fixed by section 4 of the brief; this page records how it is realised and which shared state exists.

Threads #

Thread Owner Runs
Main process SDL event pump, window and input, surface acquire and wgpuSurfacePresent, ImGui, frame orchestration; also executes jobs while waiting on a counter.
Job workers (cinder-worker), one per logical core minus one JobSystem (cinder/core/jobs.mojo), threads created by cn_thread_create Everything else: culling, animation, ECS systems, asset decode, physics step orchestration.
Jolt workers Jolt's own job system (JPH_JobSystemThreadPool) Physics islands; contact callbacks are posted to the MPMC event queue from these threads.
miniaudio device thread miniaudio Mixing; only the shim's log and end-of-sound callbacks run there and they post events.
wgpu-native internal threads wgpu Callbacks post events (ADR-0003). Mojo never runs on them.

Shared state and how it is protected #

State Mechanism
Job deques, job table, counters Chase-Lev deque protocol with Atomic and explicit orderings; counters are atomic.
Worker parking cn_semaphore_* (counting semaphore) plus an atomic idle count; submit posts only when a worker is parked.
Native callback results (wgpu, Jolt, miniaudio, SDL log) CnEventQueue, a bounded lock-free MPMC ring in the shim; drained by the main thread each frame. Overflow is counted, never silent.
Everything else Owned by one thread. Cross-thread hand-over happens only by submitting a job whose data the submitter keeps alive until the counter reaches zero.

Rules #

  1. Mojo code never runs inside a C callback (ADR-0003). The only Mojo functions that run on native threads are job-system worker entry points, which Cinder itself created.
  2. A job's data pointer must stay valid until the counter it was submitted with reaches zero; the submitter owns that memory (arena, pool or stack with keep).
  3. JobSystem.reset() is called at frame start only, when no job is queued or running.
  4. No locks exist in Mojo code. If one ever becomes necessary it must be listed here with its owner and the invariant it protects.
View as MarkdownSource: docs/THREADING.md