-
Notifications
You must be signed in to change notification settings - Fork 0
PID0: initial WASM guest with Host and Execution capabilities #28
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Draft
mikelsr
wants to merge
6
commits into
master
Choose a base branch
from
feat/pid0
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
The pid0 guest was exiting with status code 1 instead of 0 due to
resource handle portability issues when trying to pass custom stream
resources across WASM component boundaries.
Root Cause:
- Custom wetware:streams interface returned u32 handles that were
only valid in the host's resource table
- Guest's attempt to use these handles caused traps ("unknown handle")
- WASI stream budget violations occurred when writing without respecting
check_write() limits
- Resource cleanup caused "resource has children" errors due to
complex Cap'n Proto resource graphs
Solution:
- Switched from custom stream resources to stdio-based RPC
- pid0 guest now uses wasip2::cli::stdin/stdout for RPC transport
- Host's spawn_with_rpc() creates duplex channels for guest stdio
- Fixed StreamWriter to respect check_write() budget
- Added std::mem::forget() to avoid resource cleanup errors
Changes:
- Guest (guests/pid0): Use standard WASI stdio instead of custom streams
- Host (src/cell/executor.rs): Use spawn_with_rpc() instead of
spawn_with_streams_rpc()
- Cap'n Proto schema (capnp/peer.capnp): Simplified Executor interface
with runBytes() for bytecode-only execution
- RPC server (src/rpc/mod.rs): Implements Executor and Process interfaces
- Child guest (guests/child-echo): Simple test that prints CHILD_OK
Result:
- Guest successfully establishes Cap'n Proto RPC connection
- Spawns child process via Executor.runBytes() with raw WASM bytecode
- Child prints CHILD_OK and exits
- pid0 cleans up and exits with status code 0
Technical Details:
WASM Component Model resources are strongly typed and scoped. Passing
resource handles as u32 breaks the ownership model. Using stdio for RPC
avoids this by letting the host control what the guest's stdin/stdout
connect to (duplex channels), while Cap'n Proto treats them as standard
AsyncRead + AsyncWrite transports.
Added Executor.echo() method to validate that async Cap'n Proto RPC transports work at nested levels (child → host). Changes: - Added echo(message: Text) -> (response: Text) method to Executor interface in capnp/peer.capnp - Implemented echo method in host's ExecutorImpl that echoes back messages with 'Echo: ' prefix - Modified ExecutorImpl.run_bytes() to serve RPC system on child's stdio, allowing child processes to make RPC calls back to host - Transformed child-echo from simple stdout writer to full RPC client that makes two concurrent echo calls - Added stream adapters (StreamReader/StreamWriter) to child-echo - Added logging to track RPC call flow Architecture: Host serves Executor capability to pid0 over pid0's stdio. When pid0 calls runBytes() to spawn a child, host creates a NEW RPC system on the child's stdio serving the same Executor capability. This enables nested RPC: child → (via child's stdio) → host's Executor. Validation: - Child bootstraps RPC connection over its stdio - Child sends TWO concurrent echo requests - Host receives and responds to both calls - Validates pipelined/concurrent RPC at nested level - System exits successfully with code 0 Known Issue: Child's response logging doesn't work because its stdio is being used for RPC transport, so log messages would interfere with Cap'n Proto messages. Stderr logs work (start, rpc bootstrapped, sent requests) but stdout-based responses aren't visible. Host logs confirm RPC is working correctly. Result: Successfully demonstrates that async transports work through nested process boundaries with Cap'n Proto RPC.
- Replace the custom wetware stream resources with WASI `io/streams@0.2.9` in `wit/streams.wit`, so guests receive standard `input-stream`/`output-stream` resources. - Vendor `wasi:io@0.2.9` WIT in `wit/deps/io.wit` to satisfy `bindgen!` resolution for the local WIT package. - Update host bindings in `src/cell/proc.rs` to map WASI stream resources to `wasmtime_wasi_io::streams::DynInputStream/DynOutputStream` and implement `create-connection` with real async pipes (`tokio::io::duplex`). - Replace channel-based transport and stub pollables with `AsyncReadStream`/`AsyncWriteStream`, giving true readiness signals and backpressure from Wasmtime’s WASI IO implementation. - Simplify host RPC wiring to consume the duplex halves directly in `src/cell/executor.rs` and `src/rpc/mod.rs` (no `streams::Reader/Writer`). - Rework `DataStreamHandles` to hold a duplex stream and update tests to validate full-duplex behavior using split read/write halves. - Update guest runtime to use `wasip2::io::streams` + `wasip2::io::poll`, and replace the busy-spin loop with `wasi::io::poll::poll` in `guests/guest-runtime/src/lib.rs`. - Bump `wasip2` to `1.0.2+wasi-0.2.9` in `guests/child-echo` and `guests/pid0`, and add `wasip2` to `guests/guest-runtime` to wire bindings cleanly. - Add `wasmtime-wasi-io` dependency in `Cargo.toml` to support host-side WASI stream resources. - Update `PLAN.md` to reflect the completed async transport migration and next validation steps.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
No description provided.