pub const SystemTaskRunner = struct { allocator: std.mem.Allocator, jobs: std.ArrayListUnmanaged(*SystemTask), pub fn create(allocator: std.mem.Allocator) *@This() { const self = allocator.create(@This()); self.* = .{ .allocator = allocator, }; const Job = struct { ctx: *SystemTaskRunner, pub fn func(ctx: @This(), job: *core.JobContext) void { _ = job; _ = ctx; while (true) { // pump events // if nothing pumped this frame, wait 100ms if (self.jobs.items.len > 0) { for (self.jobs.items) |j| { _ = j; } } } } }; try core.dispatchJob(Job{ .ctx = self }); return self; } pub fn pushJob(self: *@This()) !*SystemTask { const task = try self.allocator.create(SystemTask); try self.jobs.append(self.allocator, task); } // check completion from the task thread // returns true if pub fn checkCompletionTT(self: *@This(), task: *SystemTask) bool { _ = task; if (builtin.os.tag == .windows) { _ = self; } } pub fn destroy(self: *@This()) void { self.allocator.destroy(self); } pub var NeonObjectTable = core.EngineObjectVTable.from(@This(), "SystemTaskRunner"); }; pub const SystemTask = struct { status: ExecutionStatus, taskRunner: *SystemTaskRunner, }; pub const SystemTaskExecution = struct { task: *SystemTask, pub fn deinit(self: *@This()) void { if (core.getEngineObject(SystemTaskRunner)) |taskRunner| { try taskRunner.pushJobRemoval(self.task); } } }; pub const ExecutionStatus = enum { ready, failed, success, }; pub const Execution = struct { mutex: std.Thread.Mutex = .{}, status: ExecutionStatus = .ready, payload: ?*anyopaque = null, command: std.ArrayListUnmanaged([]const u8) = .{}, outputStream: std.ArrayListUnmanaged(u8) = .{}, backing: std.mem.Allocator, arena: std.heap.ArenaAllocator, child: ?std.process.Child, lastUpdateTime: i64 = 0, timeout: i64 = 1000000000, pub fn startAlloc(allocator: std.mem.Allocator, command: []const []const u8) !*@This() { const self = try allocator.create(@This()); self.* = .{ .command = undefined, .backing = allocator, .arena = std.heap.ArenaAllocator.init(allocator), }; const alloc = self.arena.allocator(); for (command) |arg| { const a = try alloc.dupe(u8, arg); try self.command.append(alloc, a); } return self; } pub fn run(self: *@This()) void { self.child = std.process.Child.init(self.command.items, self.arena.allocator()); self.child.?.spawn(); } pub fn clearOutputStream(self: *@This()) void { self.outputStream.clearRetainingCapacity(); } // returns true if the status changed at all // can access output via Execution.outputStream pub fn tick(self: *@This()) bool { const lastStatus = self.status; _ = lastStatus; const lastOutputStreamLen = self.outputStream.len; var rv: bool = false; // const allocator = self.arena.allocator(); // try self.child.?.collectOutput(allocator, &self.outputStream, &self.outputStream, 8192 * 2); if (lastOutputStreamLen != self.outputStream.len) { self.lastUpdateTime = std.time.microTimestamp(); rv = true; } const ts = std.time.microTimestamp(); if (self.lastUpdateTime - self.timeout > ts) {} if (self.child.?) {} return rv; } pub fn start(command: []const []const u8) !*@This() { return try startAlloc(sys.getAllocator(), command); } pub fn destroy(self: *@This()) void { self.arena.deinit(); self.backing.destroy(self); } }; const std = @import("std"); pub const core = @import("core"); const sys = @import("../sys.zig"); const builtin = @import("builtin");