Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

await should not be a suspend point when used on a @Frame(func) and func is blocking #3067

Closed
andrewrk opened this issue Aug 15, 2019 · 0 comments
Labels
enhancement Solving this issue will likely involve adding new logic or components to the codebase.
Milestone

Comments

@andrewrk
Copy link
Member

Here's that good 'ol example again:

const std = @import("std");
const Allocator = std.mem.Allocator;

pub fn main() void {
    _ = async amainWrap();
}

fn amainWrap() void {
    amain() catch |e| {
        std.debug.warn("{}\n", e);
        if (@errorReturnTrace()) |trace| {
            std.debug.dumpStackTrace(trace.*);
        }
        std.process.exit(1);
    };
}

fn amain() !void {
    const allocator = std.heap.direct_allocator;
    var download_frame = async fetchUrl(allocator, "https://example.com/");
    var awaited_download_frame = false;
    errdefer if (!awaited_download_frame) {
        if (await download_frame) |r| allocator.free(r) else |_| {}
    };

    var file_frame = async readFile(allocator, "something.txt");
    var awaited_file_frame = false;
    errdefer if (!awaited_file_frame) {
        if (await file_frame) |r| allocator.free(r) else |_| {}
    };

    awaited_file_frame = true;
    const file_text = try await file_frame;
    defer allocator.free(file_text);

    awaited_download_frame = true;
    const download_text = try await download_frame;
    defer allocator.free(download_text);

    std.debug.warn("download_text: {}\n", download_text);
    std.debug.warn("file_text: {}\n", file_text);
}

fn fetchUrl(allocator: *Allocator, url: []const u8) ![]u8 {
    const result = try std.mem.dupe(allocator, u8, "this is the downloaded url contents");
    errdefer allocator.free(result);
    std.debug.warn("fetchUrl returning\n");
    return result;
}

fn readFile(allocator: *Allocator, filename: []const u8) ![]u8 {
    const result = try std.mem.dupe(allocator, u8, "this is the file contents");
    errdefer allocator.free(result);
    std.debug.warn("readFile returning\n");
    return result;
}

This works:

fetchUrl returning
readFile returning
download_text: this is the downloaded url contents
file_text: this is the file contents

But if we try to treat amain as non blocking:

const std = @import("std");
const Allocator = std.mem.Allocator;

pub fn main() !void {
    const allocator = std.heap.direct_allocator;
    var download_frame = async fetchUrl(allocator, "https://example.com/");
    var awaited_download_frame = false;
    errdefer if (!awaited_download_frame) {
        if (await download_frame) |r| allocator.free(r) else |_| {}
    };

    var file_frame = async readFile(allocator, "something.txt");
    var awaited_file_frame = false;
    errdefer if (!awaited_file_frame) {
        if (await file_frame) |r| allocator.free(r) else |_| {}
    };

    awaited_file_frame = true;
    const file_text = try await file_frame;
    defer allocator.free(file_text);

    awaited_download_frame = true;
    const download_text = try await download_frame;
    defer allocator.free(download_text);

    std.debug.warn("download_text: {}\n", download_text);
    std.debug.warn("file_text: {}\n", file_text);
}

fn fetchUrl(allocator: *Allocator, url: []const u8) ![]u8 {
    const result = try std.mem.dupe(allocator, u8, "this is the downloaded url contents");
    errdefer allocator.free(result);
    std.debug.warn("fetchUrl returning\n");
    return result;
}

fn readFile(allocator: *Allocator, filename: []const u8) ![]u8 {
    const result = try std.mem.dupe(allocator, u8, "this is the file contents");
    errdefer allocator.free(result);
    std.debug.warn("readFile returning\n");
    return result;
}

We get:

/home/andy/dev/zig/build/lib/zig/std/special/start.zig:31:1: error: function with calling convention 'nakedcc' cannot be async
nakedcc fn _start() noreturn {
^
/home/andy/dev/zig/build/lib/zig/std/special/start.zig:56:5: note: async function call here
    @noInlineCall(posixCallMainAndExit);
    ^
/home/andy/dev/zig/build/lib/zig/std/special/start.zig:97:33: note: async function call here
    std.os.exit(callMainWithArgs(argc, argv, envp));
                                ^
/home/andy/dev/zig/build/lib/zig/std/special/start.zig:108:20: note: async function call here
    return callMain();
                   ^
/home/andy/dev/zig/build/lib/zig/std/special/start.zig:139:37: note: async function call here
            const result = root.main() catch |err| {
                                    ^
/home/andy/dev/zig/build/test2.zig:19:27: note: await is a suspend point
    const file_text = try await file_frame;
                          ^

Really, though, the awaits inside main are non-async and should not force main to be async.

@andrewrk andrewrk added the enhancement Solving this issue will likely involve adding new logic or components to the codebase. label Aug 15, 2019
@andrewrk andrewrk added this to the 0.5.0 milestone Aug 15, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement Solving this issue will likely involve adding new logic or components to the codebase.
Projects
None yet
Development

No branches or pull requests

1 participant