Async Internals

This page explains how BoltFFI bridges Rust futures to target language async systems. You don’t need to understand this to use async functions, but it helps when debugging or optimizing async code.

The Polling Model

BoltFFI wraps each Rust future in a RustFuture<T> that exposes a C-compatible interface. The generated bindings use this interface to drive the future to completion. When you call an async function, the bindings create a future handle, poll it until ready, extract the result, and free the handle. The target language’s async runtime controls when polling happens, and BoltFFI uses continuation callbacks to signal when the future needs attention.

User CodeGenerated BindingsRust Scaffoldingcall async functioncall scaffolding functionreturn RustFuture handleloop[until RustFuture is ready]call RustFuture poll fncall future callbackcall RustFuture complete fnreturn resultcall RustFuture free fnreturn from async function

Generated FFI Functions

For each async function, BoltFFI generates five FFI functions:

  • entry - Creates the RustFuture and returns a handle
  • poll - Polls the future with a continuation callback
  • complete - Extracts the result once the future is ready
  • cancel - Marks the future as cancelled
  • free - Deallocates the future

The bindings call these in sequence: entry to create, poll in a loop until ready, complete to get the result, and free to clean up.

Continuation Callbacks

When the bindings call poll, they pass a continuation callback and a handle. If the future is not ready, BoltFFI stores this callback. When the future wakes (I/O completes, timer fires, etc.), BoltFFI invokes the stored callback, which tells the bindings to poll again. This avoids busy-waiting and lets the target language’s async runtime manage scheduling.

Lock-Free Implementation

The polling mechanism uses atomic operations for state management. A scheduler tracks whether a continuation is stored, whether the future has been waked, and whether it’s been cancelled. State transitions use compare-and-swap operations, so multiple threads can interact with the future without locks.

Cancellation

When the target language cancels an async operation, the bindings call the cancel function. This marks the future as cancelled and immediately invokes any stored continuation with a ready signal. The next call to complete will return a cancellation status. The Rust future itself is not forcibly aborted - cancellation is cooperative.