Authors need predictable queue semantics without implicit blocking on the default channel.
Concurrency package - Contracts and edge cases
Platform spec article
Concurrency package - Contracts and edge cases
Spec standingStandard
-
Factory defaults and explicit bounded/unbounded options for Channel construction.
Context
Decision
Rule Detail Default Unbounded when ChannelOptionsis omitted or no bounded capacity is setBounded ChannelOptions.Bounded(n)withn > 0Unbounded ChannelOptions.Unbounded(equivalent to default)Factory Channel<T>.Create(options: ChannelOptions = default)Consequences
Documentation must warn about memory growth on unbounded channels. Bounded queues park senders when full.
Verification anchors
Corelib concurrency tests; runtime channel builtins.
-
Cancellation signalling, event ordering, and join/channel error paths.
Context
Fibers need cooperative cancellation without panics on join or parked channel ops.
Decision
Rule Detail Signal Fiber.Cancel()sets runtime cancellation flagEvent Each Fiber<T>declaresevent OnCancelled(); runtime raises on child before unblocking parked opsJoin Join→Result<T, FiberError::Cancelled>after cancellation observedChannels Parked Send / Receive → ChannelError::CancelledOrdering OnCancelled runs before Join / channel errors; handlers must not block on Join of self Consequences
Unhandled panic in OnCancelled aborts process in v1 (same as other unhandled event paths).
Verification anchors
Corelib + runtime concurrency tests; cancel/join fixtures.
-
Fair multiplexing across registered channels when multiple receives are ready.
Context
FIFO registration order starves late channels when an early channel is always ready.
Decision
Rule Detail Algorithm Round-robin among channels with a ready Receive Cursor Per- Hubindex advanced after each successful WaitReceivev1 scope WaitReceive only — no WaitSend Consequences
Console hubs should keep registration count small (under 16 typical).
Verification anchors
Hub integration tests in runtime and corelib suites.
-
main() fiber id, join/detach policy, and process teardown.
Context
Process lifetime must be defined when main returns while child fibers still run.
Decision
Rule Detail Main main()runs on fiber 0Shutdown When mainreturns, runtime Joins spawned fibers that were not DetachedDetach Detach waives parent Join; child panic still aborts process Leak Spawn without Join or Detach before mainends → conformance warning in v0.2 testsConsequences
Future recovery policies require a new ADR; v1 aborts on undetached child panic.
Verification anchors
Runtime shutdown tests; conformance warnings catalog.
-
Error surfaces for channel, fiber join, and mutex operations.
Context
Panics as control flow for expected failure modes break contracts and LSP stability.
Decision
Surface Rule Channel Send / Receive → Result; TrySend / TryReceive →OptionFiber Join → Result<T, FiberError>; stack overflow →FiberError::StackOverflowat JoinMutex Lock → Result<MutexGuard, MutexError>; TryLock →Option(None= would block)Consequences
v1: Lock may return
Cancelledwhen fiber cancelled—no .NET-style poison.Verification anchors
Corelib API signatures; runtime integration tests.
-
Keyword policy for fiber introduction vs deferred async syntax.
Context
Aligns with inception ADR D-INC-0008; avoids dual concurrency models in v1.
Decision
Rule Detail Keyword spawnrequired for new fibers; nogoalias in v1Reserved asyncandawaitare parse errors (reserved, not implemented)Data transfer Channel only between fibers for data; Mutex / WaitGroup for coordination Handles Fiber<T>andChannel<T>are move-onlyConsequences
Parser and semantic tests reject async/await; spawn lowering returns
Fiber<T>.Verification anchors
Parser fixtures; Fibers and spawn.
-
Ship many fibers with one GC mutator; document phase B parallel mutators.
Context
Parallel GC mutators require write barriers not ready for initial ship.
Decision
Phase Rule A (ship) Many fibers, one GC mutator; gc_write_barrierno-opB (documented) Parallel mutators + real barriers; no corelib API break Consequences
Scheduler and memory specs must stay consistent with phase A barriers.
Verification anchors
Runtime GC tests; memory-and-gc-runtime-contract feature.
-
Processor count, stack sizes, and phase A arena policy.
Context
Hosts need predictable defaults without per-program scheduler tuning.
Decision
Setting Default ProcessorCountHost logical CPU count at init Stacks 64 KiB initial, 8 MiB max Arena Phase A: one process arena; pool threads run Beskid mutator code under scheduler rules Consequences
Fiber scheduler design model article details syscall parking.
Verification anchors
-
Multi-receiver/sender rules and close behavior.
Context
Authors need defined fan-in/fan-out and close idempotence.
Decision
Rule Detail Receivers Multiple allowed; each message delivered to exactly one successful Receive (FIFO) Senders Multiple allowed unless SingleWriter hint (hint only v1) Close Any handle holder may Close; idempotent writer shutdown void spawn Fiber<Unit>when entry returns no valueConsequences
Close after drain returns
ChannelError::ClosedinResult.Verification anchors
Runtime concurrency.rs; corelib channel tests.
-
Hub type parameter, limits, and heterogeneous deferral.
Context
Heterogeneous select requires tagged unions or multiple hubs in v1.
Decision
Rule Detail Fairness Round-robin (see D-CORE-CONC-0003) Max registrations 256 per hub ( HubError::Limitpossible)Element type Homogeneous — one Hub<T>wraps onlyChannel<T>with sameTHeterogeneous Not v1 — use multiple hubs or Channel<HubMessage>Result HubReceiveResult { index: i64, value: T }Consequences
UI/console hubs should stay well below 256 registrations.
Verification anchors
Hub builtin tests; examples article.
-
Spawn entry types vs fiber handle contract surface.
Context
Authors should not declare cancellation events on arbitrary spawn closures.
Decision
Rule Detail Placement OnCancelled on Fiber<T>handle fromspawnonlySpawn entry Ordinary fn(...) -> T; does not declare OnCancelledHandle Fiber<T>struct wrapping runtime builtinsConsequences
Lowering wires cancel slot from handle metadata.
Verification anchors
Semantic + lowering tests for spawn.
-
Mutex API for v1 coordination.
Context
TryLock supports non-blocking attempts; Lock parks with cancel path.
Decision
Rule Detail TryLock In v1 — returns Option<MutexGuard>Lock Parks until acquired or Cancelled Consequences
No poison semantics in v1.
Verification anchors
Mutex corelib tests.
-
Monotonic time API owned by concurrency package in v0.2.
Context
Legacy
rt_now_millisand scattered clock builtins confuse package boundaries.Decision
Concurrency.NowMillis() -> i64in concurrency package replaces legacyrt_now_millis. Wall clock deferred to futureSystem.Time.Consequences
Wall-clock ADR required before exposing civil time in corelib.
Verification anchors
Builtin spec table; corelib clock smoke tests.
-
Compile-time rule preventing join cycles on fiber stacks.
Context
Parent/child Join cycles deadlock the scheduler.
Decision
Child Join parent → compile-time diagnostic JoinWouldDeadlock. Parent Join child and sibling Join remain allowed.
Consequences
Diagnostic registry documents JoinWouldDeadlock.
Verification anchors
Semantic analyzer tests for join graph.
- Concurrency package - Contracts and edge cases Send, Receive, Join, Cancel, and Hub normative contracts.
- Concurrency package - Decisions record (legacy index) Migration index pointing to per-decision ADR files under adr/—normative text lives in ADRs, not this page.
- Concurrency package - Design model Package layout, module map, and thin-wrapper rule for Fiber and Channel structs.
- Concurrency package - Examples Illustrative spawn, Channel, and Hub usage (informative).
0 revisions (git unavailable at build; counts may be empty)
No commits recorded for this path.
| Section id | Required | Found |
|---|---|---|
what-this-feature-specifies | yes | yes |
implementation-anchors | yes | yes |
Full tree: run pnpm verify:platform-spec-layout (writes src/generated/platform-spec-layout-report.json).
Channel<T>
Section titled “Channel<T>”Construction
Section titled “Construction”Channel<T>.Create(options: ChannelOptions = default)— default is unbounded.ChannelOptions.Bounded(n)—n > 0; Send parks when full (Wait mode).ChannelOptions.Unbounded— equivalent to default; queue grows until OOM (documented risk).ChannelOptions.SingleReader()/SingleWriter()— unbounded factories that set optimization hints without changing queue semantics.- Optional capacity field inside options must not contradict
Bounded/Unboundedvariant; bounded wins whenBounded(n)is chosen.
Send and Receive (full names required)
Section titled “Send and Receive (full names required)”| Method | Contract |
|---|---|
| Send | Result<(), ChannelError>; blocks/parks fiber when full (bounded + Wait mode) |
| Receive | Result<T, ChannelError>; parks when empty and open |
| TrySend | Option<()> — None if would block |
| TryReceive | Option<T> — None if would block |
| Close | Idempotent writer close; no panic |
ChannelError (closed set)
Section titled “ChannelError (closed set)”Closed— endpoint closedCancelled— owning fiber cancelled (Cancel / OnCancelled path)
TrySend / TryReceive use Option only (None = would block); no ChannelError::Full.
ChannelOptions (.NET-inspired, sync-only)
Section titled “ChannelOptions (.NET-inspired, sync-only)”- SingleReader / SingleWriter — optimization hints; behavior unchanged if violated but may enable faster paths
- BoundedChannelFullMode::Wait — default; sender parks
- No
AllowSynchronousContinuations(async-only .NET concept)
Fiber<T>
Section titled “Fiber<T>”Fiber<T> is a corelib struct (runtime handle) that must declare:
event OnCancelled();The spawn entry function does not declare OnCancelled — only the handle type does.
| Method | Contract |
|---|---|
| Join | Result<T, FiberError> — Ok(value), Cancelled, StackOverflow, Panicked |
| Detach | void; parent waives Join; child panic aborts process |
| Cancel | void; raises OnCancelled on child fiber, then unblocks parked ops with Cancelled |
OnCancelled runs on the child fiber. Unhandled failure in a handler aborts the process. Handlers must not Join self, Join an ancestor, or block indefinitely.
Join from a child fiber to a parent (or ancestor) handle is a compile error (JoinWouldDeadlock).
M3 completion requires generated code to import the ABI symbol fiber_spawn_with_cancel_slot, pass the handle’s OnCancelled event slot, and treat the returned handle as an i64 fiber id rather than a pointer.
FiberError (closed set)
Section titled “FiberError (closed set)”CancelledStackOverflowPanicked— carries diagnostic handle / message policy per runtime
Hub<T>
Section titled “Hub<T>”- Homogeneous only in v1 —
Hub<T>registers onlyChannel<T>instances - Register(index, channel) / Unregister(index) —
indexis user-choseni64key in WaitReceive result - WaitReceive →
Result<HubReceiveResult, HubError>whereHubReceiveResultcarries member index and received value - Round-robin fairness among ready channels (see decisions record)
- Multiplexing unlike types: use
Channel<HubMessage>(enum/union) or multiple hubs — not mixed-type Hub in v1 - WaitSend — not in v1
- Replaces language-level
selectfor v1
Mutex and WaitGroup
Section titled “Mutex and WaitGroup”- Mutex.Lock →
Result<MutexGuard, MutexError> - Mutex.TryLock →
Option<MutexGuard>(Noneif would block) - Mutex.Unlock — explicit in v1 (no
deferrequired for spec) - WaitGroup.Wait parks until counter zero; Add/Done follow Go semantics
Console integration
Section titled “Console integration”Console.OnResize and control onTick paths must publish into a Channel<T> (or Hub member) so UI fibers Receive events without multicast event invocation across fibers. Language event syntax may remain for single-fiber use; cross-fiber UI must use Channel (see console-terminal-events).