11

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.

Hans Musgrave
  • 6,613
  • 1
  • 18
  • 37
  • 2
    Your quest might be related to [Rice's theorem](https://en.wikipedia.org/wiki/Rice%27s_theorem) which states that such questions are undecidable (at compilation time) – Basile Starynkevitch Feb 03 '21 at 05:02
  • I am also new to Zig and have the same question. At the moment I have solved it passing as a parameter a struct with var bool IsEnded, I set to TRUE after last suspend, but it would be great to query the frame itself if possible. – SERWare Feb 05 '21 at 10:43
  • please [join the community](https://github.com/ziglang/zig/wiki/Community#discord) to fix and discuss these kind of questions as the api and details are still in flux/design phase. – Jay-Pi Mar 28 '21 at 21:40
  • @Jay-Pi https://github.com/ziglang/zig/wiki/Community#stack-overflow ;) – Hans Musgrave Mar 28 '21 at 21:42
  • @Jay-Pi I tried a time or two to ask about this on IRC and was met with crickets. Is there a "canonical" (for lack of a better word) community to start with? Reddit? – Hans Musgrave Mar 28 '21 at 21:44
  • @HansMusgrave I am hanging out at the discord. Protty, lithdrew and haze are discussing on the showtime discord async stuff in a channel. You have probably seen prottys scheduling + async videos on the showtime. – Jay-Pi Mar 28 '21 at 22:45

1 Answers1

1

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.

Hans Musgrave
  • 6,613
  • 1
  • 18
  • 37