Zig 中的 child process 簡介

在工作中,難免會去重複執行某些某個任務,直到其成功爲止。比如下載依賴,之前我的做法是用 Shell

while ! do something; do echo retry; done

這樣雖然可以,但是有些麻煩,於是就想能不能實現個 cli,來替我們執行,如果用 C 實現的話,可以預想到的,就是 fork + exec,貌似也不是很麻煩。

但是如果要在主進程中,等待 child 完成的之前,收集 child 的 stdout,而不堵塞主進程,那就要採用異步的 API 來輪訓 stdout,比如 select 或 poll, Zig 裏面有個 child_process.zig[1],它裏面把 fork + exec + poll 都封裝好了,直接使用即可,一些關鍵函數:

/// Collect the output from the process's stdout and stderr. Will return once all output
/// has been collected. This does not mean that the process has ended. `wait` should still
/// be called to wait for and clean up the process.
///
/// The process must be started with stdout_behavior and stderr_behavior == .Pipe
pub fn collectOutput(
    child: ChildProcess,
    stdout: *std.ArrayList(u8),
    stderr: *std.ArrayList(u8),
    max_output_bytes: usize,
) !void {
    debug.assert(child.stdout_behavior == .Pipe);
    debug.assert(child.stderr_behavior == .Pipe);

    // we could make this work with multiple allocators but YAGNI
    if (stdout.allocator.ptr != stderr.allocator.ptr or
        stdout.allocator.vtable != stderr.allocator.vtable)
        @panic("ChildProcess.collectOutput only supports 1 allocator");

    var poller = std.io.poll(stdout.allocator, enum { stdout, stderr }, .{
        .stdout = child.stdout.?,
        .stderr = child.stderr.?,
    });
    defer poller.deinit();

    while (try poller.poll()) {
        if (poller.fifo(.stdout).count > max_output_bytes)
            return error.StdoutStreamTooLong;
        if (poller.fifo(.stderr).count > max_output_bytes)
            return error.StderrStreamTooLong;
    }

    stdout.* = fifoToOwnedArrayList(poller.fifo(.stdout));
    stderr.* = fifoToOwnedArrayList(poller.fifo(.stderr));
}

這是收集 stdout 的,創建進程的地方在 spawnPosix 中,感興趣的可以自行查看,後來有機會再來介紹。

推薦閱讀

參考資料

[1]  child_process.zig: https://github.com/ziglang/zig/blob/7dd1cf26f9b0cb104ada166a10ff356ca272577a/lib/std/child_process.zig#L1

[2]  microHOWTO: Capture the output of a child process in C: http://www.microhowto.info/howto/capture_the_output_of_a_child_process_in_c.html

[3]  Forking is Cool, or: A Unix Shell in Zig, or: Dave Learns How to Fork: https://ratfactor.com/zig/forking-is-cool

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/uAwpDnYCp5ts7mB8aJpaAQ