Backlog/engine/sys/src/subprocess.zig

157 lines
4.2 KiB
Zig

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");