Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@marnix
Last active November 1, 2021 21:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save marnix/25c19cf6ade4c42ef57ce3bd2900f52f to your computer and use it in GitHub Desktop.
Save marnix/25c19cf6ade4c42ef57ce3bd2900f52f to your computer and use it in GitHub Desktop.
Zig async semantics

Zig async semantics

by Marnix Klooster (https://github.com/marnix); license: public domain (attribution appreciated); status: probably-incorrect draft

(TODO: Update with Protty's feedback on gist revision 33 or 38 on Discord, https://discord.com/channels/605571803288698900/605572581046747136/794993176779292693 and subsequent discussion.)

(TODO: After I have a version that I'm at least a bit happy with, consider g-w1's suggestion of a pull request to https://github.com/ziglang/zig-spec/blob/disorganized-spec-chunks/spec/disorganized_facts_about_zig.md .)

How does async (and the related suspend/resume and await) work? Here is my attempt to describe this in a language specification kind of way.

Async functions

At compile type, every fn is categorized as being an async function or not. A function is async if its body contains a suspend statement or await expression, or a call to @frame(), or a (normal non-nosuspend) function call to an async function1.

A call to an async function can be marked with nosuspend. This promises the compiler that the async function will never suspend at runtime, and it will be treated as a function call to a non-async function.

Calling and resuming

async f(...) is only allowed on an async function f. Anonymous storage for a frame for f is allocated on the stack (so contained in the calling function's frame; so an async call does not push a new frame onto the stack). Then control is passed to that frame as with a normal function call, until the function suspends (or the function completes normally, and the return value is stored in the frame). The anonymous frame storage remains valid until the end of the block containing the async expression. Its contents are also returned (by value) by the async expression.

@Frame(f) is the type of a frame of function f, i.e., it is the type of the value returned by async f(...). Importantly, just like with an async call, the frame of an async function also contains the frame of each (normal non-nosuspend) function call to an async function. (So a call from an async function to an async function does not push a new frame onto the stack.)

resume takes a pointer to a frame, and passes control to the frame that it points to, until that function suspends again (or the function completes normally, and the return value is stored in the frame).

(A frame can be resumed using any copy of the frame contents, including using a pointer into the async call's anonymous storage, as created by @frame().)

Suspending and awaiting

suspend suspends the current async function (passing control back to the last resumer or else the async caller). The 'suspend block' is executed before passing back control, but the function can already be resumed while the suspend block is still being executed. The function resumes after the suspend statement and block.

@frame() returns a pointer to the current async function's frame. (It is usually called in a suspend block, and the result is used in resume.) [TODO: How does this interact with inline, which presumably merges multiple frames into one?]

await takes a frame (or anything that can be coerced to it), and then returns its return value if its function has completed, or otherwise it suspends the current async function (passing control back to the last resumer or else the async caller), and on resume repeats the same steps.

Footnotes

  1. Note that the Zig compiler internally desugars such calls to await async f(). Using that would make this specification simpler, but the current description helps me better in reading source code.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment