chore(legacy): remove unused legacy plugin loader and C-ABI nyash-file plugin; unify plugin headers to TypeBox v2
This commit is contained in:
@ -0,0 +1,59 @@
|
||||
# Async Task System — Phased Plan (P1–P3)
|
||||
|
||||
## Phase 1: Foundations (stabilize + timeouts)
|
||||
|
||||
- FutureBox: switch to Mutex+Condvar (done).
|
||||
- Await: poll scheduler + timeout gate in VM and JIT (done; unify to Result.Err in P3).
|
||||
- env.future.spawn_instance: enqueue via Scheduler; fallback sync if no scheduler (done).
|
||||
- Safepoint: ensure env.runtime.checkpoint is emitted around await (Lowerer rule).
|
||||
- Smokes: async-await-min; async-spawn-instance (safe form, no env).
|
||||
- Acceptance:
|
||||
- No hangs (await respects timeout); CPU near idle while waiting.
|
||||
- VM/JIT pass basic smokes; lingering processes do not remain.
|
||||
|
||||
## Phase 2: TaskGroup & CancellationToken
|
||||
|
||||
- Types:
|
||||
- CancellationToken { cancel(), is_cancelled() } idempotent; parent→child propagation only.
|
||||
- TaskGroup Box { spawn(fn)->Future, cancelAll(), joinAll() }, owns token; fini enforces cancel→join.
|
||||
- API:
|
||||
- nowait sugar targets current TaskGroup.
|
||||
- Unsafe detached spawn hidden behind unsafe_spawn_detached() and verifier checks.
|
||||
- VM implementation:
|
||||
- Extend scheduler to accept token; tasks periodically check token or are cancelled at await.
|
||||
- Group registry per scope; insert fini hooks in function epilogues and Main.
|
||||
- JIT/EXE:
|
||||
- NyRT shims accept optional token handle; if missing, use current group’s token.
|
||||
- Smokes:
|
||||
- spawn_cancel_on_scope_exit; nested_groups; lifo_join_order.
|
||||
- Acceptance:
|
||||
- Parent exit cancels and joins children deterministically (LIFO); no leaks per leak tracker.
|
||||
|
||||
## Phase 3: Error Semantics & Unification
|
||||
|
||||
- Future.await returns Result<T, Err> (Timeout/Cancelled/Panic) consistently (VM/JIT).
|
||||
- Remove 0/None fallbacks; map shims to Result at Nyash layer.
|
||||
- Lowerer verifies checkpoints around await; add verifier rule.
|
||||
- Observability: minimal counters and optional traces.
|
||||
- Smokes:
|
||||
- await_timeout distinct from cancel; panic_propagation; wakeup_race (no double resolve).
|
||||
- Acceptance:
|
||||
- Consistent error surface; result handling identical across VM/JIT/EXE.
|
||||
|
||||
## Test Matrix & CI
|
||||
|
||||
- Backends: {vm, jit, aot} × Modes: {default, strict}.
|
||||
- Smokes kept minimal; time‑bounded via timeout(1) wrapper.
|
||||
- CPU spin test: ensure idle waiting; measured via time/ps (best‑effort).
|
||||
|
||||
## Migration & Compatibility
|
||||
|
||||
- Keep env.future.spawn_instance during transition; TaskGroup.spawn preferred.
|
||||
- nowait sugar remains; mapped to TaskGroup.spawn.
|
||||
- Document flags: NYASH_AWAIT_MAX_MS, NYASH_SCHED_*.
|
||||
|
||||
## Files & Ownership
|
||||
|
||||
- Spec & Plan live here; updates linked from CURRENT_TASK.md.
|
||||
- Code changes limited to runtime/{scheduler,global_hooks}, boxes/future, jit/extern/async, lowerer await rules.
|
||||
|
||||
@ -0,0 +1,14 @@
|
||||
# Async Task System (Structured Concurrency) — Overview
|
||||
|
||||
Goal: A safe, structured, and portable async task system that runs end‑to‑end across Nyash code → MIR → VM → JIT/EXE.
|
||||
|
||||
- Default is safe: tasks are scoped to an owning group; when the owner ends, children cancel and join.
|
||||
- Everything is Box: TaskGroup and Future are Boxes; user APIs are Box methods; MIR uses BoxCall.
|
||||
- No new MIR ops required: use BoxCall/PluginInvoke consistently; safepoints are inserted around await.
|
||||
- Deterministic exits: parent exit triggers cancelAll → joinAll on children (LIFO), eliminating leaks.
|
||||
|
||||
This folder contains the spec, phase plan, and test plan:
|
||||
|
||||
- SPEC.md: User API, Box contracts, MIR/VM/JIT mapping, ABI, error semantics.
|
||||
- PLAN.md: Phased rollout (P1–P3), acceptance gates and checklists.
|
||||
|
||||
@ -0,0 +1,83 @@
|
||||
# Async Task System — SPEC
|
||||
|
||||
Scope: Define a structured concurrency model for Nyash with TaskGroup and Future as Boxes. Implementable across VM and JIT/EXE without adding new MIR instructions.
|
||||
|
||||
## User‑Facing API (Everything is Box)
|
||||
|
||||
Box TaskGroup
|
||||
- spawn(fn: () -> T) -> Future<T>
|
||||
- cancelAll() -> void
|
||||
- joinAll() -> void
|
||||
- fini: must run cancelAll() then joinAll() (LIFO order) to ensure structured shutdown.
|
||||
|
||||
Box Future<T>
|
||||
- await(timeout_ms?: int) -> Result<T, Err>
|
||||
- Ok(value)
|
||||
- Err(Timeout) | Err(Cancelled) | Err(Panic)
|
||||
- cancel() -> void (idempotent)
|
||||
|
||||
Sugar
|
||||
- nowait v = expr is sugar for: let g = current_group(); v = g.spawn(lambda: expr)
|
||||
|
||||
Default Ownership
|
||||
- An implicit TaskGroup is created per function scope and for Main. It owns tasks spawned in that scope.
|
||||
- Leaving the scope triggers cancelAll→joinAll on its group (LIFO), unless tasks were moved to a longer‑lived group explicitly.
|
||||
|
||||
Detachment (discouraged)
|
||||
- unsafe_spawn_detached(fn) only in advanced modules. Verifier should disallow use in normal code paths.
|
||||
|
||||
## MIR Mapping
|
||||
|
||||
- No new MIR instructions. Use existing BoxCall/PluginInvoke forms.
|
||||
- TaskGroup.spawn → BoxCall on TaskGroup Box, returns Future Box.
|
||||
- Future.await → BoxCall on Future Box with optional timeout parameter.
|
||||
- Lowerer inserts safepoint around await: ExternCall env.runtime.checkpoint before and after the await call.
|
||||
|
||||
Example Lowering (high level)
|
||||
- AST: nowait fut = arr.length()
|
||||
- MIR (normalized):
|
||||
- recv = … (arr)
|
||||
- mname = Const("length")
|
||||
- fut = ExternCall iface="env.future", method="spawn_instance", args=[recv, mname]
|
||||
- v = BoxCall Future.await(fut, timeout_ms?)
|
||||
|
||||
Note: In the final API, TaskGroup.spawn replaces env.future.spawn_instance, but the MIR contract remains BoxCall/ExternCall‑based.
|
||||
|
||||
## VM Semantics
|
||||
|
||||
- Scheduler: SingleThreadScheduler initially; spawn enqueues closure in FIFO. safepoint_and_poll() runs due tasks.
|
||||
- Future: implemented with Mutex+Condvar; set_result notifies; await waits with optional timeout; on cancel/timeout, returns Result.Err.
|
||||
- CancellationToken: parent→child propagation only, idempotent cancel().
|
||||
- TaskGroup: holds token and child registry; fini enforces cancelAll→joinAll (LIFO).
|
||||
|
||||
## JIT/EXE Semantics
|
||||
|
||||
- NyRT C‑ABI Shims:
|
||||
- nyash.future.spawn_method_h(type_id, method_id, argc, recv_h, vals*, tags*) -> i64 (Future handle)
|
||||
- nyash.future.spawn_instance3_i64(a0, a1, a2, argc) -> i64 (Future handle, by name/first args)
|
||||
- nyash.future.await_h(handle, timeout_ms?) -> i64/handle (Result encoding handled at Nyash layer)
|
||||
- Await shim must poll safepoints and honor timeout; returns 0 or sentinel; Nyash layer maps to Result.Err.*
|
||||
|
||||
## Errors & Results
|
||||
|
||||
- Distinguish Timeout vs Cancelled vs Panic.
|
||||
- Logging: concise, off by default; env flags can enable traces.
|
||||
- No silent fallback: unimplemented paths error early with clear labels.
|
||||
|
||||
## GC & Safepoints
|
||||
|
||||
- Lowerer must emit env.runtime.checkpoint immediately before and after await calls.
|
||||
- Scheduler.poll runs at checkpoints; long loops should explicitly insert checkpoints.
|
||||
|
||||
## Configuration
|
||||
|
||||
- NYASH_AWAIT_MAX_MS (default 5000) — global default timeout for await when not specified.
|
||||
- NYASH_SCHED_POLL_BUDGET — tasks per poll, default 1.
|
||||
- NYASH_SCHED_TRACE — prints poll/move/ran counts when 1.
|
||||
|
||||
## Security & Determinism
|
||||
|
||||
- Structured shutdown prevents orphan tasks after parent exit.
|
||||
- LIFO joinAll reduces deadlock surfaces.
|
||||
- Detached tasks are explicit and rare.
|
||||
|
||||
Reference in New Issue
Block a user