| author | |
| committer | |
| log | 41a5ad28c9a651efd2822f43486a71ca48ace726 |
| tree | a2513ed3e16aa7bfbc1c0f8e89c34ed1c1d83f8e |
| parent | 8b054e190a977ccd27302debd5d0f95c28597005 |
4 files changed, 81 insertions(+), 3 deletions(-)
lib/std/c.zig+2-1| ... | ... | @@ -153,7 +153,8 @@ pub extern "c" fn linkat(oldfd: c.fd_t, oldpath: [*:0]const u8, newfd: c.fd_t, n |
| 153 | 153 | pub extern "c" fn unlink(path: [*:0]const u8) c_int; |
| 154 | 154 | pub extern "c" fn unlinkat(dirfd: c.fd_t, path: [*:0]const u8, flags: c_uint) c_int; |
| 155 | 155 | pub extern "c" fn getcwd(buf: [*]u8, size: usize) ?[*]u8; |
| 156 | pub extern "c" fn waitpid(pid: c.pid_t, stat_loc: ?*c_int, options: c_int) c.pid_t; | |
| 156 | pub extern "c" fn waitpid(pid: c.pid_t, status: ?*c_int, options: c_int) c.pid_t; | |
| 157 | pub extern "c" fn wait4(pid: c.pid_t, status: ?*c_int, options: c_int, ru: ?*c.rusage) c.pid_t; | |
| 157 | 158 | pub extern "c" fn fork() c_int; |
| 158 | 159 | pub extern "c" fn access(path: [*:0]const u8, mode: c_uint) c_int; |
| 159 | 160 | pub extern "c" fn faccessat(dirfd: c.fd_t, path: [*:0]const u8, mode: c_uint, flags: c_uint) c_int; |
lib/std/child_process.zig+48-1| ... | ... | @@ -17,6 +17,7 @@ const Os = std.builtin.Os; |
| 17 | 17 | const TailQueue = std.TailQueue; |
| 18 | 18 | const maxInt = std.math.maxInt; |
| 19 | 19 | const assert = std.debug.assert; |
| 20 | const is_darwin = builtin.target.isDarwin(); | |
| 20 | 21 | |
| 21 | 22 | pub const ChildProcess = struct { |
| 22 | 23 | pub const Id = switch (builtin.os.tag) { |
| ... | ... | @@ -70,6 +71,43 @@ pub const ChildProcess = struct { |
| 70 | 71 | /// Darwin-only. Start child process in suspended state as if SIGSTOP was sent. |
| 71 | 72 | start_suspended: bool = false, |
| 72 | 73 | |
| 74 | /// Set to true to obtain rusage information for the child process. | |
| 75 | /// Depending on the target platform and implementation status, the | |
| 76 | /// requested statistics may or may not be available. If they are | |
| 77 | /// available, then the `resource_usage_statistics` field will be populated | |
| 78 | /// after calling `wait`. | |
| 79 | /// On Linux, this obtains rusage statistics from wait4(). | |
| 80 | request_resource_usage_statistics: bool = false, | |
| 81 | ||
| 82 | /// This is available after calling wait if | |
| 83 | /// `request_resource_usage_statistics` was set to `true` before calling | |
| 84 | /// `spawn`. | |
| 85 | resource_usage_statistics: ResourceUsageStatistics = .{}, | |
| 86 | ||
| 87 | pub const ResourceUsageStatistics = struct { | |
| 88 | rusage: @TypeOf(rusage_init) = rusage_init, | |
| 89 | ||
| 90 | /// Returns the peak resident set size of the child process, in bytes, | |
| 91 | /// if available. | |
| 92 | pub inline fn getMaxRss(rus: ResourceUsageStatistics) ?usize { | |
| 93 | switch (builtin.os.tag) { | |
| 94 | .linux => { | |
| 95 | if (rus.rusage) |ru| { | |
| 96 | return @intCast(usize, ru.maxrss) * 1024; | |
| 97 | } else { | |
| 98 | return null; | |
| 99 | } | |
| 100 | }, | |
| 101 | else => return null, | |
| 102 | } | |
| 103 | } | |
| 104 | ||
| 105 | const rusage_init = switch (builtin.os.tag) { | |
| 106 | .linux => @as(?std.os.rusage, null), | |
| 107 | else => {}, | |
| 108 | }; | |
| 109 | }; | |
| 110 | ||
| 73 | 111 | pub const Arg0Expand = os.Arg0Expand; |
| 74 | 112 | |
| 75 | 113 | pub const SpawnError = error{ |
| ... | ... | @@ -332,7 +370,16 @@ pub const ChildProcess = struct { |
| 332 | 370 | } |
| 333 | 371 | |
| 334 | 372 | fn waitUnwrapped(self: *ChildProcess) !void { |
| 335 | const res: os.WaitPidResult = os.waitpid(self.id, 0); | |
| 373 | const res: os.WaitPidResult = res: { | |
| 374 | if (builtin.os.tag == .linux and self.request_resource_usage_statistics) { | |
| 375 | var ru: std.os.rusage = undefined; | |
| 376 | const res = os.wait4(self.id, 0, &ru); | |
| 377 | self.resource_usage_statistics.rusage = ru; | |
| 378 | break :res res; | |
| 379 | } | |
| 380 | ||
| 381 | break :res os.waitpid(self.id, 0); | |
| 382 | }; | |
| 336 | 383 | const status = res.status; |
| 337 | 384 | self.cleanupStreams(); |
| 338 | 385 | self.handleWaitResult(status); |
lib/std/os.zig+21-1| ... | ... | @@ -4000,8 +4000,28 @@ pub const WaitPidResult = struct { |
| 4000 | 4000 | pub fn waitpid(pid: pid_t, flags: u32) WaitPidResult { |
| 4001 | 4001 | const Status = if (builtin.link_libc) c_int else u32; |
| 4002 | 4002 | var status: Status = undefined; |
| 4003 | const coerced_flags = if (builtin.link_libc) @intCast(c_int, flags) else flags; | |
| 4003 | 4004 | while (true) { |
| 4004 | const rc = system.waitpid(pid, &status, if (builtin.link_libc) @intCast(c_int, flags) else flags); | |
| 4005 | const rc = system.waitpid(pid, &status, coerced_flags); | |
| 4006 | switch (errno(rc)) { | |
| 4007 | .SUCCESS => return .{ | |
| 4008 | .pid = @intCast(pid_t, rc), | |
| 4009 | .status = @bitCast(u32, status), | |
| 4010 | }, | |
| 4011 | .INTR => continue, | |
| 4012 | .CHILD => unreachable, // The process specified does not exist. It would be a race condition to handle this error. | |
| 4013 | .INVAL => unreachable, // Invalid flags. | |
| 4014 | else => unreachable, | |
| 4015 | } | |
| 4016 | } | |
| 4017 | } | |
| 4018 | ||
| 4019 | pub fn wait4(pid: pid_t, flags: u32, ru: ?*rusage) WaitPidResult { | |
| 4020 | const Status = if (builtin.link_libc) c_int else u32; | |
| 4021 | var status: Status = undefined; | |
| 4022 | const coerced_flags = if (builtin.link_libc) @intCast(c_int, flags) else flags; | |
| 4023 | while (true) { | |
| 4024 | const rc = system.wait4(pid, &status, coerced_flags, ru); | |
| 4005 | 4025 | switch (errno(rc)) { |
| 4006 | 4026 | .SUCCESS => return .{ |
| 4007 | 4027 | .pid = @intCast(pid_t, rc), |
lib/std/os/linux.zig+10| ... | ... | @@ -944,6 +944,16 @@ pub fn waitpid(pid: pid_t, status: *u32, flags: u32) usize { |
| 944 | 944 | return syscall4(.wait4, @bitCast(usize, @as(isize, pid)), @ptrToInt(status), flags, 0); |
| 945 | 945 | } |
| 946 | 946 | |
| 947 | pub fn wait4(pid: pid_t, status: *u32, flags: u32, usage: ?*rusage) usize { | |
| 948 | return syscall4( | |
| 949 | .wait4, | |
| 950 | @bitCast(usize, @as(isize, pid)), | |
| 951 | @ptrToInt(status), | |
| 952 | flags, | |
| 953 | @ptrToInt(usage), | |
| 954 | ); | |
| 955 | } | |
| 956 | ||
| 947 | 957 | pub fn waitid(id_type: P, id: i32, infop: *siginfo_t, flags: u32) usize { |
| 948 | 958 | return syscall5(.waitid, @enumToInt(id_type), @bitCast(usize, @as(isize, id)), @ptrToInt(infop), flags, 0); |
| 949 | 959 | } |