-
Notifications
You must be signed in to change notification settings - Fork 0
API Contracts
This page defines Elio's public API responsibility boundaries. Use it together with the feature guides and header comments when triaging issues or reviewing security-sensitive behavior.
Specific API documentation can narrow or extend these rules. When a feature page or header gives a more specific contract, the more specific contract wins. If no page says an object is safe for concurrent use, callers must serialize mutable access to that object.
The tables below intentionally name concrete public interfaces. They are a calling-contract inventory, not a full overload reference. See API Reference for signatures and examples. A plural row covers only the named type, concept, or listed function family in that row; do not treat an unnamed helper as covered by a broad module heading without checking the feature page or header comment.
- Treat "Elio guarantees" as library-side behavior. A regression against those guarantees is a bug or contract issue.
- Treat "Caller must guarantee" as an application precondition. Violating those preconditions is caller misuse unless Elio separately promises fail-closed behavior for that path.
- For ambiguous cases, clarify the contract first, then decide whether code changes are still required.
- Protocol input from peers is a library boundary. Application payload meaning after protocol parsing is an application boundary.
- Low-level parser, buffer-view, and verbs-adjacent interfaces can have stricter caller preconditions than high-level helpers.
| Area | Elio guarantees | Caller must guarantee |
|---|---|---|
| Object lifetime | Public APIs preserve memory safety when documented lifetimes are met. Awaiters clean up registered waiters when their owning coroutine frame is destroyed according to the API contract. | Keep borrowed buffers, spans, callbacks, streams, schedulers, TLS contexts, RDMA objects, and other externally owned resources alive for the documented duration. |
| Thread safety | APIs documented as concurrent-safe protect their own internal state. Protocol send helpers that document frame serialization prevent interleaved wire frames. | Unless documented otherwise, serialize access to mutable objects from multiple coroutines or threads. Do not issue overlapping operations on non-concurrent streams or clients. |
| Cancellation and timeouts | Cancellation requests are cooperative and best-effort. APIs with cancel_token or timeout parameters preserve one terminal operation state and report cancellation through their documented result channel. A request does not roll back I/O side effects, and an actual completion may win a cancellation race. |
Pass the relevant token into operations that support cancellation and handle the documented result. A runtime or wrapper request does not forcibly destroy a child operation or wake a wait that does not observe that token. |
| Results and terminal states | Operations report errors through their documented result type, optional return, errno, or exception path. Protocol objects transition to closed/error states as documented. |
Check operation results before using returned values. Do not continue using an object after a documented terminal state unless the API documents reuse. |
| Resource limits | Configured size limits, session limits, queue limits, and deadlines are enforced at the documented layer. | Choose limits and timeouts that fit the application's threat model. Unlimited or zero-disabled limits are an application policy choice. |
| Application callbacks | Elio invokes registered callbacks at documented points and preserves protocol/resource invariants around them. | Callback code must be exception-safe for the documented callback path, must not outlive captured state, and must avoid recursively calling APIs that forbid reentry. |
| Input ownership | Elio copies or consumes data only when the API documents copying or ownership transfer. | Keep spans, std::string_view, iovec arrays, SGE arrays, and external buffers alive until the operation that references them has completed or cleanup has run. |
| Interface | Elio guarantees | Caller must guarantee |
|---|---|---|
coro::task<T> |
A task is a move-only, single-shot lazy owner. Moving transfers the unstarted coroutine frame and leaves the source empty. Awaiting binds virtual-stack ancestry to the actual awaiter and, between Elio task promises, establishes one-way cancellation propagation before returning the result or rethrowing the stored exception. Linking cancellation may allocate and propagate allocation failure from co_await. Destroying a non-empty task destroys its frame unless ownership was transferred to the runtime. Runtime policy remains in the promise's shared execution context, not in the task object. |
Do not await an empty or already-awaited task. Do not treat moving a task as migration, cancellation authority, or running work. Treat a foreign coroutine promise as a cancellation boundary unless adapter code deliberately bridges a token. Keep objects referenced by the coroutine alive across suspension points. |
Direct co_await on Elio awaitables |
Awaitables resume through the scheduler or backend path documented by that awaitable. | Do not destroy the awaited object, scheduler, stream, buffer, or synchronization primitive while an await is still registered unless the API documents safe teardown. |
join_handle<T> |
Awaiting a join handle returns the spawned task result or rethrows its exception. is_ready() is a non-blocking result-readiness check and can precede frame destruction. is_destroyed() observes frame release; after wait_destroyed() returns for a normally completed spawned wrapper, its frame parameters, callable, arguments, and captures have been destroyed. request_cancel() publishes a cooperative request through the spawned wrapper's shared execution context and remains safe after frame destruction; it does not rewrite a result that already completed. The request propagates down direct lazy-task awaits between Elio tasks. |
Await or intentionally discard join handles according to the task lifetime you need. Call wait_destroyed() only from a non-coroutine thread that may block. Do not use a moved-from handle. Pass this_coro::cancel_token() into cancellation-aware waits inside the task. Do not assume request_cancel() forcibly destroys the task, stops it promptly, crosses a foreign coroutine promise, or cancels a separate explicit token. Registered callback exceptions can propagate from request_cancel(). |
coro::task_group |
Owns registration, cancellation, failure collection, and completion accounting for children submitted to one scheduler. The default failure policy records the first child failure, requests sibling cancellation, waits for every registered child frame to leave the group, and then rethrows that failure from the direct single-use join() awaitable. join() does not create or link a nested task. collect_all records failures without cancelling siblings and reports them together through task_group_error. A nonzero max_concurrency bounds executing child bodies while preserving every accepted child registration. outstanding_children() counts accepted child submissions, not an active task_scope() body. A group created on its scheduler inherits the current task's cancellation token. Its join continuation always resumes on a worker of the selected scheduler. An ordinary external thread, including the thread that called scheduler::start(), synchronously dispatches cancellation there; a worker in another scheduler posts cancellation asynchronously to avoid cross-scheduler deadlock. |
Call join() exactly once while executing on a worker of the group's scheduler, and keep the group alive until it completes. Pass this_coro::cancel_token() into cancellation-aware child operations; cancellation is cooperative and cannot finish a child blocked in work that ignores its token. Do not spawn after joining starts. Keep child captures alive through join. Treat an explicitly selected scheduler as the group's only execution domain and keep it running until the group drains. Account for synchronous callback execution and possible blocking on ordinary external threads; do not assume cancellation has run when a request returns on another scheduler's worker. The destructor requests cancellation but does not synchronously join. |
coro::task_scope() |
Creates a task group for a callback-shaped lexical scope and runs the body under the group cancellation context. Normal return joins all children. A fail-fast child can therefore wake a token-aware suspended body before the scope joins and reports the child failure. If a body awaitable resumes elsewhere, scope cleanup hands execution back to a worker of the selected scheduler. The body callable and its captures remain alive until the children join. If the body throws, the scope requests child cancellation and joins every child. Fail-fast then rethrows the body failure; collect_all reports the body failure together with every child failure in task_group_error. |
Use it when lexical cancel-and-join is required. The body must return an Elio task, must not call join() on its own group, and must not allow token-ignoring work to outlive captured resources. The explicit-scheduler overload must initially be awaited on a worker of that scheduler; it does not migrate a foreign worker or external thread into the scope. Automatic local objects in the body coroutine are destroyed when that coroutine returns, so children that can outlive the body must not retain references to those locals. Choose collect_all or a concurrency bound explicitly when fail-fast and unlimited execution are not suitable. Keep the selected scheduler running through cleanup and caller resumption. |
coro::generator<T> |
next() delivers yielded values in producer order and returns completion through the documented optional result. It binds producer virtual-stack ancestry to the active consumer and restores the consumer context before yield and completion transfers, including after internal asynchronous suspension. |
Use it as a single-consumer stream unless a future generator API documents sharing. Do not retain yielded references or views beyond their documented lifetime. |
coro::cancel_source |
Calling cancel() publishes cooperative cancellation and synchronously dispatches callbacks outside the state lock. Same-dispatch reentrant teardown may remove a later selected callback. After dispatch, cancel() rethrows the first callback exception. Concurrent calls publish one request. |
Keep callback code reentry-safe and account for execution on the requesting thread. Do not assume cancellation forcibly destroys operations that do not observe the token. Handle callback exceptions where callbacks may throw. |
coro::cancel_token |
Cancellation-aware operations observe the token at their documented wait or poll points. Destroying or unregistering a callback registration prevents a callback not yet selected by cancellation. Outside callback dispatch, teardown waits when another thread has selected or started the callback. During callback reentry, cross-dispatch teardown is deferred to prevent mutual wait cycles; the callback payload remains dispatcher-owned. Self-unregistration and reentrant removal of a later callback by the same synchronous dispatcher do not deadlock. | Pass the token into every operation that should stop. Keep externally owned callback state synchronized: teardown called from another cancellation callback is not a cross-dispatch join point. Synchronize shared state accessed by different callbacks. An outer request cannot cancel waits that never receive or check the token. |
coro::this_coro::cancel_token() |
Returns the current Elio task's runtime cancellation token. Outside an active Elio runtime frame it returns a default never-cancelled token. | Treat it as a cooperative request channel. Pass it into each operation that should react. Explicit token parameters remain independent unless application or framework code deliberately bridges them. |
elio::when_all() |
Returns a lazy task that registers every supplied task-producing callable in one scheduler-bound task group. A child whose body has not started when cancellation is already visible may finish without invoking its callable. The first child failure requests sibling cancellation, every accepted child is joined, and then that failure is rethrown. Later child failures are routed to the scheduler unhandled-exception handler. A launch-time callable-transfer failure takes precedence over child failures because not every branch was accepted. Parent cancellation that leaves a required result unavailable throws combinator_cancelled after drain. |
Supply callables that return Elio tasks. Pass this_coro::cancel_token() into waits that should stop on fail-fast or parent cancellation. Keep captures valid until the combinator returns. |
elio::when_any() |
Returns a lazy task, selects the first successful or exceptional branch completion, requests cancellation of the remaining branches, and joins every accepted loser before publishing the winner. A launch-time callable-transfer failure takes precedence over an already selected winner because not every branch was accepted. Otherwise, a winner exception is rethrown; a later loser exception is routed to the scheduler unhandled-exception handler before return. Parent cancellation with no winner throws combinator_cancelled. |
Accept the supplied cancel_token, or use this_coro::cancel_token(), for work that should stop when another branch wins. A token-ignoring loser delays return until natural completion. Keep captures valid until the combinator returns. |
elio::with_timeout() |
Owns the callable by value and races it against a cancellable timer in a structured when_any(). If the timer reports expiry first, Elio requests child cancellation and returns a timed-out result only after the callable reaches a terminal state. Parent cancellation is distinct from expiry and throws combinator_cancelled when no callable result exists. Concurrent expiry and parent cancellation use the timer's documented best-effort terminal result, so either outcome may be observed. |
Treat the duration as a deadline for requesting cancellation, not a guaranteed return-time bound. Pass move-only callables as rvalues. Pass the supplied token or this_coro::cancel_token() into every operation that should stop promptly. Keep externally referenced captures valid until return. |
elio::go() |
Stores callable arguments in the spawned coroutine frame and runs the task independently until completion. | Use value captures for detached work that can outlive the caller. Keep referenced external objects alive. |
elio::go_to() |
Sets task affinity before the first resume and requests execution on the selected worker when the scheduler can honor it. | Pass a valid worker ID when deterministic pinning matters. Handle fallback/resizing behavior for out-of-range or retired workers. |
elio::spawn() |
Stores callable arguments in the coroutine frame and returns a join handle for result, exception, and task-local cancellation requests. Separate spawned tasks have independent cancellation contexts. | Await the handle when result, exception, or completion ordering matters. Keep referenced captures alive until the task completes. Use a structured scope, not independent spawn alone, when caller-to-child lifetime and cancellation propagation are required. |
ELIO_GO, ELIO_GO_TO, ELIO_SPAWN
|
Provide inline spawn syntax. | These macros use reference captures; every referenced object must outlive the spawned coroutine. Prefer explicit captures for detached work. |
runtime::scheduler |
Starts worker threads, runs submitted coroutine tasks, routes per-worker I/O, and performs orderly shutdown according to its API. Its lifecycle is one-shot: after shutdown begins, later start() calls do not restart workers or scheduler-owned resources, and set_thread_count() does not change the worker count. Graceful shutdown atomically closes independent initial admission before waiting; work accepted before that boundary may still enqueue continuations and register structured task-group children while draining, while external task-group submission remains closed. Before teardown, linked admission is sealed and the tracked accepted set is rechecked under the lifecycle lock, so a running untracked raw task cannot add a child after the final idle observation. Concurrent shutdown callers are serialized through teardown, and external callers wait for worker-initiated teardown to finish. A worker request made while an external resize is waiting for that worker is handed to the resize controller, so the worker-side call can return before final teardown. An actively I/O-pinned continuation is routed only to the worker/context generation that owns the operation, including while that worker is draining after a resize. Raw spawn/spawn_to detach construction-time ancestry for independent work. Raw try_spawn and try_schedule variants preserve caller ownership on rejection; consuming spawn variants destroy rejected handles. try_schedule/try_schedule_to preserve await ancestry. |
Start it before submitting work that requires runtime or I/O services. Keep it alive while scheduler-owned objects and tasks can use it. Create a new scheduler instead of attempting to restart one after shutdown. Treat every independent initial submission concurrent with or later than lifecycle closure as potentially rejected, and handle each API's documented ownership/result path. Do not destroy the scheduler from one of its own worker threads. Do not assume a worker-side shutdown_force() call has synchronously joined that worker; use an external lifecycle owner when teardown completion must be observed. Do not use a spawn variant to resume a suspended handle or a try_schedule variant for initial ownership handoff. Check a try_ scheduling result and retain, resume, destroy, or otherwise resolve the still-live handle on failure. |
runtime::worker_thread |
Owns a worker queue and I/O context used by the scheduler. | Treat worker objects as scheduler-owned unless an API explicitly exposes direct control. |
runtime::wait_strategy |
Controls worker idle waiting behavior according to selected policy. | Choose a strategy that matches latency, CPU, and power goals; it is not a correctness synchronization primitive. |
runtime::run_config |
Configures run() and async-main scheduler defaults. |
Set thread counts, backend options, and shutdown policy deliberately for the process. |
elio::run() |
Creates and drives a scheduler for the supplied async entry point, returning its result or surfacing failure as documented. | Do not nest independent schedulers unless the involved APIs document that pattern. Keep process-level resources valid for the entry point. |
ELIO_ASYNC_MAIN |
Bridges a coroutine entry point into a process main. |
Follow the macro's required function shape and avoid owning another incompatible scheduler around it. |
runtime::autoscaler |
Samples scheduler state and applies configured scale actions while serializing its own config updates. | Keep the scheduler alive while the autoscaler runs. Choose min/max bounds, thresholds, and custom actions that are valid for the workload. |
spawn_blocking() and blocking pool |
Runs blocking or CPU-heavy callables outside scheduler worker execution and resumes the awaiting coroutine on its scheduler. Without scheduler context it uses a standalone detached thread. If a scheduler exists but its blocking pool is unavailable, it stays on the current worker and throws std::runtime_error; it does not migrate to a detached thread. |
Use it for work that would block or starve scheduler workers. Keep callable captures valid by value/reference rules. Keep the scheduler alive through completion and handle pool-rejection exceptions where the pool can be shut down independently. |
runtime::current_worker_id() |
Reports the current worker ID when running on a scheduler worker. | Handle the no-current-worker case according to the return contract. |
runtime::set_affinity() |
Requests migration or pinning to the target worker according to scheduler affinity rules. | Use valid worker IDs for deterministic placement and account for resizing. |
runtime::clear_affinity() |
Clears caller-requested affinity. It does not clear an active operation-local I/O pin. | Use it only when the coroutine no longer needs caller-selected placement. Do not treat it as cancellation or migration of pending I/O. |
runtime::bind_to_current_worker() |
Binds the current coroutine to its current worker when one exists. | Call it only after entering scheduler execution and before relying on worker-local resources. |
Process fork() boundary |
Before any Elio runtime or I/O resource is used, a single-threaded process may fork and let parent and child create independent fresh runtimes. If a runtime or any other thread is active, the parent may continue while the child immediately calls an explicitly async-signal-safe exec function such as execve(), or _exit(). See Fork Safety. |
Do not schedule, resume, cancel, poll, shut down, destroy, or replace inherited Elio runtime state in the child. Do not unwind inherited Elio owners or call std::exit(). Do not assume every exec-family wrapper is async-signal-safe. Elio installs no pthread_atfork repair hooks; satisfy the fork contracts of the C/C++ runtime and all other linked libraries as well. |
coro::task_execution_context, promise_base::execution_context()
|
Keep scheduler-visible task policy alive through shared ownership independently of coroutine-frame lifetime. The context owns task-chain cancellation authority and stores user affinity, the internal worker-local flag, and read-only ownership metadata for an active I/O pin. Operation completion and cancellation state remain owned by each awaitable/backend lifecycle. | Treat the context as a runtime integration boundary, not as proof that a coroutine frame or pending operation remains live. Do not mutate internal I/O ownership, store raw promise pointers in external owners, or treat task-level cancellation as operation completion. |
coro::promise_base::affinity(), set_affinity(), clear_affinity()
|
Store and report caller-requested affinity through the shared execution context. Effective affinity is an active I/O owner first, then caller affinity. Affinity changes made while I/O is pending take effect only after the backend reaches a terminal completion. | Treat these methods as coroutine-runtime integration points, not as synchronization or I/O cancellation APIs. Use valid worker IDs for deterministic caller placement. |
time::sleep_for() |
Wakes after the requested duration or token cancellation for cancellable overloads. If backend timer preparation fails, Elio uses the scheduler blocking pool without moving the continuation off its scheduler; if that pool is unavailable, the await resumes on its current worker and throws std::runtime_error. |
Pass a token if cancellation is required. Do not rely on exact wakeup time under scheduler load. Keep the scheduler blocking pool available while fallback may be needed, or handle rejection exceptions. |
time::sleep_until() |
Wakes at or after the requested time point. It has the same backend-fallback and blocking-pool rejection behavior as sleep_for(). |
Use a clock/source appropriate for the application deadline and handle fallback rejection when the blocking pool can be shut down independently. |
time::yield() |
Reschedules the current coroutine according to scheduler policy. | Use it to cooperate, not to enforce ordering with other tasks. |
| Interface | Elio guarantees | Caller must guarantee |
|---|---|---|
elio::serve() |
Runs a server with configured shutdown signals and deadlines, then stops accepting new work as documented. | Choose signal sets and shutdown deadlines suitable for the process. Ensure application handlers observe shutdown and release resources. |
elio::serve_all() |
Coordinates multiple serve targets under the documented shared shutdown policy. | Ensure each served object remains alive for the full serve call and can tolerate the shared shutdown behavior. |
elio::wait_shutdown_signal() |
Waits for configured shutdown signals through the signal integration path. | Block/process signals consistently across the application and third-party libraries. |
signal::signal_set |
Stores a set of signal numbers and exposes membership/mask accessors. | Use valid signal numbers and coordinate process-wide signal mask policy. |
signal::signal_set::block_error(), block(), unblock_error(), unblock(), set_mask_error(), set_mask(), block_all_threads_error(), block_all_threads()
|
Apply the stored mask to the calling thread and report the direct pthread error code or boolean success according to the overload. | Account for thread-local and inherited signal-mask effects. Call block_all_threads() before creating worker threads when the goal is process-wide inherited blocking. |
signal::signal_fd |
Integrates Linux signalfd with coroutine waits, binds to its construction-time io_context, and returns observed signal information. Standard waits validate that scheduler-owned context before submission. |
Block the same signals in threads that should route them through signalfd. Keep the object alive while waits are pending. Construct and await it on the same scheduler worker, or drive its standalone context yourself. |
signal::signal_info |
Reports decoded signal metadata from signalfd. |
Treat it as event data; application shutdown policy remains caller-owned. |
signal::signal_block_guard |
Restores the previous signal mask when destroyed according to RAII semantics. | Keep guard lifetime aligned with the critical section that needs the mask. |
signal::wait_signal() |
Creates a temporary signal_fd, waits for one matching signal, and returns signal_info or throws on read failure. |
Keep the chosen io_context alive and explicitly unblock signals later if automatic blocking is used. |
signal::signal_name() and signal::signal_number()
|
Convert between supported signal numbers and conventional short names. | Handle null/unknown conversion results; do not use names as a portable policy boundary across platforms. |
Worker/backend ownership and object-level concurrency are separate contracts. Elio prevents a continuation with pending worker-local I/O from migrating away from the backend owner. It does not serialize operations on a stream, listener, fd, or protocol object. Unless a more specific type documents otherwise, callers must prevent overlapping reads, overlapping writes, close-versus-I/O races, and other conflicting mutable access. Backend acceptance of multiple requests does not make their higher-level ordering or object lifetime safe.
| Interface | Elio guarantees | Caller must guarantee |
|---|---|---|
io::io_context |
Owns an I/O backend and exposes stable owner/generation diagnostics. Mutating operations (prepare, submit, poll, and cancel) reject access outside the exact scheduler owner thread by throwing std::logic_error; notify() is the non-throwing cross-thread wakeup entry. A submitted operation pins an Elio task continuation to that owner until normal completion, cancellation completion, prepare failure, or orphan cleanup. All standard awaitables retain context-level drain accounting, including when awaited by a non-Elio coroutine promise. Resize drain keeps polling while backend work or operation pins remain. The legacy static get_last_result() reports the most recent completion published by either built-in backend on the calling thread. |
Keep the context, file descriptors, request storage, and buffers valid until completion unless ownership transfer is documented. Drive and serialize a standalone context yourself, and do not mutate it from a scheduler worker. Custom coroutine runtimes that independently re-enqueue a suspended handle must preserve the owner worker while its I/O is pending. Read get_last_result() from the resumed completion path before another context on the same thread publishes a newer result. |
io::io_result |
Carries kernel-style result values and error information without hiding partial progress. | Check negative results before using counts. Treat zero/EOF according to the specific operation. |
io::async_read() and io::async_write()
|
Submit one positional or current-offset read/write request through the active backend and return the kernel-style completion. | Keep the fd and buffer alive until completion. Handle short transfers, EOF, and negative errno results. Serialize current-offset operations when file-position ordering matters. |
io::async_readv() and io::async_writev()
|
Submit one scatter-gather read/write request and report actual transfer or errno. | Keep the iovec array and every pointed-to segment alive until completion. Advance/retry iovecs when a complete logical message is required. |
io::async_recv() and io::async_send()
|
Submit one socket receive/send request and report actual transfer or errno. Socket sends suppress process-level SIGPIPE where the platform provides per-call suppression. Cancellable overloads honor the provided token at the documented wait points. |
Keep the socket fd and buffer alive until completion. Treat short socket I/O and zero-length peer close according to protocol needs. |
io::async_sendmsg() |
Submits one socket scatter-gather send over the supplied iovec array and reports actual transfer or errno. It is not a general sendmsg(2) wrapper for destination addresses or ancillary/control data. It suppresses process-level SIGPIPE where the platform provides per-call suppression. |
Keep the socket fd, iovec array, and referenced buffers alive until completion. Handle short socket writes, transient readiness errors, and protocol-level retry/advance logic. |
io::async_accept() |
Submits one accept operation and returns the accepted fd in io_result::result on success. |
Keep the listening fd, optional address storage, and optional socklen_t storage alive until completion. Close or wrap the accepted fd on every success path. |
io::async_connect() |
Submits one connect operation for the supplied fd and sockaddr. Cancellable overloads honor the provided token at the documented wait points. The epoll backend rejects a blocking socket with -EINVAL before calling connect(2) so a scheduler worker cannot block. |
Keep the fd and sockaddr storage valid until completion. When epoll may be selected, set O_NONBLOCK before submission and do not clear it until completion. Check the result before using the socket as connected. |
io::async_close() |
Submits fd close through the backend where supported and reports the close result. | Do not reuse or close the same fd concurrently through another path. Treat close ordering with in-flight operations as caller-owned unless a higher-level wrapper documents safe teardown. |
io::async_poll_read() and io::async_poll_write()
|
Wait for readiness according to the active backend and return readiness/error status. Cancellable overloads honor the provided token. | Keep the fd alive while polling and re-check the actual operation result after readiness. |
io::batch_read_segment and io::batch_write_segment
|
Describe per-segment file offsets, buffers, and lengths for batch helpers. | Ensure segment buffers remain valid and that overlapping output regions are intentional and externally synchronized. |
io::batch_read() and io::batch_write()
|
Copy segment descriptors at awaitable construction, submit supported file segments, and return one result per segment in input order. Current-position segments are executed in order. | Interpret partial success per segment; do not assume the batch is atomic as a group. Keep the buffers referenced by each copied segment alive until completion. |
io::read_file() |
Opens and reads a file in chunks, returning accumulated bytes on EOF or after later read failure, or std::nullopt when open/read fails before any bytes are produced. |
Validate path trust, maximum expected size, permissions, and TOCTOU policy. Treat an engaged result as file bytes read, not as an integrity guarantee that the file was stable or complete. |
io::write_file() and io::append_file()
|
Open/create the target and write data in chunks, returning boolean success. write_file() truncates; append_file() uses append semantics. |
Choose overwrite/append policy deliberately. Ensure path ownership, permissions, symlink policy, and data durability requirements outside the helper. |
io::file_exists(), io::file_size(), and io::read_dir()
|
Query filesystem metadata or directory entries and report absence/errors through boolean or optional results. | Treat results as snapshots that can race with later filesystem changes. Validate path trust and authorization in application code. |
io::fd_guard |
Closes an owned fd on destruction unless released. | Do not let another owner close the same fd. Release only when ownership has been transferred. |
net::ipv4_address, net::ipv6_address, net::socket_address
|
Represent IPv4, IPv6, or generic socket address/port values and convert between supported forms. Numeric-literal constructors log invalid text and fall back to an any-address value. | Pass syntactically valid numeric literals or pre-validate/resolve host strings when fallback-to-any is not acceptable. Choose address family and bind/connect policy appropriate for the deployment. |
net::resolve_cache, resolve_cache_key, resolve_cache_entry, and resolve_cache_stats
|
Store positive and negative DNS lookup results with TTLs and expose cache statistics/invalidations. | Choose cache lifetime, invalidation, and sharing policy. Do not treat cached DNS results as authorization decisions. |
net::resolve_options, default_resolve_cache(), and default_cached_resolve_options()
|
Configure whether resolver helpers use caller-provided or default cache state. | Keep any custom cache alive while resolver operations use it. Choose positive and negative TTLs appropriate for the deployment. |
net::try_parse_ipv4_literal() and net::try_parse_ipv6_literal()
|
Parse numeric address literals and append representable addresses to the output vector. | Treat a false result as parse failure and manage errno/output vector state according to the helper contract. |
net::resolve_all() and net::resolve_hostname()
|
Resolve host/port pairs to supported socket addresses, using literal parsing, optional cache, and blocking DNS offload as documented. Empty results set errno for lookup failure. |
Decide address ordering, retries, family preference, failover policy, DNS trust, and cache invalidation. Keep host string data valid for the call. |
net::tcp_listener |
Binds/listens with supplied options and accepts connections asynchronously. Closing the listener stops future accepts as documented. | Choose bind address, backlog, reuse options, and permissions appropriate for deployment. Keep listener alive while accepts are pending. |
net::tcp_stream |
read() and write() perform one readiness-aware operation and return actual byte count or error. Transient readiness for these base calls is handled inside the awaitable path. Socket writes suppress process-level SIGPIPE where the platform provides per-call suppression. One read-side operation and one write-side operation may overlap. |
Treat positive short reads/writes as normal stream behavior. Loop or use exact-length helpers when a full protocol message must be transferred. Keep buffers valid until completion. Externally serialize multiple readers, multiple writers, and close/destruction against active I/O. |
tcp_stream::read_exactly() |
Continues reading until the requested byte count, EOF, cancellation, or error. | Use it only when exactly that many bytes are required. Keep destination buffers valid for the full operation. |
tcp_stream::write_exactly() |
Continues writing until all requested bytes are sent, cancellation occurs, or an error is returned. | Use it for full message writes. Keep source buffers valid for the full operation and handle partial-progress errors. |
tcp_stream::writev() |
Submits one scatter-gather socket write operation and reports the backend result, including positive short writes or transient readiness errors. Socket scatter-gather writes suppress process-level SIGPIPE where the platform provides per-call suppression. |
Keep the iovec array and referenced data valid until completion. Handle EAGAIN/EWOULDBLOCK, polling, retry, and iovec advancement when a complete logical message is required. |
net::tcp_connect() |
Creates/connects a TCP socket for the supplied address and reports connection failure through std::nullopt with errno or awaited operation status. |
Choose destination, source/network policy, and timeout/cancellation strategy. Check the optional result before using the stream. |
net::unix_address |
Represents filesystem or Linux abstract Unix-domain socket addresses. to_sockaddr() enforces sockaddr_un::sun_path capacity and rejects overlong addresses with std::invalid_argument before any bind/connect syscall is attempted. |
Choose socket path/namespace, filesystem permissions, abstract-socket naming, and cleanup policy. Keep filesystem paths and abstract names within sockaddr_un::sun_path capacity before binding or connecting. |
net::uds_listener |
Binds/listens/accepts Unix-domain sockets asynchronously. Socket creation failures, and bind/listen failures after address conversion succeeds, are reported as std::nullopt with errno set. |
Keep path ownership and unlink behavior under application control. Keep the listener alive while accepts are pending. Treat overlong unix_address values as caller precondition failures, not socket syscall failures. |
net::uds_connect() |
Converts the supplied UDS address, attempts the connection, and reports socket/connect failures as std::nullopt with errno set from the failing operation. Cancellable overloads honor the supplied token at the connect wait. |
Ensure the address meets unix_address length rules and represents an intended filesystem or abstract namespace target. Check the optional result before use. Pass a token when the connection attempt must stop on caller cancellation. |
net::uds_stream |
Provides stream I/O semantics matching TCP stream base/exact helpers over Unix-domain sockets, including cancellation-aware read/write helpers and per-call SIGPIPE suppression where supported for socket writes. One read-side operation and one write-side operation may overlap. |
Apply the same short I/O, cancellation, buffer-lifetime, and external serialization rules as TCP streams. |
net::stream concept/helpers |
Expose generic stream requirements for APIs that accept stream-like types. | Provide streams that satisfy the expected read/write/close contract for the consuming API. |
io::io_op, io::io_request, and io::io_backend
|
Define the low-level backend request/result contract used by concrete I/O backends. io_context does not expose mutable raw backend access. |
Treat direct backend instances as standalone backend integration interfaces. Serialize and drive them yourself, and keep request-owned buffers, addresses, and op state alive according to the backend contract. |
io::io_uring_backend and io::epoll_backend
|
Normalize supported backend completions into Elio awaitable results and release operation ownership before resuming the continuation. | Select a backend supported by the kernel and deployment. Do not bypass owner-thread rules or infer stream/fd concurrency safety from backend queue acceptance. |
| Interface | Elio guarantees | Caller must guarantee |
|---|---|---|
tls::tls_context |
Configures OpenSSL context state, certificates, keys, ALPN, ciphers, protocol versions, and verification mode according to return values. | Keep the context alive while streams/listeners use it. Load trusted CA paths, certificates, and private keys appropriate for deployment. |
tls::tls_stream |
Performs handshake, encrypted reads/writes, exact-length helpers, peer certificate access, and bounded close-notify shutdown according to its API. After the TLS handshake completes, direct OpenSSL SSL* state access is serialized internally, so one read-side operation and one write-side operation may overlap while suspended on socket readiness. |
Serialize handshake-starting operations, multiple concurrent readers, multiple concurrent writers, and shutdown/destruction against active I/O according to the higher-level protocol. Keep plaintext buffers valid until operations finish. Call shutdown() when close-notify semantics matter. |
tls_connect() |
Resolves/connects TCP, applies SNI, performs TLS handshake, and reports failure according to result type. | Provide hostname, port, context, and resolver policy appropriate for the peer. Check the returned stream/result before use. |
tls_listener |
Accepts TCP connections and performs server-side TLS handshake before returning streams. | Keep tls_context and listener alive while accepts are pending. Configure certificates and verification policy explicitly. |
| Certificate verification settings | Applies OpenSSL verification mode and reports verification errors through the documented path. | Disable verification only for controlled tests. Hostname, trust-store, key rotation, and certificate policy belong to the application/deployment. |
| Interface | Elio guarantees | Caller must guarantee |
|---|---|---|
http::url |
Parses and exposes supported URL components according to HTTP client rules. | Validate application-specific scheme, host, path, query, and credential policy. |
http::headers |
Stores header fields and provides documented lookup/serialization behavior. | Do not rely on it for application authorization or semantic validation. Avoid adding invalid or unsafe header names/values. |
http::request |
Represents parsed or constructed HTTP requests and preserves method, target, headers, and body fields. | Validate routes, methods, authorization, content type, and body schema in application code. |
http::response |
Represents and serializes status, headers, and body framing generated through Elio APIs. | Choose status, redirects, cache headers, and payload content safely. Do not expose secrets through response fields. |
http::method, method_to_string(), and string_to_method()
|
Provide supported method enum values and exact token conversion. | Handle std::nullopt for unknown methods and apply application method policy before dispatch. |
http::status and status_reason()
|
Provide supported status values and reason strings. Response serialization omits bodies for status/method combinations that HTTP forbids. | Choose statuses appropriate to the application and do not treat reason strings or serialization rules as authorization or cache policy. |
http::headers, http::url, http::request, and http::response mutators/serializers |
Reject or fail to parse syntax that Elio's public HTTP message types cannot safely represent or serialize. Throwing setters report invalid caller-supplied values through std::invalid_argument. |
Validate application-specific semantics separately. Do not pass unchecked external strings into constructors, setters, or serializers that document strict syntax. |
http::request_parser, http::response_parser, parse_state, and parse_result
|
Validate request/response line grammar, headers, transfer encoding, body framing, and configured byte limits. | Feed bytes in order and respect terminal parser error states. Raw parser use does not replace application policy checks. |
http::server_config |
Applies configured request size, header, body, keep-alive, timeout, and session limits at the documented layer. max_request_size caps aggregate HTTP request bytes for line, headers, and body; WebSocket frame bytes after a completed upgrade are outside that HTTP cap. |
Choose limits that match deployment risk and expected traffic. A disabled or unlimited setting is caller policy. |
http::router, http::route, and handler registration |
Match routes according to documented literal, parameter, and wildcard rules before invoking handlers. | Register only intended routes. Avoid ambiguous application routing and validate authorization/business rules in handlers. |
http::server and make_server()
|
Accept connections, parse malformed HTTP fail-closed before handler dispatch, and run handlers according to server config. | Keep router, TLS context, handler captures, and scheduler alive for spawned handlers. Treat handler input as syntactically parsed HTTP, not trusted application data. |
http::client |
Performs connection setup, optional TLS, request serialization, response parsing, redirect behavior, and timeout handling according to config. | Check response status and errors. Decide retries, authentication, idempotency, redirect trust, and payload validation. |
http::base_client_config |
Defines shared timeout, size, and behavior settings for client operations. | Set values appropriate for target endpoints and threat model. |
http::client_config |
Extends base client settings with HTTP/1.1 client-specific options. | Keep configured defaults aligned with application retry/redirect/security policy. |
| Interface | Elio guarantees | Caller must guarantee |
|---|---|---|
http::h2_client |
Negotiates TLS/ALPN where configured, initializes nghttp2 session state, validates frames through nghttp2, and reports response or error results. | Avoid concurrent use of one high-level client unless a future API documents shared-session multiplexing. Use separate clients for parallel application work. |
http::h2_get() and http::h2_post()
|
Create a default HTTP/2 client request path and return an optional response according to client failure semantics. | Treat them as convenience calls without application retry/authentication policy. Use explicit clients/configs when limits, deadlines, or certificates matter. |
http::h2_client_config |
Applies configured connect/read deadlines, per-stream response body/header limits, and HTTP/2 settings where supported. Header count and name/value-byte limits cover final headers plus trailers; discarded informational blocks reset accounting. | Choose finite limits/settings that match peer behavior and workload. |
http::h2_session |
Encapsulates nghttp2 session interaction and translates protocol validation to Elio result paths. A response-header limit breach rejects before copying, resets only the offending stream with ENHANCE_YOUR_CALM, and reports EMSGSIZE. |
Treat direct session use as lower-level than h2_client; preserve stream/session ownership and callback lifetimes. Configure both response-header limits when overriding session defaults. |
| nghttp2 package integration | Uses the configured bundled or system nghttp2 provider for HTTP/2 protocol handling. | Provide the dependency through the documented source, package, or install mode. Handle provider-specific deployment constraints. |
Names below use the convenience re-exports from <elio/http/websocket.hpp> and
<elio/http/sse.hpp>. The concrete declarations live under
elio::http::websocket and elio::http::sse.
| Interface | Elio guarantees | Caller must guarantee |
|---|---|---|
WebSocket handshake builders and validators such as build_client_handshake(), build_server_handshake(), build_rejection_response(), is_websocket_upgrade(), validate_upgrade_request(), and build_upgrade_response()
|
Build or validate the specific handshake strings/responses named by the helper, including syntactic header checks where the helper documents them. | Register intended routes/subprotocols and validate origin, authorization, session identity, and application policy. Do not assume pure builders perform network I/O, deadlines, or connection lifecycle management. |
websocket::ws_connect() and ws_client::connect()
|
Perform the client connection and upgrade path, applying configured connect/handshake deadlines and returning an optional/client state result according to failure semantics. | Choose reconnect, authentication, origin, TLS, and replay policy; check the result before sending application messages. |
websocket::opcode, close_code, frame_header, frame encode helpers, is_valid_close_code(), and parse_close_payload()
|
Encode/decode WebSocket framing metadata and report invalid opcodes, close codes, and payload rules according to helper result types. | Choose endpoint role and masking policy correctly. Validate application message schema after protocol parsing. |
websocket::frame_parser and parse_frame_header()
|
Validate opcodes, reserved bits, control-frame rules, fragmentation, payload length, UTF-8 requirements where enforced, and frame header payload rules. frame_parser applies a 16 MiB aggregate message limit by default and validates masking direction after the caller configures an endpoint role. |
Feed bytes in order, configure server or client role when masking direction matters, choose an application-specific limit with set_max_message_size(), pass close payloads through parse_close_payload() when close-code semantics matter, and respect parser terminal error states. Setting the limit to 0 explicitly opts into unbounded messages. |
websocket::ws_connection |
Server-side send_text(), send_binary(), send_ping(), send_pong(), heartbeat ping, close-response, and auto-pong writes are serialized so frames from multiple senders do not interleave on the wire. Receive/close follow documented state transitions, and pongs observed by receive() satisfy the configured server heartbeat. A heartbeat with timeout enabled fails closed if the ping cannot be sent within the timeout window or no pong is observed before the window expires. |
Keep the connection object alive while operations run. Use only one active receive loop per connection. Stop sending after close/error results and validate payload meaning in handlers. |
websocket::ws_router and websocket::ws_server
|
Upgrade matching routes into WebSocket handlers, enforce route pattern rules, apply WebSocket message/read-buffer limits, and start the configured per-route server heartbeat after a successful upgrade. | Keep handler captures and TLS contexts alive for spawned handlers, run the route receive loop when heartbeat pongs must be observed, authorize connections, and decide application close/retry policy. |
websocket::ws_client |
connect(), receive(), send_text(), send_binary(), control-send helpers, and close() maintain client protocol state, reset parser state for new connection attempts, and fail closed on invalid peer frames. |
Serialize use of one client unless documented safe. Reconnect policy, backoff, idempotency, and replay of application messages belong to the caller. |
sse::event and serialize_event()
|
Preserve and serialize SSE event type, id, retry, and data fields according to SSE syntax. | Interpret event semantics, durable ordering, persistence, and payload schema in application code. |
sse::build_sse_response() |
Builds HTTP response headers suitable for an SSE stream. | Authorize the request, keep the stream open, and manage event production separately from the header helper. |
sse::sse_connection |
Serializes events, comments, retry fields, and simple data messages into SSE wire format and serializes concurrent sends where documented. | Decide event names, ids, retry values, authorization, and payload schema. Stop producing when the connection is inactive. |
sse::sse_endpoint |
Stores the caller-provided SSE handler for use with HTTP routing integration. | Keep handler captures/resources alive and enforce authorization before streaming. The endpoint object does not own connection lifecycle by itself. |
sse::sse_client |
Parses SSE response headers and event stream syntax, enforces configured event-buffer limits, tracks Last-Event-ID, applies configured connect and response-header read deadlines, and performs configured receive-driven reconnect/backoff after an established stream fails while not closed. |
Decide whether to enable reconnect and how many attempts to allow. Retry initial connect() failures, duplicate handling, replay/idempotency, persistence across process restarts, and application event validation remain caller-owned. |
sse::sse_connect() |
Performs the configured SSE client connect path and returns a client object or empty result according to failure semantics. | Choose retry policy for initial connection failures and configure credentials, deadlines, and limits deliberately. |
| Interface | Elio guarantees | Caller must guarantee |
|---|---|---|
rpc::buffer_view |
Represents a non-owning byte view. | Keep backing storage alive and unchanged for the duration of any operation that reads it. |
rpc::buffer_writer |
Appends serialized bytes and reports allocation/size behavior through normal C++ container semantics. | Do not share a mutable writer across threads or coroutines unless externally synchronized. |
rpc::buffer_ref |
Represents a non-owning external byte reference. Deserialization can expose received payload bytes without copying; current serialization copies referenced bytes into the outgoing writer. | Keep referenced storage valid until the operation that reads or copies it has completed. Use cleanup callback registration, not buffer_ref itself, for deferred external ownership release. |
rpc::iovec_buffer |
Builds scatter-gather buffers for frame writes according to the writer contract. | Keep all referenced segments valid until the write operation completes. |
RPC CRC32 helpers such as crc32(), frame checksum, and iovec checksum functions |
Compute non-cryptographic checksums over frames or iovec data. | Use CRC32 only for accidental corruption detection or protocol compatibility, not authentication. |
| RPC serialization functions and serializers | Serialize/deserialize supported types and ELIO_RPC_FIELDS in declared order. |
Use compatible schemas on both sides and enforce application-level versioning and validation. |
ELIO_RPC_FIELDS and schema macros |
Declare field order for generated serialization helpers. | Keep declarations stable for wire compatibility or version schemas deliberately. |
rpc::frame_header |
Represents validated frame metadata after parsing or builder construction. | Do not trust unparsed bytes as a header. Check parser/builder results before dispatch. |
rpc::message_type, message_flags, rpc_error
|
Provide protocol enum values and error reporting surface. | Handle unknown or unsupported values according to caller protocol policy. |
| RPC request, response, error, one-way, and keepalive message builders | Build frames with documented flags, payload length, and checksum handling. | Provide payloads and flags that match the method schema and peer capabilities. |
| RPC frame parser functions | Validate frame type, flags, payload length, checksum presence, and configured max message size before dispatching frames. | Configure max message size and close peers that violate application policy. Do not treat CRC32 as security. |
rpc::rpc_context |
Exposes request context and response helpers to handlers. | Keep handler-captured resources valid and enforce authorization/business invariants in handlers. |
rpc::cleanup_callback_t |
Runs cleanup at the documented post-send or post-serialization point for methods registered with cleanup support. | Make cleanup idempotent or safe for the documented call path. Do not assume it runs as a failure-path finalizer. |
rpc::rpc_server_config |
Applies session, per-session in-flight request, message-size, timeout, and checksum settings according to server behavior. | Choose bounds and overload policy appropriate for exposed services, handler cost, downstream pools, and expected payloads. |
rpc::rpc_server<Stream> |
Dispatches registered handlers for valid method frames and enforces configured session, per-session in-flight request, and timeout limits. Each session structurally owns accepted request, pong, and overload-response tasks. Closing or cancelling the handle_client() owner requests both explicit rpc_context cancellation and runtime task cancellation, wakes pending frame reads, cancels pending response writes/lock waits, and joins accepted children before releasing the session slot. Shared bookkeeping remains valid if the server facade is released after its stopped serve() call returns while accepted handlers drain. |
Keep the server facade alive until every active serve() and handle_client() call has returned. Assign stable unique method IDs, maintain schema compatibility, validate caller identity/authorization, and keep handler captures alive. Pass rpc_context::cancel_token or this_coro::cancel_token() into waits that must stop on disconnect. Cancellation is cooperative; work that ignores both tokens can delay session teardown and slot release. |
rpc::rpc_client_config |
Applies client timeout, checksum, and message-size settings to calls. | Set timeouts and size caps for workload and threat model. |
rpc::rpc_client<Stream> |
Correlates concurrent calls by request ID, reports timeouts through rpc_result, and prevents stale timed-out responses from matching unrelated future calls. |
Keep the client alive for outstanding calls. Check rpc_result::ok() before reading values. Bound total in-flight calls according to application resource policy. |
rpc::rpc_result<T> |
Carries value or error state for RPC calls. | Check success/error state before accessing the value. |
| RPC type traits and method traits | Detect supported message, serialization, and method shapes at compile time. | Keep custom types within supported trait/schema rules. |
| Interface | Elio guarantees | Caller must guarantee |
|---|---|---|
sync::mutex |
lock(token) returns cancel_result and atomically resolves notification against cancellation. Cancellation that wins does not acquire the lock; notification that wins returns completed with ownership. lock() remains non-cancellable with a void await result. |
Check the token-aware result before entering the critical section. Do not destroy the mutex while waiters can still reference it. Release the lock after every completed acquisition, including when cancellation is requested immediately afterward. |
sync::shared_mutex |
lock_shared(token) and lock(token) return cancel_result and atomically resolve cancellation against reader/writer admission. A cancellation winner owns no lock; completed owns the requested shared or exclusive lock. The no-token overloads retain void await results. |
Check the token-aware result before entering a read or write critical section. Match lock mode to the protected invariant, release every completed acquisition, and avoid upgrades/downgrades unless an API documents them. Keep the object alive while waiters exist. |
sync::shared_lock_guard |
Releases an already-held shared lock on destruction or explicit unlock(). |
Acquire the shared lock before constructing the guard. Keep the referenced shared mutex alive for the guard lifetime. |
sync::unique_lock_guard |
Releases an already-held exclusive lock on destruction or explicit unlock(). |
Acquire the exclusive lock before constructing the guard. Keep the referenced shared mutex alive for the guard lifetime and avoid suspending in unsafe critical sections. |
sync::semaphore |
acquire(token) returns cancel_result and atomically resolves permit handoff against cancellation. A cancellation winner does not consume a permit; a completed acquisition does. acquire() remains non-cancellable with a void await result. |
Check the token-aware result before using a permit. Release only permits that match the intended concurrency invariant. Keep the semaphore alive while waiters exist. Treat completed as ownership even if cancellation is requested concurrently. |
sync::event |
wait(token) returns cancel_result and atomically resolves set() against cancellation. wait() remains non-cancellable with a void await result. The event state itself is not rolled back by cancellation. |
Check the token-aware result before assuming the event was observed. Keep waited objects/captures alive until the waiter resumes or is destroyed. Handle either result when set() races cancellation. |
sync::condition_variable |
Token-aware wait, generic-lock wait, and wait_unlocked overloads return cancel_result and atomically resolve notification against cancellation. A pre-cancelled lock-based wait leaves the held lock untouched. If waiting released an associated lock, Elio re-acquires it before returning either result. |
Check the result before treating the predicate as notified. Protect predicates with the correct lock and re-check them after completed; decide explicitly whether cancelled exits the predicate loop. Keep the CV and associated lock alive while waiters exist. |
sync::channel<T> |
Token-aware send and recv return result objects containing both the existing operation result and cancel_result. Cancellation that wins before transfer does not transfer a pending send value into the channel or consume a receive value. Normal send, receive, or close completion can win the race and preserves rendezvous, buffering, and drain-on-close semantics. No-token overloads retain their existing boolean and optional results. |
Inspect was_cancelled() before interpreting sent == false or an empty receive as channel closure. Treat a completed send as transferred and a completed receive value as consumed even if cancellation is requested immediately afterward. Keep the channel and pending values alive until the operation resumes or is destroyed. |
sync::object_cache |
Coalesces construction per key, returns move-only borrows with reference-counted lifetime tracking, and applies TTL/eviction/reclaim behavior by config. | Keep constructor callables and captures valid while construction runs. Release borrows promptly and treat cached object state/eviction as application policy. |
sync::spinlock |
Provides a thread-blocking atomic lock for short critical sections. | Do not hold it across co_await or long-running work. Prefer coroutine-aware primitives for suspending code. |
sync::spinlock_guard |
Releases the spinlock on guard destruction. | Keep the spinlock alive for the guard lifetime and keep the critical section short. |
runtime::chase_lev_deque<T> |
Provides the scheduler's owner-push/pop and thief-steal work-queue behavior with documented memory-ordering guarantees. | Use owner-only and thief-only operations according to the Chase-Lev role contract. Do not use it as a general application queue unless you preserve those roles. |
sync::LockfreeMPMCRing<T> |
Provides bounded MPMC try_push()/try_pop() operations and approximate diagnostic size/empty queries. |
Use only nothrow-movable element types. Treat size()/empty() as approximate under contention and keep element ownership rules explicit. |
| Interface | Elio guarantees | Caller must guarantee |
|---|---|---|
hash::crc32(), crc32_iovec(), crc32_update(), and crc32_finalize()
|
Compute the documented CRC32 value over supplied bytes and scatter-gather inputs. | Use CRC32 only for accidental error detection or compatibility, not as a security boundary. Keep inputs valid for the call. |
hash::crc32c() |
Computes the documented CRC32C value where available, with the documented software/hardware dispatch behavior. | Use it only for protocols that require CRC32C or non-cryptographic checks. Keep inputs valid for the call. |
hash::sha1_context, sha1(), and sha1_hex()
|
Compute SHA-1 over supplied or incremental input. | Do not use SHA-1 for new collision-resistant security designs. Keep input spans valid. |
hash::sha256_context, sha256(), and sha256_hex()
|
Compute SHA-256 over supplied or incremental input. | Choose SHA-256 only when a hash, not authentication or encryption, satisfies the security goal. Keep input spans valid. |
hash::to_hex() |
Converts digest bytes or raw bytes to documented textual forms. | Treat output formatting as representation only; compare/authenticate according to application security requirements. |
| Interface | Elio guarantees | Caller must guarantee |
|---|---|---|
rdma::backend_traits |
Defines the backend posting contract and normalizes synchronous post failures into awaiter result paths. | Backend post_* methods must be noexcept, follow the return convention, and keep QP/CQ/backend objects alive while operations can complete. |
rdma::polymorphic_backend |
Routes operation posts through runtime-dispatched backend functions according to the same backend contract. | Keep backend implementation and user data alive for outstanding operations. |
rdma::buffer_view and remote_buffer
|
Represent local and remote memory ranges used by RDMA operations. | Keep local memory registered/alive, ensure remote address/rkey/access rights are valid, and respect 32-bit length preconditions where documented. |
rdma::sge arrays |
Describe scatter-gather entries for verbs-adjacent operations. | Keep SGE arrays and all pointed-to payload buffers alive until hardware completion. Split oversized buffers into valid SGEs. |
RDMA operation awaiters (connection data-path and SRQ receive operations) |
Use the shared op_state lifecycle and do not provide token-aware cancellation. A pending/posted operation can be orphaned safely before delivery wins. A completed eager .start() operation with no waiter can be discarded safely. Once delivery wins pending → completed for a suspended operation, the waiter handle has been snapshotted and cannot be proven revocable. |
Keep resources alive until completion delivery. Once delivery wins for a suspended operation, keep its coroutine frame alive until await_resume consumes the result and clears the handle; do not force-destroy it even if scheduler routing does not enqueue the snapshot. |
rdma::connection<Backend>::send/recv |
Posts send/receive work requests and reports completions or synchronous post failures through awaiter results. | Keep connection/backend and buffers alive until completion. Post receives according to peer protocol needs. |
rdma::connection<Backend>::rdma_write/rdma_read |
Posts RDMA read/write operations and fail-fast checks documented high-level length preconditions. | Ensure remote keys, addresses, access permissions, and local buffer registration are valid until completion. |
rdma::connection<Backend>::cas/fetch_add |
Posts supported 8-byte atomic operations through backends that implement atomic traits. | Use aligned 8-byte local/remote buffers and valid atomic-capable remote access until completion. |
rdma::send_flags::inline_send with connection<Backend>::send(), send_with_imm(), rdma_write(), and rdma_write_with_imm()
|
Fail before posting when inline size or SGE preconditions are not satisfied at documented high-level entry points. | Configure inline thresholds that match hardware/provider capabilities. |
rdma::srq and SRQ receive helpers |
Post/receive through SRQ-capable backends and map failures to completion results. | Use only with backends and QPs configured for SRQ. Keep SRQ objects alive for outstanding receives. |
rdma::memory_region |
Registers/deregisters memory according to ownership contract. | Keep underlying memory and protection domain/context alive for the memory-region lifetime and for all operations using it. |
memory_region::view(), view(offset, sub_length), remote(), and remote(offset, sub_length)
|
Produce verbs-adjacent local/remote views. | Bounds and 32-bit sub-length preconditions are caller-owned where documented. |
rdma::dispatcher and rdma::cq_pump
|
Deliver completions to awaiting operations according to wr_id/op_state lifecycle rules. For a suspended operation, delivery snapshots its waiter before publishing pending → completed; forced frame destruction after that transition fails closed because safe revocation of the snapshot cannot be proven. |
Drive the dispatcher/CQ pump until all outstanding operations complete or are intentionally drained. After delivery wins for a suspended operation, do not force-destroy its coroutine before the result is consumed. |
rdma_cm::event_channel |
Wraps an RDMA-CM event channel/fd, exposes cancellable event waits, and requires acking consumed events. | Destroy derived cm_id objects before the channel. Ack every event exactly once according to the helper contract. |
rdma_cm::cm_id |
Owns one rdma_cm_id*, destroys attached QP/CQ resources through the RDMA-CM teardown path, and releases ownership only through release(). |
Do not use moved-from IDs. If release() is called, the caller owns eventual rdma_destroy_id and any attached QP teardown. |
rdma_cm::resolve() and complete_connect()
|
Drive client-side address/route resolve and final connect phases, returning cm_id/cm_status with normalized errors. |
Configure addresses, routes, port space, QP attributes, connection parameters, and teardown policy valid for the provider. Create the QP before complete_connect(). |
rdma_cm::cm_listener::accept() and rdma_cm::accept_connect()
|
Consume connect requests for the listener and complete server-side accept after caller-created QP setup. | Keep listener/channel alive, create the QP on the returned ID, and choose connection parameters/security policy before accepting. |
rdma_ibverbs::endpoint and ibverbs_backend
|
Provide a reference provider-backed endpoint/backend path when enabled. endpoint::shutdown() cancels and asynchronously joins its CQ pump before releasing the QP, CQ, completion channel, and PD. Starting shutdown makes the endpoint terminal: data-path accessors and pump start reject further use, while a serialized shutdown retry is allowed. Checked provider failures while releasing QP/CQ/channel/PD are reported and the failed resource plus its dependencies remain owned for that retry. abandon_outstanding() is a non-waiting terminal escape hatch for eager .start() operations that never installed a waiter: true confirms checked QP destruction before the remaining verbs resources are intentionally relinquished; false retains the QP and dependencies. It does not make suspended operation frames revocable. The destructor does not wait for the CQ pump; an active pump or QP-destruction failure causes teardown to fail closed by relinquishing the affected ownership graph. |
Deploy with compatible libibverbs/RDMA-Core provider, permissions, and device configuration. Ensure every posted operation and its awaiter has completed, destroy memory regions registered from the endpoint PD, serialize shutdown with endpoint use, keep the endpoint and the scheduler supplied to start_cq_pump() operational through co_await endpoint::shutdown(), and prefer that graceful path over destructor or forced-scheduler-shutdown fallback. If a fatal path cannot drain provider-owned eager .start() operations, call abandon_outstanding() while those never-awaited operation objects, MRs, and payload buffers are still alive; only a true result permits unwinding them. On false, keep all affected lifetimes intact, repair provider state through raw handles, and retry or terminate. Never use it to justify destroying a suspended operation frame; once delivery may have snapshotted a waiter, resume that coroutine and consume the result. |
rdma_cuda::gpu_buffer and gpu_memory_region
|
Expose CUDA-specific buffer and registration helpers when the feature is enabled. | Ensure CUDA context, device pointer validity, registration support, peer access, and driver/runtime compatibility. |
| Interface | Elio guarantees | Caller must guarantee |
|---|---|---|
| Logging macros | Format and dispatch log messages through the configured logger path. | Avoid logging secrets and keep format arguments valid for the call. |
log::logger |
Serializes writes according to the logger implementation and honors configured level. | Configure level/sinks for deployment and avoid relying on logging for synchronization. |
elio::version() and version macros |
Report the library version compiled into the headers. | Do not use version strings as feature detection when compile-time feature macros or CMake options are the real contract. |
| Virtual stack/debug helpers | Expose coroutine-frame metadata on a best-effort diagnostic basis. | Treat debug output as diagnostic data, not a stable application protocol or security boundary. |
elio-pstack, GDB, and LLDB helpers |
Interpret Elio debug metadata when available. | Use them for debugging only; handle missing symbols, optimized builds, and stale process state. |