Skip to content

Cancel → Master close → pool.put_all

Description

Cancel → Master close → pool.put_all.

  • Pool seeded with 3 Events, used as a Select event source via getWaitResult.
  • eventLoop processes one item, then a timer triggers, ending the loop.
  • cancelAndRecycle empties sel.cancel(), recycles any in-flight item via pool.put.
  • pool.close then frees everything recycled — no item is lost or double-freed.

Diagram

 pool (seeded: Event×3)
 │ getWaitResult
 Select(MasterEvent) ◄── sleepFn (timer)
 .pool_ev .item ──► process ──pool.put──► pool   (1 item processed)
 .timer ──► sel.cancel() loop
            .pool_ev .item ──► pool.put (recycle, not freed!)
            .pool_ev .canceled ──► (no item, skip)
 pool.close ──► on_close ──► freeList (all recycled items freed cleanly)

Source

pub fn cancel_master_close_pool_put_all(allocator: std.mem.Allocator, io: std.Io) !void {
    const ph: PoolHandle = try pool.new(io, allocator);
    var pool_ctx: hooks.AlwaysCreateHooks = .{ .alloc = allocator };
    const tags = [_]*const anyopaque{items.Event.EventPolyHelper.TAG};
    try pool.init(ph, pool_ctx.poolHooks(&tags));
    defer {
        pool.close(ph);
        pool.destroy(ph, allocator);
    }

    try seedPool(ph);

    var buf: [8]MasterEvent = undefined;
    var sel: std.Io.Select(MasterEvent) = std.Io.Select(MasterEvent).init(io, &buf);
    try setupSelect(ph, io, &sel);

    var processed: usize = 0;
    var recycled: usize = 0;
    try eventLoop(ph, &sel, &processed);
    cancelAndRecycle(ph, &sel, &recycled);

    std.log.info("done: processed={d}, recycled via cancel={d}", .{ processed, recycled });
}

const TIMER_NS: i96 = 15_000_000; // 15 ms

const MasterEvent = union(enum) {
    pool_ev: pool.PoolResult,
    timer: void,
};

fn sleepFn(sleep_t: std.Io.Timeout, io: std.Io) void {
    std.Io.Timeout.sleep(sleep_t, io) catch {};
}

fn seedPool(ph: PoolHandle) !void {
    for (0..3) |i| {
        var slot: Slot = null;
        try pool.get(ph, items.Event.EventPolyHelper.TAG, .new_only, &slot);
        items.Event.EventPolyHelper.mustIdentifySlotAs(&slot).code = @intCast(i + 1);
        pool.put(ph, &slot);
    }
}

fn setupSelect(ph: PoolHandle, io: std.Io, sel: *std.Io.Select(MasterEvent)) !void {
    const sleep_t: std.Io.Timeout = .{
        .duration = .{ .raw = .{ .nanoseconds = TIMER_NS }, .clock = .real },
    };
    try sel.concurrent(.pool_ev, pool.getWaitResult, .{ ph, items.Event.EventPolyHelper.TAG, null });
    try sel.concurrent(.timer, sleepFn, .{ sleep_t, io });
}

fn eventLoop(ph: PoolHandle, sel: *std.Io.Select(MasterEvent), processed: *usize) !void {
    loop: while (true) {
        const event: MasterEvent = try sel.await();
        switch (event) {
            .pool_ev => |r| switch (r) {
                .item => |handle| {
                    var slot: Slot = handle;
                    defer pool.put(ph, &slot);
                    const ev: *items.Event = items.Event.EventPolyHelper.mustIdentifySlotAs(&slot);
                    processed.* += 1;
                    std.log.info("pool_ev: processed code={d} → put back to pool", .{ev.code});
                    try sel.concurrent(.pool_ev, pool.getWaitResult, .{ ph, items.Event.EventPolyHelper.TAG, null });
                },
                .closed, .canceled, .timeout, .not_created => break :loop,
            },
            .timer => {
                std.log.info("timer: canceling remaining pool watchers", .{});
                break :loop;
            },
        }
    }
}

fn cancelAndRecycle(ph: PoolHandle, sel: *std.Io.Select(MasterEvent), recycled: *usize) void {
    while (sel.cancel()) |event| {
        switch (event) {
            .pool_ev => |r| switch (r) {
                .item => |handle| {
                    var slot: Slot = handle;
                    pool.put(ph, &slot);
                    recycled.* += 1;
                    std.log.info("cancel walk: recycled pool item (not freed)", .{});
                },
                .canceled, .closed, .timeout, .not_created => {},
            },
            .timer => {},
        }
    }
}

const items = @import("../items/items.zig");
const hooks = @import("../hooks/hooks.zig");
const matryoshka = @import("matryoshka");
const std = @import("std");
const pool = matryoshka.pool;
const polynode = matryoshka.polynode;
const Slot = polynode.Slot;
const PoolHandle = pool.PoolHandle;