Introduce deinitIfLive utility and integrate enhanced memory management

This commit is contained in:
2026-08-02 22:59:02 +02:00
parent b1bdfccd1e
commit d70a051a57
3 changed files with 62 additions and 10 deletions

View File

@@ -1,3 +1,8 @@
//! Entry point for the zocket daemon.
//!
//! Handles allocator selection (debug-checked vs. release), CLI argument
//! parsing, and configuration path resolution before handing off to `run`.
const zocket = @import("zocket");
const std = @import("std");
@@ -7,6 +12,14 @@ const options = @import("build_options");
const args = zocket.deps.args;
// TODO: switch vars/consts/params to snake_case
/// Resolves the config path, then delegates to `run`.
///
/// Allocator strategy:
/// - Debug builds use `DebugAllocator`, which tracks every allocation and
/// panics/exits on leaks or double-frees.
/// - Release builds use `c_allocator` for C ABI interop.
pub fn main(init: std.process.Init) !void
{
const debug = builtin.mode == .Debug;
@@ -21,10 +34,13 @@ pub fn main(init: std.process.Init) !void
const allocator = if (debug) gpa.allocator() else std.heap.c_allocator;
var tmpArena = std.heap.ArenaAllocator.init(std.heap.c_allocator);
const tmpAllocator = tmpArena.allocator();
var tmp_arena = std.heap.ArenaAllocator.init(allocator);
var arena_live = true;
var parser = try args.ArgumentParser.init(tmpAllocator, .{
const tmp_allocator = tmp_arena.allocator();
errdefer zocket.memory.deinitIfLive(&tmp_arena, &arena_live);
var parser = try args.ArgumentParser.init(tmp_allocator, .{
.name = "zocket",
.version = options.version,
.description = "A lightweight Zig WebSocket server and mesh routing daemon.",
@@ -39,23 +55,30 @@ pub fn main(init: std.process.Init) !void
const path = if (debug) path:
{
const tmpPath = result.getString("path") orelse "config/config.toml";
break :path try allocator.dupe(u8, tmpPath);
const tmp_path = result.getString("path") orelse "config/config.toml";
break :path try allocator.dupe(u8, tmp_path);
}
else path:
{
const tmpPath = result.getString("path") orelse blk: {
const exe = try std.process.executableDirPathAlloc(io, tmpAllocator);
break :blk try std.Io.Dir.path.join(tmpAllocator, &.{ exe, "config/config.toml" });
const tmp_path = result.getString("path") orelse blk: {
const exe = try std.process.executableDirPathAlloc(io, tmp_allocator);
break :blk try std.Io.Dir.path.join(tmp_allocator, &.{ exe, "config/config.toml" });
};
break :path try allocator.dupe(u8, tmpPath);
break :path try allocator.dupe(u8, tmp_path);
};
tmpArena.deinit();
zocket.memory.deinitIfLive(&tmp_arena, &arena_live);
try run(io, allocator, path);
}
/// Loads and parses the configuration file at `path`, then hands off to
/// the rest of the application.
///
/// Owns `path` and frees it once it's no longer needed; Callers must not free `path` themselves!
///
/// On parse failure, logs a human-readable reason and terminates the
/// process immediately via `std.process.exit`.
fn run(io: std.Io, allocator: std.mem.Allocator, path: []const u8) !void
{
const parsed = zocket.config.parse(io, allocator, path) catch |err|

27
src/memory/util.zig Normal file
View File

@@ -0,0 +1,27 @@
const std = @import("std");
/// Deinitializes `allocator` only if it is still live.
///
/// Pass a pointer to the original allocator owner, such as an
/// `ArenaAllocator` or `DebugAllocator`.
///
/// If `live` is `true`, calls `allocator.deinit()` and then sets
/// `live` to `false`, preventing a later cleanup path from attempting
/// to deinitialize the same allocator again.
///
/// The return value of `deinit()` is discarded.
pub fn deinitIfLive(allocator: anytype, live: *bool) void
{
comptime
{
const T = @TypeOf(allocator);
if (@typeInfo(T) != .pointer) @compileError("deinitIfLive expects a pointer!");
if (T == std.mem.Allocator) @compileError("deinitIfLive expects a pointer to an allocator owner, not std.mem.Allocator!");
}
if (live.*) {
_ = allocator.deinit();
live.* = false;
}
}

View File

@@ -4,7 +4,9 @@ pub const deps = struct {
pub const config = @import("config/config.zig");
pub const memory = @import("memory/util.zig");
test {
_ = config;
_ = memory;
}