Hi,
I’m trying to understand how to write to stdout correctly from async functions when using std.Io.Threaded, for the use case of writing logs from the connection handler function in a tcp server.
I have the following minimum code to reproduce the issue, which is an error.WriteFailed that only happens from the connection handler, and only when it is called with io.async.
I bet something is wrong with the way i use std.Io.Mutex, or the way i store my handle to stdout and my writer, or the way i init the threaded io, but I’ve been struggling to find examples up to date with the new I/O interface and i don’t know much about multithreading so i can’t figure out the fix.
Can someone let me know what’s wrong with the code below ?
const std = @import("std");
const Io = std.Io;
const net = Io.net;
const fmt = std.fmt;
const Logger = struct {
stdout: std.Io.File,
stdout_buffer: [4096]u8,
stdout_mutex: std.Io.Mutex,
writer: std.Io.File.Writer,
pub fn init(l: *Logger, io: std.Io) void {
l.stdout = std.Io.File.stdout();
l.stdout_buffer = undefined;
l.stdout_mutex = std.Io.Mutex.init;
l.writer = std.Io.File.Writer.init(l.stdout, io, &l.stdout_buffer);
}
pub fn log(l: *Logger, io: std.Io, comptime format: []const u8, args: anytype) !void {
try l.stdout_mutex.lock(io);
defer l.stdout_mutex.unlock(io);
var wr = &l.writer.interface;
try wr.print(format, args);
try wr.flush();
}
};
fn handleConn(io: Io, logger: *Logger, conn: net.Stream) void {
logger.log(io, "handling connection in handleConn\n", .{}) catch |err| {
std.debug.print("ERROR: {}\n", .{err});
};
conn.close(io);
}
pub fn main() !void {
var debug_allocator: std.heap.DebugAllocator(.{
.thread_safe = true,
}) = .init;
const process_allocator = debug_allocator.allocator();
var threaded: Io.Threaded = .init(process_allocator, .{});
var io = threaded.io();
var logger: Logger = undefined;
logger.init(io);
try logger.log(io, "START SERVICE\n", .{});
const loopback: net.IpAddress = .{ .ip4 = net.Ip4Address.loopback(8888) };
var server = loopback.listen(io, .{ .reuse_address = true }) catch |err| {
std.debug.print("error : {}\n", .{err});
return err;
};
defer server.deinit(io);
while (true) {
const conn = server.accept(io) catch {
continue;
};
// The following works as expected:
//
// handleConn(io, &logger, conn);
// The following does not work. It shows "ERROR: error.WriteFailed" in
// the terminal when i send a request to the listening server
var conn_future = io.async(handleConn, .{ io, &logger, conn });
defer conn_future.cancel(io);
}
}