Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In Zig, how do you tell if a frame represents a fully executed function?

Tags:

zig

In Zig (currently using 0.7.1), suppose for some reason you don't have any good way to design code which always has exactly one resume for every suspend. Is there any supported way to detect at runtime that a given frame has or has not been executed to completion?

// overly simplistic example designed to illustrate the problem
pub fn main() void {
    var frame = async amain(2);
    resume frame;
    resume frame;

    // panic/UB -- resume async function which already returned
    // 
    // we would prefer to have some kind of check which could allow
    // us to detect at runtime that the following resumption is illegal
    resume frame;
}

fn amain(ubound: i32) void {
    var i: i32 = 0;
    while (i < ubound) : (i += 1) {
        suspend;
    }
}

If I log the raw bytes of those frame structs (which as far as I can tell are opaque and don't support field access? I'm a little new to Zig), then it seems pretty obvious that a portion of the frame is dedicated to marking whether it has returned:

[70, 3a, 23, 00, 00, 00, 00, 00, 02, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 02, 00, 00, 00, 00, 00, 00, 00]
[70, 3a, 23, 00, 00, 00, 00, 00, 02, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 02, 00, 00, 00, 01, 00, 00, 00]
[70, 3a, 23, 00, 00, 00, 00, 00, ff, ff, ff, ff, ff, ff, ff, ff, ff, ff, ff, ff, ff, ff, ff, ff, 02, 00, 00, 00, 02, 00, 00, 00]

Blindly reading that data seems a little reckless however, and I'd feel a lot more comfortable if I knew the struct layout were guaranteed or that there were some builtin way to uncover that information.

Edit::

In particular, the problem that I'm trying to solve is that when designing an event loop (e.g. when interfacing between JS and Zig/WASM) you seem to have to marry the implementation of an async function to the API of the event loop itself.

The built-in event loop, for example, has a yield() function precisely so that it can do the necessary bookkeeping to ensure that code has one resume per suspend, but as far as I can tell that's an unnecessary restriction since whether a frame has returned seems to be stored and readily accessible.

It's certainly possible that I'm misunderstanding the purpose of Zig's async/await, but I don't see any fundamental reason why a general purpose event loop capable of handling any async function (not just those adhering to a particular loop API) couldn't be written, but I'm struggling to see how that's possible without a little more runtime introspection than the docs indicate is available.

like image 603
Hans Musgrave Avatar asked Jan 31 '21 04:01

Hans Musgrave


1 Answers

As of April 2022 there's an open proposal for implementing this feature in the language. A workaround till then might still be manually reading the async frame header.

like image 82
Hans Musgrave Avatar answered Nov 07 '22 10:11

Hans Musgrave