| 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,7 +153,8 @@ pub extern "c" fn linkat(oldfd: c.fd_t, oldpath: [*:0]const u8, newfd: c.fd_t, n |
| 153 | pub extern "c" fn unlink(path: [*:0]const u8) c_int; | 153 | pub extern "c" fn unlink(path: [*:0]const u8) c_int; |
| 154 | pub extern "c" fn unlinkat(dirfd: c.fd_t, path: [*:0]const u8, flags: c_uint) c_int; | 154 | pub extern "c" fn unlinkat(dirfd: c.fd_t, path: [*:0]const u8, flags: c_uint) c_int; |
| 155 | pub extern "c" fn getcwd(buf: [*]u8, size: usize) ?[*]u8; | 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 | pub extern "c" fn fork() c_int; | 158 | pub extern "c" fn fork() c_int; |
| 158 | pub extern "c" fn access(path: [*:0]const u8, mode: c_uint) c_int; | 159 | pub extern "c" fn access(path: [*:0]const u8, mode: c_uint) c_int; |
| 159 | pub extern "c" fn faccessat(dirfd: c.fd_t, path: [*:0]const u8, mode: c_uint, flags: c_uint) c_int; | 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,6 +17,7 @@ const Os = std.builtin.Os; |
| 17 | const TailQueue = std.TailQueue; | 17 | const TailQueue = std.TailQueue; |
| 18 | const maxInt = std.math.maxInt; | 18 | const maxInt = std.math.maxInt; |
| 19 | const assert = std.debug.assert; | 19 | const assert = std.debug.assert; |
| 20 | const is_darwin = builtin.target.isDarwin(); | ||
| 20 | 21 | ||
| 21 | pub const ChildProcess = struct { | 22 | pub const ChildProcess = struct { |
| 22 | pub const Id = switch (builtin.os.tag) { | 23 | pub const Id = switch (builtin.os.tag) { |
| ... | @@ -70,6 +71,43 @@ pub const ChildProcess = struct { | ... | @@ -70,6 +71,43 @@ pub const ChildProcess = struct { |
| 70 | /// Darwin-only. Start child process in suspended state as if SIGSTOP was sent. | 71 | /// Darwin-only. Start child process in suspended state as if SIGSTOP was sent. |
| 71 | start_suspended: bool = false, | 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 | pub const Arg0Expand = os.Arg0Expand; | 111 | pub const Arg0Expand = os.Arg0Expand; |
| 74 | 112 | ||
| 75 | pub const SpawnError = error{ | 113 | pub const SpawnError = error{ |
| ... | @@ -332,7 +370,16 @@ pub const ChildProcess = struct { | ... | @@ -332,7 +370,16 @@ pub const ChildProcess = struct { |
| 332 | } | 370 | } |
| 333 | 371 | ||
| 334 | fn waitUnwrapped(self: *ChildProcess) !void { | 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 | const status = res.status; | 383 | const status = res.status; |
| 337 | self.cleanupStreams(); | 384 | self.cleanupStreams(); |
| 338 | self.handleWaitResult(status); | 385 | self.handleWaitResult(status); |
lib/std/os.zig+21-1| ... | @@ -4000,8 +4000,28 @@ pub const WaitPidResult = struct { | ... | @@ -4000,8 +4000,28 @@ pub const WaitPidResult = struct { |
| 4000 | pub fn waitpid(pid: pid_t, flags: u32) WaitPidResult { | 4000 | pub fn waitpid(pid: pid_t, flags: u32) WaitPidResult { |
| 4001 | const Status = if (builtin.link_libc) c_int else u32; | 4001 | const Status = if (builtin.link_libc) c_int else u32; |
| 4002 | var status: Status = undefined; | 4002 | var status: Status = undefined; |
| 4003 | const coerced_flags = if (builtin.link_libc) @intCast(c_int, flags) else flags; | ||
| 4003 | while (true) { | 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 | switch (errno(rc)) { | 4025 | switch (errno(rc)) { |
| 4006 | .SUCCESS => return .{ | 4026 | .SUCCESS => return .{ |
| 4007 | .pid = @intCast(pid_t, rc), | 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,6 +944,16 @@ pub fn waitpid(pid: pid_t, status: *u32, flags: u32) usize { |
| 944 | return syscall4(.wait4, @bitCast(usize, @as(isize, pid)), @ptrToInt(status), flags, 0); | 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 | pub fn waitid(id_type: P, id: i32, infop: *siginfo_t, flags: u32) usize { | 957 | pub fn waitid(id_type: P, id: i32, infop: *siginfo_t, flags: u32) usize { |
| 948 | return syscall5(.waitid, @enumToInt(id_type), @bitCast(usize, @as(isize, id)), @ptrToInt(infop), flags, 0); | 958 | return syscall5(.waitid, @enumToInt(id_type), @bitCast(usize, @as(isize, id)), @ptrToInt(infop), flags, 0); |
| 949 | } | 959 | } |