Skip to content

Using completion in multi-threaded application #134

Open
@fnzr

Description

@fnzr

This is a general question, I probably just don't understand things enough.

The following program prints "timer" to the console every second, and when something gets written to the stdin, the program print "received stdin", sleeps 5 seconds then prints "end stdin".

const std = @import("std");
const xev = @import("xev");

pub fn main() !void {
    var tpool = xev.ThreadPool.init(.{});
    defer tpool.deinit();
    defer tpool.shutdown();

    var loop = try xev.Loop.init(.{ .thread_pool = &tpool });
    defer loop.deinit();

    var stdin_completion = .{
        .op = .{
            .poll = .{
                .fd = std.io.getStdIn().handle,
                .events = 1,
            },
        },
        .userdata = null,
        .callback = (struct {
            fn callback(_: ?*anyopaque, _: *xev.Loop, _: *xev.Completion, _: xev.Result) xev.CallbackAction {
                std.io.getStdOut().writer().writeAll("received stdin\n") catch unreachable;
                _ = std.io.getStdIn().reader().skipUntilDelimiterOrEof('\n') catch unreachable;
                std.time.sleep(std.time.ns_per_s * 5);
                std.io.getStdOut().writer().writeAll("end stdin\n") catch unreachable;
                return .rearm;
            }
        }).callback,
    };
    loop.add(&stdin_completion);

    var watcher = try xev.Timer.init();
    defer watcher.deinit();
    var timer_completion: xev.Completion = undefined;
    watcher.run(&loop, &timer_completion, 1000, xev.Timer, &watcher, &timerCallback);

    try loop.run(.until_done);
}
fn timerCallback(
    watcher: ?*xev.Timer,
    loop: *xev.Loop,
    c: *xev.Completion,
    result: xev.Timer.RunError!void,
) xev.CallbackAction {
    _ = result catch unreachable;
    std.io.getStdOut().writer().writeAll("timer\n") catch unreachable;
    watcher.?.reset(loop, c, c, 1000, xev.Timer, watcher.?, &timerCallback);
    return .disarm;
}

The issue is, when the stdin event is triggered, the timer is stopped until the stdin callback exits.

I can solve this problem by using the ThreadPool and inside the Task, handle the stdin, but then I lose access to the xev.Completion and on-demand callback (I'd need a while(true) to read stdin)

Is there a way to run both the timer and stdin callbacks concurrently?

extra question: what are these poll events? To be honest I kinda guessed 1 and it worked as I wanted

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions