Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@ jobs:
uses: ./.github/workflows/ci.yml
native-stack:
uses: ./.github/workflows/native-stack.yml
sustained:
uses: ./.github/workflows/sustained.yml
plan:
needs: [canonical, native-stack]
needs: [canonical, native-stack, sustained]
permissions:
contents: read
id-token: write
Expand Down
59 changes: 59 additions & 0 deletions .github/workflows/sustained.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
name: sustained runtime

on:
workflow_dispatch:
workflow_call:

permissions:
contents: read

jobs:
sustained:
name: sustained (${{ matrix.target }}, ${{ matrix.carriers }} carriers)
strategy:
fail-fast: false
matrix:
runner: [ubuntu-24.04, macos-14]
carriers: [1, 4]
include:
- runner: ubuntu-24.04
target: linux-x86-64
system: Linux
machine: x86_64
- runner: macos-14
target: macos-arm64
system: Darwin
machine: arm64
runs-on: ${{ matrix.runner }}
timeout-minutes: 85
env:
CARGO_TARGET_DIR: ${{ github.workspace }}/target/sustained
CARGO_HOME: ${{ github.workspace }}/target/cargo-home
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Verify native host
env:
EXPECTED_SYSTEM: ${{ matrix.system }}
EXPECTED_MACHINE: ${{ matrix.machine }}
run: |
test "$(uname -s)" = "$EXPECTED_SYSTEM"
test "$(uname -m)" = "$EXPECTED_MACHINE"
- name: Install Rust
run: rustup toolchain install 1.96.1 --profile minimal
- name: Build locked default runtime
run: cargo build --locked --release -p vthread-lab --bin vthread-lab
- name: Qualify one sustained process
run: >-
python3 scripts/run-sustained.py
--binary "$CARGO_TARGET_DIR/release/vthread-lab"
--out .qualification/sustained --duration 3600
--carriers ${{ matrix.carriers }} --tasks 4096
- name: Upload sustained evidence
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: sustained-${{ github.run_id }}-${{ matrix.target }}-${{ matrix.carriers }}
path: .qualification/sustained/
include-hidden-files: true
retention-days: 90
if-no-files-found: error
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,18 @@

## Unreleased

## 0.1.0-rc.3 - 2026-09-11

- Require sustained runtime qualification before release planning: one uninterrupted
hour on Linux x86_64 and macOS ARM64, with both one and four carriers and
4,096-task mixed batches. Verify lifetime accounting, service reclamation,
cancellation, shutdown, and sampled memory and descriptor growth after warmup.
- Preserve the RC.2 runtime implementation and document the repaired inbox
notification boundaries, tested operating scope, and production support contract
intended for `0.1.0`. Keep final publication separate from RC qualification.
- Update shared package versions, exact dependency pins, lockfiles and examples
together. The full Release rehearsal now requires the sustained gate.

## 0.1.0-rc.2 - 2026-09-11

- Keep the signed-off RC runtime and reconcile its history with public main.
Expand Down
10 changes: 5 additions & 5 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 4 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,17 @@ members = ["crates/vthread", "crates/vthreads", "crates/vthread-stack", "crates/
resolver = "3"

[workspace.package]
version = "0.1.0-rc.2"
version = "0.1.0-rc.3"
edition = "2024"
rust-version = "1.96"
license = "Apache-2.0"
repository = "https://github.com/zsumz/vthread"
authors = ["vthread contributors"]

[workspace.dependencies]
vthread = { path = "crates/vthread", version = "=0.1.0-rc.2" }
vthread-stack = { path = "crates/vthread-stack", version = "=0.1.0-rc.2" }
vthread-sync-core = { path = "crates/vthread-sync-core", version = "=0.1.0-rc.2" }
vthread = { path = "crates/vthread", version = "=0.1.0-rc.3" }
vthread-stack = { path = "crates/vthread-stack", version = "=0.1.0-rc.3" }
vthread-sync-core = { path = "crates/vthread-sync-core", version = "=0.1.0-rc.3" }
zio = { version = "=0.0.1-dev.1", default-features = false }
socket2 = { version = "=0.6.5", default-features = false }
libc = "=0.2.189"
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ Add vthread to your project:

```toml
[dependencies]
vthread = "=0.1.0-rc.2"
vthread = "=0.1.0-rc.3"
```

```rust
Expand Down Expand Up @@ -76,7 +76,7 @@ for verification coverage and known limitations.

## Compatibility

vthread `0.1.0-rc.2` is a candidate for production use on its supported platforms
vthread `0.1.0-rc.3` is a candidate for production use on its supported platforms
within the documented boundaries. The eventual `0.1.0` release and subsequent
`0.1.x` releases will keep compatible public API updates within `0.1`; breaking API
or contract changes move to `0.2`. Tested configurations and known limitations are
Expand Down
86 changes: 78 additions & 8 deletions RELEASE.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,81 @@ Release automation uses [zrelease](https://github.com/zsumz/zrelease), pinned to
[the Rehearse workflow](.github/workflows/rehearse.yml) and
[the Release workflow](.github/workflows/release.yml).

The signed candidate is `0.1.0-rc.2` at
[`793e675`](https://github.com/zsumz/vthread/commit/793e675c2c3ddc13940607ab4ec3342e209d0568).
The current candidate is `0.1.0-rc.3`. It retains the published RC.2 runtime
implementation and adds the sustained production-scope gate described below.
Package versions, exact internal dependency
pins, and the release tag must agree. Both workflows enable zrelease's lockstep
policy; a stable-looking tag over RC packages is rejected. No final release is
being prepared in this cycle.
policy; a stable-looking tag over RC packages is rejected. This cycle prepares
and qualifies an RC; final `0.1.0` publication remains a separate action.

## Production support contract

The release standard for `0.1.0` is **production ready within the documented
supported workloads and platforms**, with a deliberately limited feature set.
Supported applications use `vthread` or its `vthreads` alias on Linux x86_64 or
macOS ARM64 with Rust 1.96+ and unwinding panics. Internal support crates are
implementation dependencies, without a direct-use compatibility commitment.

Structured ownership, carrier affinity, bounded admission and services,
cooperative cancellation, and controlled shutdown are supported contracts.
Correctness failures within those contracts are bugs to fix. Public API and
contract changes remain compatible throughout `0.1.x`; breaking changes require
`0.2`. Standard-library blocking, arbitrary native faults, stack overflow, and
non-cooperative work retain the boundaries documented in [Security](SECURITY.md).

Feature completeness is not a release gate. Native correctness checks, the
application load/failure matrix, sustained qualification, and exact archive and
consumer verification are gates. A passing RC qualifies its own version and
source; final-version manifests and archives must pass the release gates again.

## Inbox progress repairs

The notification weaknesses discussed in the older release notes have concrete
repairs in the current runtime. Active carriers treat published inbox depth as
work to receive, independently of a delayed notification. A later publisher wakes
an already parked carrier, and waiter registration rechecks the queue under its
mutex before sleeping. These changes are recorded in
[`f92e5de`](https://github.com/zsumz/vthread/commit/f92e5dec76ae52340dd2086649538a1bfa1ef723)
and [`1ac097c`](https://github.com/zsumz/vthread/commit/1ac097c3039c9a167e7504f74edcd652921345fc).

The canonical gate exercises paused notifiers, active and parked carriers,
registration races, small queues with multiple producers, and a production-shaped
4,096-task refill. Boundary regressions demonstrated failures before the repairs;
the sustained gate exercises repeated lifetimes and reclamation on the repaired
runtime. The old pre-repair warning does not describe today's notification protocol.

## Sustained qualification

The full **Release** workflow, including `publish: false`, requires
[sustained runtime](.github/workflows/sustained.yml) before creating a release
plan. The compact automatic branch rehearsal remains a faster package check.

| Platform | Carriers | Mixed worker batch | Required uninterrupted duration |
| --- | --- | --- | --- |
| Linux x86_64 | 1 and 4, separate processes | 4,096 tasks | One hour per process |
| macOS ARM64 | 1 and 4, separate processes | 4,096 tasks | One hour per process |

Each default-feature optimized process retains one runtime across batches and
performs payload-checked TCP and bounded-channel exchanges, contended mutex
handoffs, semaphore admission, timers, native blocking jobs, carrier-affinity
checks, and cancellation races. Every batch checks service drain; final shutdown
checks active tasks, pending wakes, readiness registrations and native work.
The supervisor requires at least one million completed task lifetimes per
process, exact spawn/completion and park/wake accounting, exact stack acquisition
accounting, and the expected mutex updates. A timeout, crash, or restart fails.

RSS and open descriptors are sampled every ten seconds. After ten minutes of
warmup, the baseline is the next ten-minute median. The final ten-minute median
and every warmed sample must stay within the larger of 32 MiB or 20% of baseline
RSS, and within eight descriptors of baseline. Missing measurements fail the
gate. These are declared resource-growth checks for this workload, not a fixed
memory-per-task or universal throughput promise. The receipt records source,
lockfile and binary hashes, host, workload counts, samples, and gate results.

The separate 22-case application matrix checks concurrency 1/16/64/256 with one
and four carriers, fixed arrivals at 2,000/second, overload rejection, deadline
recovery, and shutdown while clients are blocked. These configurations define
the tested scope; they are not maximum supported capacity or latency guarantees.

## Practice a release

Expand Down Expand Up @@ -128,7 +197,7 @@ node dist/install.mjs --sha "$(git rev-parse HEAD)" \
```

Regenerate when the workspace dependency graph changes. Preserve the caller's
canonical and native-stack prerequisites, automatic branch rehearsal, explicit
canonical, native-stack and sustained prerequisites, automatic branch rehearsal, explicit
publish condition, `main` requirement for publication, and the consumer smoke
inputs and lockstep policy in both workflows. Run `actionlint` and `zcheck run check` before committing the update.

Expand All @@ -149,9 +218,10 @@ and binary identities for debug and release on both targets.
The RC signoff is the runtime baseline; each release run records fresh evidence
for its own source commit and archives. Historical closeout records remain in
Git history and the archived candidate evidence. Automation does not establish
new scale or performance claims. Alternate-stack sanitizer hooks, larger
simultaneous populations, cross-platform sustained runs, memory footprint,
loaded tails, and controlled-host idle CPU remain unqualified. Local timing is
new scale or performance claims. The sustained matrix above adds cross-platform
lifetime and resource-growth coverage. Alternate-stack sanitizer hooks, populations
above the tested scope, absolute memory footprint, controlled loaded-tail targets,
and controlled-host idle CPU remain unqualified. Local timing is
observational; `zcheck run perf-cancellation-history` is a separate timing guard.

The eventual `0.1.0` and subsequent `0.1.x` releases preserve public API
Expand Down
8 changes: 4 additions & 4 deletions benchmarks/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions benchmarks/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
[package]
name = "vthread-benchmarks"
version = "0.0.0"
version = "0.1.0-rc.3"
edition = "2024"
publish = false
license = "Apache-2.0"

[features]
allocation-probe = []
Expand All @@ -11,7 +12,7 @@ scheduler-profiling = ["vthread/scheduler-profiling"]
handoff-profiling = ["scheduler-profiling", "vthread/handoff-profiling"]

[dependencies]
vthread = { path = "../crates/vthread" }
vthread = { path = "../crates/vthread", version = "=0.1.0-rc.3" }

[profile.release]
codegen-units = 1
Expand Down
2 changes: 1 addition & 1 deletion crates/vthread-stack/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Use [`vthread`](https://github.com/zsumz/vthread) in applications. Its public cr
forbids unsafe Rust. This support crate isolates the unsafe stack mechanics and has no
compatibility contract for direct downstream use.

See [release notes](https://github.com/zsumz/vthread/blob/v0.1.0-rc.2/RELEASE.md)
See [release notes](https://github.com/zsumz/vthread/blob/v0.1.0-rc.3/RELEASE.md)
for verification coverage and known limitations.

## Ownership and safety
Expand Down
2 changes: 1 addition & 1 deletion crates/vthread-sync-core/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ The narrow exclusive-value and protocol core supporting `vthread` synchronizatio
Use [`vthread`](https://github.com/zsumz/vthread) in applications. This support crate
has no compatibility contract for direct downstream use.

See [release notes](https://github.com/zsumz/vthread/blob/v0.1.0-rc.2/RELEASE.md)
See [release notes](https://github.com/zsumz/vthread/blob/v0.1.0-rc.3/RELEASE.md)
for verification coverage and known limitations.

## Runtime boundary
Expand Down
6 changes: 3 additions & 3 deletions crates/vthread/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ suspension points. The public runtime crate forbids unsafe Rust.

Supported targets are Linux x86_64 and macOS ARM64, with Rust 1.96 or newer and
`panic = "unwind"`. Builds with `panic = "abort"` are rejected.
See [release notes](https://github.com/zsumz/vthread/blob/v0.1.0-rc.2/RELEASE.md)
See [release notes](https://github.com/zsumz/vthread/blob/v0.1.0-rc.3/RELEASE.md)
for verification coverage and known limitations.

vthread `0.1.0-rc.2` is a candidate for production use on its supported platforms
vthread `0.1.0-rc.3` is a candidate for production use on its supported platforms
within the documented boundaries. The eventual `0.1.0` release and subsequent
`0.1.x` releases will keep compatible public API updates within `0.1`; breaking API
or contract changes move to `0.2`.
Expand All @@ -21,7 +21,7 @@ Add vthread to your project:

```toml
[dependencies]
vthread = "=0.1.0-rc.2"
vthread = "=0.1.0-rc.3"
```

```rust
Expand Down
2 changes: 1 addition & 1 deletion crates/vthreads/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ runtime-evidence = ["vthread/runtime-evidence"]
qualification = ["vthread/qualification"]

[dependencies]
vthread = { path = "../vthread", version = "=0.1.0-rc.2" }
vthread = { path = "../vthread", version = "=0.1.0-rc.3" }

[lints]
workspace = true
Loading