The Green Runtime (--green)
--green builds the server on an experimental, from-scratch stackful-coroutine + epoll runtime (runtime/green/) instead of the default thread-per-connection model.
./weld examples/calc.weld --green --emit bin -O ReleaseSafe
./weld examples/db.weld --green --profile --emit bin -O ReleaseSafeWhat it is
- Each connection is a cheap green task (a coroutine), not an OS thread.
- One green event loop runs per core (
SO_REUSEPORT, thread-local schedulers), so the kernel load-balances connections across cores. - A proper HTTP/1.1 connection: keep-alive, fragmented / large request accumulation, per-socket idle timeouts (slow-loris guard), and graceful shutdown across all carriers.
- The context switch is hand-written per target, so
--greencross-compiles and runs on x86_64, aarch64, and riscv64 (all validated under qemu; other arches are a clean compile error).
Preemption
CPU-bound handlers can't monopolise a carrier:
- Every loop back-edge is a cooperative yield point (
__coop), keeping/pingat p90 ~3 ms while 24 compute-heavy requests saturate all carriers. - For code with no such points (a loop-free blob, or a big JSON parse inside std), a sysmon thread signals real async preemption (SIGURG; the handler swaps out of the coroutine and
sigreturnrestores it later — arch-agnostic), so even those can't monopolise a carrier (p90 ~50 ms with cooperative yielding fully disabled).
Non-blocking outbound I/O
Outbound Postgres, gRPC, and HTTP and HTTPS upstreams run on a green std.Io — their socket ops park the coroutine on epoll instead of blocking the carrier, so a slow call doesn't stall its neighbours. HTTP uses a pooled keep-alive green client; HTTPS runs std.crypto.tls over the same green socket. WebSocket hubs work too — an upgrade builds a live green socket, so idle readers yield instead of pinning a carrier. Pool and lock waits spin-yield rather than block the carrier.
Memory
Handlers borrow their large buffers from a per-thread pool, so coroutine stacks are 64 KB (256 KB with upstreams/TLS) and mmap'd with a guard page. An idle keep-alive connection holds ~64 KB + a ~16 KB grow-on-demand request buffer.
When to use it
--green targets high-concurrency, I/O-bound workloads: many connections, slow upstreams, lots of idle keep-alive sockets. It has been soak-tested (bench/) under 150 s of adversarial mixed load — keep-alive floods, malformed/partial requests, connection churn, slow-loris — with flat RSS (~11 MB), no fd leak, and zero crashes.
Add --profile for a per-phase, per-route timing breakdown printed on shutdown.
Experimental
The green runtime is experimental. The default thread-per-connection server remains the conservative choice; reach for --green when concurrency and outbound-I/O overlap are the bottleneck.