← board

Parallel processing as a language feature

Motivation

Expose parallelism as a first-class language surface, not just raw pthread binding. Today there is low-level groundwork — --threadsafe / {$THREADSAFE ON} emits atomic refcounts, and test/test_multithreading.pas drives raw pthread workers — but no language constructs for spawning and joining work, sharing data safely, or expressing data-parallel loops.

Scope (design-open)

Pick a model and a minimal surface; this ticket is the design + first slice:

Design context: ../../developer/threads-todo.md (ordered thread arc), ../../developer/threading-and-heap-design.md. The worker-pool / resumable-frame mechanism can be shared with feature-async-coroutines (one event loop + pool, two surfaces) — design them together rather than twice.

Why blocked

Concurrent allocation needs a proven thread-safe heap contract for the active memory-management mode. The unified allocator has landed, and --threadsafe covers important refcount paths, but Track A still needs to audit/define the heap behavior for real preemptive threads; see feature-threadsafe-heap-contract. Parallel code doing I/O also wants feature-threadsafe-io-serialization (statement-atomic write/writeln) — not a hard blocker, but expect to need it in the same breath.

ESP32 / FreeRTOS (decided 2026-06-18)

Threads route through the OS/RTOS — PXX will not ship a bare-metal scheduler. Rationale: anyone wanting threads on ESP is, in practice, already pulling in ESP-IDF for Wi-Fi / BLE / drivers, so threads = FreeRTOS tasks (the IDF profile). See developer/concurrency-memory-model.md.

Distinct from the coroutine work: stackless/stackful coroutines are cooperative and the RAM-cheap default for embedded (feature-async-auto-backend / feature-stackful-coro-port). Threads are the preemptive multicore axis and only make sense on the IDF profile.

Formalise --esp-profile={idf,bare} with idf as the default (≈99% of real apps use something from IDF) and bare a first-class one-flag opt-in (tiny images, no IDF toolchain, fast language testing under qemu). Tracked here because the threads ⇒ idf rule needs the profile to be an explicit, queryable selector. Today the IDF path is implied by .o/--emit-obj output and bare by --esp-profile=bare; unify them under one flag.

Acceptance

A program spawns workers, joins results, and shares data through the chosen primitives with correct results under repeated runs (data-race-free for the covered surface); self-host fixedpoint holds; --threadsafe covers the atomic paths. On ESP: the thread surface compiles+runs under the IDF profile (FreeRTOS tasks, optional core pin) and is a clear error under --esp-profile=bare.

SHIPPED — parallel for (2026-07-17, closing)

Data-parallel loop delivered end to end, self-host byte-identical throughout, gated in test-threads/test-core:

Accepted limitations (decisions, not defects — every one a CLEAN compile error)

Closed. Remaining epic items live in [[meta-multithreading]].

Log

Part of the multithreading epic (2026-06-30)

Umbrella: [[meta-multithreading]]. Invariant: threading is opt-in/off-by-default; single-threaded self-build stays byte-identical; no libc (Linux syscalls only).