Trying to understand cancellation

I don’t understand why the following program hangs forever. I thought that accept was a cancelable operation (and indeed it has Io.Cancelable as part of its error set), but it doesn’t actually work. Can someone tell me what I’m missing?

OS: Windows
Zig: 0.16.0-dev.2193+fc517bd01

const std = @import("std");

pub fn main(init: std.process.Init) !void {
    const io = init.io;

    const addr = std.Io.net.IpAddress.parse("127.0.0.1", 0) catch unreachable;
    var server = try addr.listen(io, .{});
    defer server.deinit(io);

    var accept = try io.concurrent(std.Io.net.Server.accept, .{ &server, io });
    defer if (accept.cancel(io)) |stream| stream.close(io) else |_| {};

    try io.sleep(.fromSeconds(1), .real);
}

Because cancelling is something that the runtime needs to actively check for, Threaded does at least, other runtimes might be able to be smarter.
The sleep simply causes the task to get far enough to do the syscall which blocks its thread until a connection is attempted, this is the behaviour of the Threaded Io implementation, it can’t check for cancellation in the middle of a syscall.

Another thread can however interrupt it when calling cancel, but that doesn’t seem to be implemented yet, though I wouldn’t be able to tell unless it was obvious.

So it’s just the result of using a WIP runtime. If it is a bug it should be reported, but I can’t tell you if that is the case.

This code is intended to work. You’re not missing anything.

It already works on POSIX systems, but there is additional code that needs to be added to the Windows implementation in order for this to work.

I don’t see an open bug report for this. Would you mind making one?

2 Likes

Thanks for clearing that up!

Thanks! The low level workings of cancelation has been super interesting to learn about.