Skip to main content

Nosuspend

When calling a function which is determined to be async (i.e. it may suspend) without an async invocation, the function which called it is also treated as being async. When a function of a concrete (non-async) calling convention is determined to have suspend points, this is a compile error as async requires its own calling convention. This means, for example, that main cannot be async.

pub fn main() !void {
suspend {}
}

(compiled from windows)

C:\zig\lib\zig\std\start.zig:165:1: error: function with calling convention 'Stdcall' cannot be async
fn WinStartup() callconv(.Stdcall) noreturn {
^
C:\zig\lib\zig\std\start.zig:173:65: note: async function call here
std.os.windows.kernel32.ExitProcess(initEventLoopAndCallMain());
^
C:\zig\lib\zig\std\start.zig:276:12: note: async function call here
return @call(.{ .modifier = .always_inline }, callMain, .{});
^
C:\zig\lib\zig\std\start.zig:334:37: note: async function call here
const result = root.main() catch |err| {
^
.\main.zig:12:5: note: suspends here
suspend {}
^

If you want to call an async function without using an async invocation, and without the caller of the function also being async, the nosuspend keyword comes in handy. This allows the caller of the async function to not also be async, by asserting that the potential suspends do not happen.

const std = @import("std");

fn doTicksDuration(ticker: *u32) i64 {
const start = std.time.milliTimestamp();

while (ticker.* > 0) {
suspend {}
ticker.* -= 1;
}

return std.time.milliTimestamp() - start;
}

pub fn main() !void {
var ticker: u32 = 0;
const duration = nosuspend doTicksDuration(&ticker);
}

In the above code if we change the value of ticker to be above 0, this is detectable illegal behaviour. If we run that code, we will have an error like this in safe build modes. Similar to other illegal behaviours in Zig, having these happen in unsafe modes will result in undefined behaviour.

async function called in nosuspend scope suspended
.\main.zig:16:47: 0x7ff661dd3414 in main (main.obj)
const duration = nosuspend doTicksDuration(&ticker);
^
C:\zig\lib\zig\std\start.zig:173:65: 0x7ff661dd18ce in std.start.WinStartup (main.obj)
std.os.windows.kernel32.ExitProcess(initEventLoopAndCallMain());
^