mirror of
https://codeberg.org/ziglang/zig.git
synced 2026-03-08 01:04:43 +01:00
std.Progress: implement ipc resource cleanup
This commit is contained in:
parent
ffc6da29e3
commit
71156aff80
4 changed files with 556 additions and 543 deletions
|
|
@ -386,10 +386,14 @@ pub const ZigProcess = struct {
|
|||
child: std.process.Child,
|
||||
multi_reader_buffer: Io.File.MultiReader.Buffer(2),
|
||||
multi_reader: Io.File.MultiReader,
|
||||
progress_ipc_fd: if (std.Progress.have_ipc) ?std.posix.fd_t else void,
|
||||
progress_ipc_index: ?if (std.Progress.have_ipc) std.Progress.Ipc.Index else noreturn,
|
||||
|
||||
pub const StreamEnum = enum { stdout, stderr };
|
||||
|
||||
pub fn saveState(zp: *ZigProcess, prog_node: std.Progress.Node) void {
|
||||
zp.progress_ipc_index = if (std.Progress.have_ipc) prog_node.takeIpcIndex() else null;
|
||||
}
|
||||
|
||||
pub fn deinit(zp: *ZigProcess, io: Io) void {
|
||||
zp.child.kill(io);
|
||||
zp.multi_reader.deinit();
|
||||
|
|
@ -417,7 +421,14 @@ pub fn evalZigProcess(
|
|||
|
||||
if (s.getZigProcess()) |zp| update: {
|
||||
assert(watch);
|
||||
if (std.Progress.have_ipc) if (zp.progress_ipc_fd) |fd| prog_node.setIpcFd(fd);
|
||||
if (zp.progress_ipc_index) |ipc_index| prog_node.setIpcIndex(ipc_index);
|
||||
zp.progress_ipc_index = null;
|
||||
var exited = false;
|
||||
defer if (exited) {
|
||||
s.cast(Compile).?.zig_process = null;
|
||||
zp.deinit(io);
|
||||
gpa.destroy(zp);
|
||||
} else zp.saveState(prog_node);
|
||||
const result = zigProcessUpdate(s, zp, watch, web_server, gpa) catch |err| switch (err) {
|
||||
error.BrokenPipe, error.EndOfStream => |reason| {
|
||||
std.log.info("{s} restart required: {t}", .{ argv[0], reason });
|
||||
|
|
@ -426,7 +437,7 @@ pub fn evalZigProcess(
|
|||
return s.fail("unable to wait for {s}: {t}", .{ argv[0], e });
|
||||
};
|
||||
_ = term;
|
||||
s.clearZigProcess(gpa);
|
||||
exited = true;
|
||||
break :update;
|
||||
},
|
||||
else => |e| return e,
|
||||
|
|
@ -442,7 +453,7 @@ pub fn evalZigProcess(
|
|||
return s.fail("unable to wait for {s}: {t}", .{ argv[0], e });
|
||||
};
|
||||
s.result_peak_rss = zp.child.resource_usage_statistics.getMaxRss() orelse 0;
|
||||
s.clearZigProcess(gpa);
|
||||
exited = true;
|
||||
try handleChildProcessTerm(s, term);
|
||||
return error.MakeFailed;
|
||||
}
|
||||
|
|
@ -467,19 +478,16 @@ pub fn evalZigProcess(
|
|||
.progress_node = prog_node,
|
||||
}) catch |err| return s.fail("failed to spawn zig compiler {s}: {t}", .{ argv[0], err });
|
||||
|
||||
zp.* = .{
|
||||
.child = zp.child,
|
||||
.multi_reader_buffer = undefined,
|
||||
.multi_reader = undefined,
|
||||
.progress_ipc_fd = if (std.Progress.have_ipc) prog_node.getIpcFd() else {},
|
||||
};
|
||||
zp.multi_reader.init(gpa, io, zp.multi_reader_buffer.toStreams(), &.{
|
||||
zp.child.stdout.?, zp.child.stderr.?,
|
||||
});
|
||||
if (watch) s.setZigProcess(zp);
|
||||
if (watch) s.cast(Compile).?.zig_process = zp;
|
||||
defer if (!watch) zp.deinit(io);
|
||||
|
||||
const result = try zigProcessUpdate(s, zp, watch, web_server, gpa);
|
||||
const result = result: {
|
||||
defer if (watch) zp.saveState(prog_node);
|
||||
break :result try zigProcessUpdate(s, zp, watch, web_server, gpa);
|
||||
};
|
||||
|
||||
if (!watch) {
|
||||
// Send EOF to stdin.
|
||||
|
|
@ -670,26 +678,6 @@ pub fn getZigProcess(s: *Step) ?*ZigProcess {
|
|||
};
|
||||
}
|
||||
|
||||
fn setZigProcess(s: *Step, zp: *ZigProcess) void {
|
||||
switch (s.id) {
|
||||
.compile => s.cast(Compile).?.zig_process = zp,
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
|
||||
fn clearZigProcess(s: *Step, gpa: Allocator) void {
|
||||
switch (s.id) {
|
||||
.compile => {
|
||||
const compile = s.cast(Compile).?;
|
||||
if (compile.zig_process) |zp| {
|
||||
gpa.destroy(zp);
|
||||
compile.zig_process = null;
|
||||
}
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
|
||||
fn sendMessage(io: Io, file: Io.File, tag: std.zig.Client.Message.Tag) !void {
|
||||
const header: std.zig.Client.Message.Header = .{
|
||||
.tag = tag,
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ const Alignment = std.mem.Alignment;
|
|||
const assert = std.debug.assert;
|
||||
const posix = std.posix;
|
||||
const windows = std.os.windows;
|
||||
const ws2_32 = std.os.windows.ws2_32;
|
||||
const ws2_32 = windows.ws2_32;
|
||||
|
||||
/// Thread-safe.
|
||||
///
|
||||
|
|
@ -2609,8 +2609,7 @@ fn batchAwaitAsync(userdata: ?*anyopaque, b: *Io.Batch) Io.Cancelable!void {
|
|||
// opportunity to find additional ready operations.
|
||||
break :t 0;
|
||||
}
|
||||
const max_poll_ms = std.math.maxInt(i32);
|
||||
break :t max_poll_ms;
|
||||
break :t std.math.maxInt(i32);
|
||||
};
|
||||
const syscall = try Syscall.start();
|
||||
const rc = posix.system.poll(&poll_buffer, poll_len, timeout_ms);
|
||||
|
|
@ -2730,6 +2729,7 @@ fn batchAwaitConcurrent(userdata: ?*anyopaque, b: *Io.Batch, timeout: Io.Timeout
|
|||
break :allocation allocation;
|
||||
};
|
||||
@memcpy(slice[0..poll_buffer_len], storage.slice);
|
||||
storage.slice = slice;
|
||||
}
|
||||
storage.slice[len] = .{
|
||||
.fd = file.handle,
|
||||
|
|
@ -2783,9 +2783,7 @@ fn batchAwaitConcurrent(userdata: ?*anyopaque, b: *Io.Batch, timeout: Io.Timeout
|
|||
}
|
||||
const d = deadline orelse break :t -1;
|
||||
const duration = d.durationFromNow(t_io);
|
||||
if (duration.raw.nanoseconds <= 0) return error.Timeout;
|
||||
const max_poll_ms = std.math.maxInt(i32);
|
||||
break :t @intCast(@min(max_poll_ms, duration.raw.toMilliseconds()));
|
||||
break :t @min(@max(0, duration.raw.toMilliseconds()), std.math.maxInt(i32));
|
||||
};
|
||||
const syscall = try Syscall.start();
|
||||
const rc = posix.system.poll(&poll_buffer, poll_storage.len, timeout_ms);
|
||||
|
|
@ -14420,7 +14418,10 @@ const WindowsEnvironStrings = struct {
|
|||
PATHEXT: ?[:0]const u16 = null,
|
||||
|
||||
fn scan() WindowsEnvironStrings {
|
||||
const ptr = windows.peb().ProcessParameters.Environment;
|
||||
const peb = windows.peb();
|
||||
assert(windows.ntdll.RtlEnterCriticalSection(peb.FastPebLock) == .SUCCESS);
|
||||
defer assert(windows.ntdll.RtlLeaveCriticalSection(peb.FastPebLock) == .SUCCESS);
|
||||
const ptr = peb.ProcessParameters.Environment;
|
||||
|
||||
var result: WindowsEnvironStrings = .{};
|
||||
var i: usize = 0;
|
||||
|
|
@ -14446,7 +14447,7 @@ const WindowsEnvironStrings = struct {
|
|||
|
||||
inline for (@typeInfo(WindowsEnvironStrings).@"struct".fields) |field| {
|
||||
const field_name_w = comptime std.unicode.wtf8ToWtf16LeStringLiteral(field.name);
|
||||
if (std.os.windows.eqlIgnoreCaseWtf16(key_w, field_name_w)) @field(result, field.name) = value_w;
|
||||
if (windows.eqlIgnoreCaseWtf16(key_w, field_name_w)) @field(result, field.name) = value_w;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -14465,29 +14466,46 @@ fn scanEnviron(t: *Threaded) void {
|
|||
// This value expires with any call that modifies the environment,
|
||||
// which is outside of this Io implementation's control, so references
|
||||
// must be short-lived.
|
||||
const ptr = windows.peb().ProcessParameters.Environment;
|
||||
const peb = windows.peb();
|
||||
assert(windows.ntdll.RtlEnterCriticalSection(peb.FastPebLock) == .SUCCESS);
|
||||
defer assert(windows.ntdll.RtlLeaveCriticalSection(peb.FastPebLock) == .SUCCESS);
|
||||
const ptr = peb.ProcessParameters.Environment;
|
||||
|
||||
var i: usize = 0;
|
||||
while (ptr[i] != 0) {
|
||||
const key_start = i;
|
||||
|
||||
// There are some special environment variables that start with =,
|
||||
// so we need a special case to not treat = as a key/value separator
|
||||
// if it's the first character.
|
||||
// https://devblogs.microsoft.com/oldnewthing/20100506-00/?p=14133
|
||||
if (ptr[key_start] == '=') i += 1;
|
||||
|
||||
const key_start = i;
|
||||
if (ptr[i] == '=') i += 1;
|
||||
while (ptr[i] != 0 and ptr[i] != '=') : (i += 1) {}
|
||||
const key_w = ptr[key_start..i];
|
||||
if (std.mem.eql(u16, key_w, &.{ 'N', 'O', '_', 'C', 'O', 'L', 'O', 'R' })) {
|
||||
|
||||
const value_start = i + 1;
|
||||
while (ptr[i] != 0) : (i += 1) {} // skip over '=' and value
|
||||
const value_w = ptr[value_start..i];
|
||||
i += 1; // skip over null byte
|
||||
|
||||
if (windows.eqlIgnoreCaseWtf16(key_w, &.{ 'N', 'O', '_', 'C', 'O', 'L', 'O', 'R' })) {
|
||||
t.environ.exist.NO_COLOR = true;
|
||||
} else if (std.mem.eql(u16, key_w, &.{ 'C', 'L', 'I', 'C', 'O', 'L', 'O', 'R', '_', 'F', 'O', 'R', 'C', 'E' })) {
|
||||
} else if (windows.eqlIgnoreCaseWtf16(key_w, &.{ 'C', 'L', 'I', 'C', 'O', 'L', 'O', 'R', '_', 'F', 'O', 'R', 'C', 'E' })) {
|
||||
t.environ.exist.CLICOLOR_FORCE = true;
|
||||
} else if (windows.eqlIgnoreCaseWtf16(key_w, &.{ 'Z', 'I', 'G', '_', 'P', 'R', 'O', 'G', 'R', 'E', 'S', 'S' })) {
|
||||
t.environ.zig_progress_file = file: {
|
||||
var value_buf: [std.fmt.count("{d}", .{std.math.maxInt(usize)})]u8 = undefined;
|
||||
const len = std.unicode.calcWtf8Len(value_w);
|
||||
if (len > value_buf.len) break :file error.UnrecognizedFormat;
|
||||
assert(std.unicode.wtf16LeToWtf8(&value_buf, value_w) == len);
|
||||
break :file .{
|
||||
.handle = @ptrFromInt(std.fmt.parseInt(usize, value_buf[0..len], 10) catch
|
||||
break :file error.UnrecognizedFormat),
|
||||
.flags = .{ .nonblocking = true },
|
||||
};
|
||||
};
|
||||
}
|
||||
comptime assert(@sizeOf(Environ.String) == 0);
|
||||
|
||||
while (ptr[i] != 0) : (i += 1) {} // skip over '=' and value
|
||||
i += 1; // skip over null byte
|
||||
}
|
||||
} else if (native_os == .wasi and !builtin.link_libc) {
|
||||
var environ_count: usize = undefined;
|
||||
|
|
@ -14549,20 +14567,9 @@ fn scanEnviron(t: *Threaded) void {
|
|||
t.environ.exist.CLICOLOR_FORCE = true;
|
||||
} else if (std.mem.eql(u8, key, "ZIG_PROGRESS")) {
|
||||
t.environ.zig_progress_file = file: {
|
||||
const int = std.fmt.parseInt(switch (@typeInfo(File.Handle)) {
|
||||
.int => |int_info| @Int(
|
||||
.unsigned,
|
||||
int_info.bits - @intFromBool(int_info.signedness == .signed),
|
||||
),
|
||||
.pointer => usize,
|
||||
else => break :file error.UnsupportedOperation,
|
||||
}, value, 10) catch break :file error.UnrecognizedFormat;
|
||||
break :file .{
|
||||
.handle = switch (@typeInfo(File.Handle)) {
|
||||
.int => int,
|
||||
.pointer => @ptrFromInt(int),
|
||||
else => comptime unreachable,
|
||||
},
|
||||
.handle = std.fmt.parseInt(u31, value, 10) catch
|
||||
break :file error.UnrecognizedFormat,
|
||||
.flags = .{ .nonblocking = true },
|
||||
};
|
||||
};
|
||||
|
|
@ -14668,16 +14675,17 @@ fn spawnPosix(t: *Threaded, options: process.SpawnOptions) process.SpawnError!Sp
|
|||
const any_ignore = (options.stdin == .ignore or options.stdout == .ignore or options.stderr == .ignore);
|
||||
const dev_null_fd = if (any_ignore) try getDevNullFd(t) else undefined;
|
||||
|
||||
const prog_pipe: [2]posix.fd_t = p: {
|
||||
if (options.progress_node.index == .none) {
|
||||
break :p .{ -1, -1 };
|
||||
} else {
|
||||
// We use CLOEXEC for the same reason as in `pipe_flags`.
|
||||
break :p try pipe2(.{ .NONBLOCK = true, .CLOEXEC = true });
|
||||
}
|
||||
};
|
||||
const prog_pipe: [2]posix.fd_t = if (options.progress_node.index != .none)
|
||||
// We use CLOEXEC for the same reason as in `pipe_flags`.
|
||||
try pipe2(.{ .NONBLOCK = true, .CLOEXEC = true })
|
||||
else
|
||||
.{ -1, -1 };
|
||||
errdefer destroyPipe(prog_pipe);
|
||||
|
||||
if (native_os == .linux and prog_pipe[0] != -1) {
|
||||
_ = posix.system.fcntl(prog_pipe[0], posix.F.SETPIPE_SZ, @as(u32, std.Progress.max_packet_len * 2));
|
||||
}
|
||||
|
||||
var arena_allocator = std.heap.ArenaAllocator.init(t.allocator);
|
||||
defer arena_allocator.deinit();
|
||||
const arena = arena_allocator.allocator();
|
||||
|
|
@ -14801,7 +14809,7 @@ fn spawnPosix(t: *Threaded, options: process.SpawnOptions) process.SpawnError!Sp
|
|||
if (options.stderr == .pipe) posix.close(stderr_pipe[1]);
|
||||
|
||||
if (prog_pipe[1] != -1) posix.close(prog_pipe[1]);
|
||||
options.progress_node.setIpcFd(prog_pipe[0]);
|
||||
options.progress_node.setIpcFile(t, .{ .handle = prog_pipe[0], .flags = .{ .nonblocking = true } });
|
||||
|
||||
return .{
|
||||
.pid = pid,
|
||||
|
|
@ -15259,8 +15267,9 @@ fn processSpawnWindows(userdata: ?*anyopaque, options: process.SpawnOptions) pro
|
|||
|
||||
const prog_pipe = if (options.progress_node.index != .none) try t.windowsCreatePipe(.{
|
||||
.server = .{ .attributes = .{ .INHERIT = false }, .mode = .{ .IO = .ASYNCHRONOUS } },
|
||||
.client = .{ .attributes = .{ .INHERIT = true }, .mode = .{ .IO = .SYNCHRONOUS_NONALERT } },
|
||||
.client = .{ .attributes = .{ .INHERIT = true }, .mode = .{ .IO = .ASYNCHRONOUS } },
|
||||
.inbound = true,
|
||||
.quota = std.Progress.max_packet_len * 2,
|
||||
}) else undefined;
|
||||
errdefer if (options.progress_node.index != .none) for (prog_pipe) |handle| windows.CloseHandle(handle);
|
||||
|
||||
|
|
@ -15476,7 +15485,7 @@ fn processSpawnWindows(userdata: ?*anyopaque, options: process.SpawnOptions) pro
|
|||
|
||||
if (options.progress_node.index != .none) {
|
||||
windows.CloseHandle(prog_pipe[1]);
|
||||
options.progress_node.setIpcFd(prog_pipe[0]);
|
||||
options.progress_node.setIpcFile(t, .{ .handle = prog_pipe[0], .flags = .{ .nonblocking = true } });
|
||||
}
|
||||
|
||||
return .{
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -1848,6 +1848,24 @@ pub const F = struct {
|
|||
pub const RDLCK = if (is_sparc) 1 else 0;
|
||||
pub const WRLCK = if (is_sparc) 2 else 1;
|
||||
pub const UNLCK = if (is_sparc) 3 else 2;
|
||||
|
||||
pub const LINUX_SPECIFIC_BASE = 1024;
|
||||
|
||||
pub const SETLEASE = LINUX_SPECIFIC_BASE + 0;
|
||||
pub const GETLEASE = LINUX_SPECIFIC_BASE + 1;
|
||||
pub const NOTIFY = LINUX_SPECIFIC_BASE + 2;
|
||||
pub const DUPFD_QUERY = LINUX_SPECIFIC_BASE + 3;
|
||||
pub const CREATED_QUERY = LINUX_SPECIFIC_BASE + 4;
|
||||
pub const CANCELLK = LINUX_SPECIFIC_BASE + 5;
|
||||
pub const DUPFD_CLOEXEC = LINUX_SPECIFIC_BASE + 6;
|
||||
pub const SETPIPE_SZ = LINUX_SPECIFIC_BASE + 7;
|
||||
pub const GETPIPE_SZ = LINUX_SPECIFIC_BASE + 8;
|
||||
pub const ADD_SEALS = LINUX_SPECIFIC_BASE + 9;
|
||||
pub const GET_SEALS = LINUX_SPECIFIC_BASE + 10;
|
||||
pub const GET_RW_HINT = LINUX_SPECIFIC_BASE + 11;
|
||||
pub const SET_RW_HINT = LINUX_SPECIFIC_BASE + 12;
|
||||
pub const GET_FILE_RW_HINT = LINUX_SPECIFIC_BASE + 13;
|
||||
pub const SET_FILE_RW_HINT = LINUX_SPECIFIC_BASE + 14;
|
||||
};
|
||||
|
||||
pub const F_OWNER = enum(i32) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue