updated logger: integrate mutex into WriterState (move-safety), fix lock/unlock logic in deinit

This commit is contained in:
2026-08-07 23:22:01 +02:00
parent bea0b6668a
commit 963f1611fb

View File

@@ -55,20 +55,21 @@ pub const Logger = struct {
level: Level = .info,
on_error: ErrorCallback = null,
io: std.Io = undefined,
state: *WriterState = undefined,
mutex: std.Io.Mutex = undefined,
allocator: std.mem.Allocator = undefined,
io: std.Io,
state: *WriterState,
allocator: std.mem.Allocator,
const Self = @This();
/// Heap-allocated home for the write buffer and the `File.Writer`
/// built on top of it. `File.Writer` holds a pointer into
/// `buffer`, so both must live at a stable address that survives
/// the `Logger` value itself being copied or moved.
/// Heap-allocated home for the write buffer, the `File.Writer`
/// built on top of it, and the mutex guarding both. `File.Writer`
/// holds a pointer into `buffer`, so all three must live at a
/// stable address that survives the `Logger` value itself being
/// copied or moved.
const WriterState = struct {
buffer: []u8,
mutex: std.Io.Mutex,
writer: std.Io.File.Writer,
};
@@ -92,15 +93,16 @@ pub const Logger = struct {
const state = try allocator.create(WriterState);
state.* = .{
.buffer = buffer,
.mutex = .init,
.writer = options.file.writer(options.io, buffer),
};
return Self{
.level = options.level,
.on_error = options.on_error,
.io = options.io,
.state = state,
.mutex = .init,
.allocator = allocator,
};
}
@@ -116,9 +118,12 @@ pub const Logger = struct {
/// allocations are freed unconditionally.
pub fn deinit(logger: *Self) void
{
logger.mutex.lock(logger.io) catch {};
logger.state.writer.interface.flush() catch {};
logger.mutex.unlock(logger.io);
if (logger.state.mutex.lock(logger.io)) |_|
{
logger.state.writer.interface.flush() catch {};
logger.state.mutex.unlock(logger.io);
}
else |_| {}
logger.allocator.free(logger.state.buffer);
logger.allocator.destroy(logger.state);
@@ -143,8 +148,8 @@ pub const Logger = struct {
{
if (@intFromEnum(level) < @intFromEnum(logger.level)) return;
try logger.mutex.lock(logger.io);
defer logger.mutex.unlock(logger.io);
try logger.state.mutex.lock(logger.io);
defer logger.state.mutex.unlock(logger.io);
try logger.state.writer.interface.print(fmt, args);
try logger.state.writer.interface.writeByte('\n');
@@ -170,8 +175,8 @@ pub const Logger = struct {
/// Returns an error if the underlying writer fails to flush.
pub fn flush(logger: *Self) !void
{
try logger.mutex.lock(logger.io);
defer logger.mutex.unlock(logger.io);
try logger.state.mutex.lock(logger.io);
defer logger.state.mutex.unlock(logger.io);
try logger.state.writer.interface.flush();
}