zig icon indicating copy to clipboard operation
zig copied to clipboard

Mutually recursive async functions disallowed even with dynamic frame allocation

Open pmwhite opened this issue 5 years ago • 1 comments

This program complains that amain depends on itself. Although this program is an infinite loop that constantly leaks memory, my understanding is that this is not an illegal zig program. I had a less bad program with the same error, but this one is shorter.

const std = @import("std");

async fn f() void {}

fn recurse() !void {
    const frame = try std.heap.direct_allocator.create(@Frame(amain));
    frame.* = async amain();
    try await frame;
}

pub fn amain() error{OutOfMemory}!void {
    var bytes = try std.heap.direct_allocator.alignedAlloc(u8, 16, 0);
    await @asyncCall(bytes, {}, f);
    try recurse();
}

pub fn main() anyerror!void {
    try amain();
}

pmwhite avatar Mar 31 '20 21:03 pmwhite

The problem seems to be the recursive reference to the @Frame(...) type. As a partial workaround for now, you can use @asyncCall in enough places to break any @Frame-type cycles in the callgraph, using @frameSize rather than anything looking like @sizeOf(@Frame(...)) (which allocator.create is doing internally), and then you just need a big enough alignment for your buffer.

I'm not sure if there's a user-space way to get something like an alignment counterpart to @frameSize though. I bet std.Target.stack_align will always suffice, but that's only a hunch.

hmusgrave avatar Nov 03 '22 15:11 hmusgrave