New concurrency implementation (threaded and evented on linux)

With latest zig master i tried playing with threaded and evented. I tried copying code from main.zig from zig compiler. But the threaded variation seems to segfault. .evented seems to work. is there any working sample I can look at to learn about how it should be used ?

const builtin = @import("builtin");
const native_os = builtin.os.tag;
const std = @import("std");
const Io = std.Io;
const mem = std.mem;
const Allocator = mem.Allocator;

const use_debug_allocator = false;
const mem_leak_frames = 200;

const IoMode = enum {
    threaded, evented
};

const io_mode: IoMode = .threaded;

const RootAllocator = if (use_debug_allocator) std.heap.DebugAllocator(.{
    .stack_trace_frames = mem_leak_frames,
    .thread_safe = switch (io_mode) {
        .threaded => true,
        .evented => false,
    },
}) else struct {
    pub const init: RootAllocator = .{};
    pub fn allocator(_: RootAllocator) Allocator {
        if (native_os == .wasi) return std.heap.wasm_allocator;
        if (builtin.link_libc) return std.heap.c_allocator;
        return std.heap.smp_allocator;
    }
    pub fn deinit(_: RootAllocator) std.heap.Check {
        return .ok;
    }
};

const IoImpl = switch (io_mode) {
    .threaded => Io.Threaded,
    .evented => Io.Evented,
};

const thread_stack_size = 2000;

fn writeAll(io: Io, file: std.Io.File, data: []const u8) !void {
    var buffer: [1024]u8 = undefined;
    var writer: std.Io.File.Writer = .initStreaming(file, io, &buffer);
    const w = &writer.interface;
    try w.writeAll(data);
    try writer.end();
}


fn saveFile2(io: Io, data: []const u8, name: []const u8) !void {
    const file = try Io.Dir.cwd().createFile(io, name, .{});
    defer file.close(io);

    try writeAll(io, file, data);

    // var buffer: [1024]u8 = undefined;
    // var writer: std.Io.File.Writer = .initStreaming(file, io, &buffer);
    // const w = &writer.interface;
    // try w.writeAll(data);

    // try file.writeAll(io, data);
}

fn saveData4(io: Io, data: []const u8) !void {
   var a_future = io.async(saveFile2, .{io, data, "saveA.txt"});
   defer a_future.cancel(io) catch {};

   var b_future = io.async(saveFile2, .{io, data, "saveB.txt"});
   defer b_future.cancel(io) catch {};

   // We could decide to cancel the current task
   // and everything would be realeased correctly.
   // if (true) return error.Canceled;

   try a_future.await(io);
   try b_future.await(io);

   // const out: Io.File = .stdout();
   try writeAll(io, .stdout(), "save complete");
}

pub fn main(init: std.process.Init.Minimal) !void {
    var root_allocator: RootAllocator = .init;
    defer _ = root_allocator.deinit();
    const root_gpa = root_allocator.allocator();
    var io_impl: IoImpl = undefined;
    switch (io_mode) {
        .threaded => io_impl = .init(root_gpa, .{
            .stack_size = thread_stack_size,
            .argv0 = .init(init.args),
            .environ = init.environ,
        }),
        .evented => try io_impl.init(root_gpa, .{
            .argv0 = .init(init.args),
            .environ = init.environ,
            .backing_allocator_needs_mutex = use_debug_allocator,
        }),
    }
    defer io_impl.deinit();

    const io = io_impl.io();
    // const gpa = switch (io_mode) {
    //     .threaded => root_gpa,
    //     .evented => io_impl.allocator(),
    // };

    try saveData4(io, "data");
}

1 Like

can you provide the stack trace