std::runtime
std::runtime defines a runtime interface layer that sits underneath the
rest of the standard library.
The goal is to make OS- and environment-specific primitives pluggable while
keeping the public std::... APIs stable. The default std shipped with the
compiler targets a hosted POSIX baseline, but other environments (Windows,
non-POSIX, embedded, sandboxed runtimes) should be able to provide their own
runtime implementation by supplying an alternate stdlib root with compatible
std::runtime::... modules.
Motivation#
std::fs,std::task,std::sync, and other OS-facing std modules need low-level primitives (files, clocks, threads, syscalls).- Those primitives differ significantly across platforms.
- Keeping these differences confined to
std::runtime::...avoids scatteringextand platform#ifstyle logic across the entire stdlib.
Structure#
The std runtime is organized as:
std::runtime::<area>— a stable interface module used by the rest of std.std::runtime::posix::<area>— the default POSIX-backed implementation used by the compiler’s shipped stdlib on hosted targets.
Example:
std::runtime::fsis the interface used bystd::fs.std::runtime::posix::fsprovides the POSIX implementation usingextcalls likeopen(2),read(2), andclose(2).
In the shipped stdlib today:
std::runtime::memdelegates tostd::runtime::posix::mem,std::runtime::fsdelegates tostd::runtime::posix::fs(hosted baseline; onwasm32-wasithe compiler rewrites this tostd::runtime::wasi::fs, which implements a filesystem subset using WASI Preview 1 preopened directories and resolves relative paths against a virtual cwd),std::runtime::iodelegates tostd::runtime::posix::io(hosted baseline; onwasm32-wasithe compiler rewrites this tostd::runtime::wasi::io, which implements stdio primitives and maintains a POSIX-shapederrnocell for higher-level wrappers likestd::runtime::process),std::runtime::taskdelegates tostd::runtime::posix::task,std::runtime::syncdelegates tostd::runtime::posix::sync,std::runtime::timedelegates tostd::runtime::posix::time(hosted baseline; onwasm32-wasithe compiler rewrites this tostd::runtime::wasi::time, which implements the samemonotonic_now_ns/unix_now_ns/unix_now_mscontract with WASI Preview 1 clocks),std::runtime::envdelegates tostd::runtime::posix::env,std::runtime::processdelegates tostd::runtime::posix::process(hosted baseline; onwasm32-wasithe compiler rewrites this tostd::runtime::wasi::process, which implements_exitvia WASIproc_exitandchdir/getcwdvia a virtual cwd layer),std::runtime::netdelegates tostd::runtime::posix::net(hosted sockets),std::runtime::regexis implemented via bundled runtime support (libsilk_rt) and is used bystd::regex,std::runtime::unicodeis implemented via bundled runtime support (libsilk_rt) and is used bystd::unicode,std::runtime::numberis implemented via bundled runtime support (libsilk_rt) and is used bystd::number,std::runtime::readlineis implemented via bundled runtime support (libsilk_rt) and is used bystd::readline,std::runtime::gpuis implemented via bundled runtime support (libsilk_rt), dynamically discovers HIP on Linux, and is used bystd::gpu,std::runtime::windowuses bundled runtime support (libsilk_rt) on macOS/iOS and local unsupported-provider stubs on targets without a current window provider; it is used only by the opt-instd::windowfacade.
The long-term shape is still that std::runtime::<area> remains the stable
interface point, while platform backends (such as std::runtime::posix::<area>
and std::runtime::windows::<area>) can exist as separate modules in an
alternate stdlib root without changing higher-level std::... modules.
Interface Design Rules#
- The
std::runtime::...surface is allowed to be low-level andunsafe: raw pointers, integer error codes, and OS-specific constants are acceptable. - When an operation can fail, prefer returning the error code as a value
(via
std::result::Result(T, int)or an optional errorint?) so callers do not need to pair a sentinel return with a separateerrno()query. - Higher-level, ergonomic, and allocation-aware APIs belong in
std::...modules (for examplestd::fs::File.read_to_end). std::runtime::...modules should avoid exposing platform-specific struct layouts directly to Silk code when possible; prefer integer-like handles and pointer-plus-size patterns.- The stable contract is the Silk-level signature in
std::runtime::..., not the specificextspellings used by the POSIX backend. - Low-level primitives should be localized:
- libc allocator
extbindings (malloc/free/realloc) and compiler-backed raw-memory/string intrinsics (__silk_*) live instd::runtime::posix::mem(and analogous backendmemmodules), - other runtime backend modules should call those exported wrappers instead
of declaring duplicate allocator/intrinsic
extsites. - for example, the shipped WASI backends (
std::runtime::wasi::ioandstd::runtime::wasi::time) usestd::runtime::wasi::memfor allocation and__silk_*intrinsics.
Considerations#
Runtime areas in the shipped stdlib:
std::runtime::mem— low-level allocation and compiler-backed intrinsics used by higher-level std modules (alloc/realloc/free, rawload/store, and string view helpers), plus basic environment queries used by higher-level wrappers (for examplepage_size()formmapalignment).- when an active region context is established with
with(regions), allocations are routed to that region for the dynamic extent of thewithblock (including calls into stdlib code): std::runtime::mem::allocallocates from the active region instead of the heap,std::runtime::mem::reallocreallocates region pointers by allocating a new region block and copying bytes (it never calls libcreallocon a region-backed pointer),std::runtime::mem::freeis a no-op for region-backed pointers.- pointers returned by
std::runtime::mem::allocare owned by Silk; they must be released withstd::runtime::mem::freeand are not valid to pass to libcfree()directly. std::runtime::build— build metadata provided by the compiler:is_debug() -> boolreturnstruewhen the current artifact was compiled withsilk ... --debug(or-g).kind() -> stringreturns the current build kind ("executable","object","static", or"shared").mode() -> stringreturns the current build mode ("debug","release", or"test").version() -> stringreturns the current package version when building a package, otherwise"0.0.0".- the module also exports Formal Silk build-gating theories:
build_kind_is(...)build_mode_is(...)requires_debug_mode()requires_release_mode()requires_executable_kind()requires_object_kind()requires_static_kind()requires_shared_kind()build_version_at_least(...)std::runtime::gpu— Linux host-side GPU discovery, tracked device memory, bounded copies, packed explicit-kernarg kernel launch, synchronization, and last-error access used bystd::gpu; see runtime gpu.std::runtime::fs— filesystem primitives used bystd::fs(hosted baseline; onwasm32-wasithe shipped backend supports a small subset using the first preopened directory as a sandbox root, and resolves relative paths against a virtual cwd (std::runtime::wasi::cwd)).- includes read-only mapping helpers (
mmap_readonly/munmap); onwasm32-wasimapping is currently unsupported and reportsInvalidInput. - includes
mkstemp(template_ptr)for creating unique temporary files from a writable NUL-terminated template ending inXXXXXX(hosted POSIX baseline). Onwasm32-wasithis operation is currently unsupported and reportsInvalidInput. - includes raw stat metadata queries (
stat,lstat,fstat) plus path classification (path_kind) and owned canonical path resolution (realpath) for higher-level wrappers such asstd::fs::{stat,lstat,fstat,path_kind,is_regular_file,realpath}. - on the hosted POSIX baseline,
stat/path_kindfollow symlinks,lstatreports the link itself, andrealpathresolves symlinks via the underlying OS, - on
wasm32-wasi,stat/lstat/fstatare implemented from WASI preview1 filestat syscalls with a reduced metadata set,path_kindis supported, andrealpathis currently unsupported and reportsInvalidInput. std::runtime::io— low-level stdio primitives used bystd::io(onwasm32-wasi, rewritten tostd::runtime::wasi::io, which maintains a POSIX-shapederrnocell for wrappers that still queryerrno()). This surface also includesasync fnwrappers (read_async/write_async) backed by the hosted async runtime onlinux/*; on other targets they complete immediately by issuing the blockingread/writeoperation. It also includes PTY helpers used bystd::process::child::Command.spawn_ptyon the hosted POSIX baseline (pty_open,pty_prepare_child).std::runtime::task— hosted task/runtime primitives used bystd::task(sleep/yield_now/available parallelism; currently blocking OS-thread operations; delegates tostd::runtime::posix::taskin the shipped stdlib).std::runtime::sync— hosted synchronization primitives used bystd::sync(mutexes/condvars and allocation helpers; delegates tostd::runtime::posix::syncin the shipped stdlib. Onwasm32-wasithe compiler rewrites this tostd::runtime::wasi::sync, which is a single-thread stub backend.)std::runtime::time— hosted time primitives used bystd::temporaland other std modules:- monotonic clock reads (
monotonic_now_ns), - Unix wall-clock timestamp reads (
unix_now_ns/unix_now_ms), - delegates to
std::runtime::posix::timein the shipped stdlib, - the POSIX implementation reads into a calling-thread stack
timespecthrough the bundled runtime, so clock reads are allocation-free, reentrant across task workers, and supported by--noheapbuilds. std::runtime::env— hosted environment primitives used bystd::env(process environment variables; delegates tostd::runtime::posix::envin the shipped stdlib on hosted targets. Onwasm32-wasithe compiler rewrites the backend tostd::runtime::wasi::env, which implementsgetenvviaenviron_sizes_get/environ_get(caching the environment snapshot for the process lifetime) and leavessetenvunsupported).std::runtime::process— hosted process primitives used bystd::process(current working directory plus child-process primitives forstd::process::child; delegates tostd::runtime::posix::processin the shipped stdlib on hosted targets. Onwasm32-wasi,_exitis implemented viaproc_exit, whilechdir/getcwdare implemented via a virtual cwd layer (std::runtime::wasi::cwd); hosted child-process operations remain unsupported).std::runtime::net— hosted networking primitives used bystd::net(IPv4/IPv6 TCP + UDP sockets plus hostname resolution used bystd::net::resolve_host; delegates tostd::runtime::posix::netin the shipped stdlib).- Apple Security runtime helpers — bundled
silk_rt_apple_crypto_*symbols used by the Appleplatformsecurity provider forstd::cryptocore/random operations. These helpers are statically linked when referenced and requireSecurity.frameworkon Apple targets. std::runtime::z3— low-levelextbindings for the Z3 C API (built-in on the glibc hosted layout; musl targets require an explicit downstream Z3 library).std::runtime::regex/std::runtime::unicode/std::runtime::number/std::runtime::readline— non-OS-specific runtime helpers used bystd::{regex,unicode,number,readline}. These are implemented viaextbindings to a small bundled runtime support library (libsilk_rt) that ships alongside the compiler.std::runtime::readlinenow also includes process-global completion-list management used by the publicstd::readline::{clear_completions,add_completion}surface.- the compiler statically links this bundled runtime support into executable
and shared-library outputs (no runtime
DT_NEEDEDdependency onlibsilk_rt*). - embedders can override internal allocation used by
libsilk_rt(for example regex runtime compilation) by callingsilk_rt_set_allocator(seeinclude/silk/rt.h) before invoking anysilk_rt_*entrypoints. This hook affects allocations routed throughsilk_rt_malloc_bytes/silk_rt_realloc_bytes/silk_rt_free_bytes; it does not change the allocator used bystd::runtime::memfor heap-backed pointers. - allocator changes affect future bundled-runtime allocations. Any pointer
returned by
silk_rt_malloc_bytes(...)remembers the realloc/free hooks that created it, so latersilk_rt_realloc_bytes(...)/silk_rt_free_bytes(...)calls keep allocator identity stable across later allocator changes. Runtime-owned regex bytecode uses that same lifetime rule. - the allocator override is process-global, but bundled-runtime helper calls
and
silk_rt_set_allocatorare internally synchronized while reading or updating the current hook set. Concurrent allocator changes can still affect which hook future bundled-runtime allocations use. silk_rt_realloc_bytes(...)andsilk_rt_free_bytes(...)only accept pointers that correspond to a currently live allocation previously returned bysilk_rt_malloc_bytes(...)orsilk_rt_realloc_bytes(...). Foreign pointers, forged helper headers, stale pre-reallocpointers, and already-freed helper pointers are all treated as non-live inputs and ignored safely (reallocreturnsNULL,freeis a no-op).- when building with
--noheap, the compiler linkslibsilk_rt_noheap.ainstead oflibsilk_rt.a. In that configuration,libsilk_rtperforms no default heap allocation unless an embedder installs an allocator viasilk_rt_set_allocator. std::runtime::window— low-level target/provider detection, opaque provider handles, nonblocking provider event polling, high-level providerrun(...)/run_ex(...)boundaries, and native window-control hooks used bystd::window. The shipped runtime currently opens AppKit windows with stdlib creation options, pumps one AppKit event at a time, exposes AppKit title/visibility/focus/size/position/minimize/maximize/always-on-top/ background controls, entersUIApplicationMainand creates a visibleUIWindowon iOS when launched from the generated app bundle, and rejects GTK/unsupported targets through local stubs that do not declare window provider externs.std::runtime::graphics::metal— low-level macOS Metal runtime boundary used bystd::graphics::metalandstd::graphics::window. It declares thesilk_rt_metal_*device, queue, layer, drawable, render-pass, encoder, buffer, library, pipeline, draw, and compatibility clear-window ABI only for macOS. Unsupported-target behavior stays in the public graphics facades so non-Metal targets do not lower Metal provider externs.
Follow-ups are expected to introduce additional runtime areas:
- Async event loop / executor integration (
std::runtime::event_loop) for hostedasync/await: - the compiler already ships a bundled bring-up executor in
libsilk_rt(src/silk_rt_async.c) and lowersasync/awaitto it on the hostedlinux/x86_64target, - the
std::runtime::event_loopmodule now exposes low-level awaitable building blocks (timers + fd readiness, includingfd_wait_readable2andfd_wait_readable_any) and an explicitHandle/pollsurface for manually driving the hosted executor/event loop. Higher-level async adapters are still follow-up work (see async runtime). - the hosted executor is thread-affine:
Handle.poll()/Handle.deinit()must be called from the same OS thread that created the handle; cross-thread wake is supported viaHandle.wake(). - abort-aware wrappers exist for cooperative cancellation (
std::abort_controller): sleep_ms_abortable(ms, sig) -> boolfd_wait_readable_abortable(fd, sig) -> boolfd_wait_writable_abortable(fd, sig) -> boolIn the Supported forms, aborts are generally observed only before/after the awaited operation. Forfd_wait_readable_abortable, when the runtime can provide a pollable abort fd (AbortSignalBorrow.wait_fd()), aborts can interrupt an in-flight wait by awaitingfd_wait_readable2(fd, abort_fd). When no pollable abort fd is available, it falls back to the before/after checks.- WASI networking (via WASI sockets or similar proposals) when supported by the toolchain targets.
Providing a Custom Runtime#
To provide your own runtime implementation underneath the standard library,
ship an alternate stdlib root that includes compatible std::runtime::...
modules.
For a CLI-focused walkthrough of selecting a std root and archive, see howto custom stdlib root.
At a minimum, your stdlib root should provide the runtime areas used by the
higher-level std modules you want to reuse. For example, to reuse the shipped
std::task and std::sync, provide:
std/runtime/task.slkimplementing thestd::runtime::taskinterface (available_parallelism,yield_now,sleep_us),std/runtime/sync.slkimplementing thestd::runtime::syncinterface (alloc_zeroed,heap_free, mutex/condvar ops),
and similarly for std::fs (std/runtime/fs.slk) if you reuse std::fs.
To reuse std::io, provide std/runtime/io.slk implementing the
std::runtime::io interface (STDIN_FD, STDOUT_FD, STDERR_FD, read,
write, dup, read_async, write_async, puts, and hosted fd helpers used
by std::process::child such as dup2, pipe, poll, and set_cloexec).
Fallible operations should return errors directly:
- value-returning operations use
std::result::Result(T, int)whereErr(int)is a stable, area-specific error code consumed by higher-levelstd::...wrappers (for examplestd::io::IOFailed.code), - status operations use optional errors (
int?), returningNoneon success andSome(code)on failure.
On hosted POSIX, runtime wrappers typically map errno into these stable codes
inside std::runtime::<area> so callers do not need to pair sentinel returns
with a separate errno() query.
To reuse hosted time helpers in std::temporal, provide std/runtime/time.slk
implementing the std::runtime::time interface (monotonic_now_ns,
unix_now_ns, and unix_now_ms).
Selecting the Runtime (Toolchain)#
Because std::runtime is part of the stdlib source tree, selecting a custom
runtime is done by selecting a custom stdlib root:
- CLI: pass
--std-root <path>(and optionally--std-lib <path>to provide a prebuilt std archive), or setSILK_STD_ROOT/SILK_STD_LIB. - Embedding ABI: set
silk_compiler_set_std_root(and optionally setSILK_STD_LIBto point at a prebuilt std archive).
When no suitable std archive is provided, the compiler can fall back to compiling the reachable std sources as part of the build on supported targets.
Building a Custom Std Archive#
For supported native hosted archive targets in the current toolchain
(linux/x86_64 and macos/aarch64), a prebuilt stdlib archive
(libsilk_std.a) contains one object per std module.
Archive member naming requirement (current scheme):
- the archive member name is the module path relative to the std root with
/replaced by_, and.slkreplaced by.o, - for example:
std/runtime/posix/task.slk→runtime_posix_task.o.
The in-repo make stdlib target produces archives with this naming scheme.
Source repository · Edit this page · View Markdown