stage2: avoid linux-only APIs on other operating systems

This commit is contained in:
Andrew Kelley 2023-03-02 22:37:07 -07:00
parent 7ffdbb3b85
commit 9bf63b0996
5 changed files with 57 additions and 38 deletions

View file

@ -1847,7 +1847,7 @@ fn cleanupTmpArtifactDirectory(
}
}
pub fn hotCodeSwap(comp: *Compilation, prog_node: *std.Progress.Node, pid: std.os.pid_t) !void {
pub fn hotCodeSwap(comp: *Compilation, prog_node: *std.Progress.Node, pid: std.ChildProcess.Id) !void {
comp.bin_file.child_pid = pid;
try comp.makeBinFileWritable();
try comp.update(prog_node);

View file

@ -264,7 +264,7 @@ pub const File = struct {
/// of this linking operation.
lock: ?Cache.Lock = null,
child_pid: ?std.os.pid_t = null,
child_pid: ?std.ChildProcess.Id = null,
/// Attempts incremental linking, if the file already exists. If
/// incremental linking fails, falls back to truncating the file and
@ -388,10 +388,14 @@ pub const File = struct {
});
try emit.directory.handle.copyFile(emit.sub_path, emit.directory.handle, tmp_sub_path, .{});
try emit.directory.handle.rename(tmp_sub_path, emit.sub_path);
switch (std.os.errno(std.os.linux.ptrace(std.os.linux.PTRACE.ATTACH, pid, 0, 0, 0))) {
.SUCCESS => {},
else => |errno| log.warn("ptrace failure: {s}", .{@tagName(errno)}),
switch (builtin.os.tag) {
.linux => {
switch (std.os.errno(std.os.linux.ptrace(std.os.linux.PTRACE.ATTACH, pid, 0, 0, 0))) {
.SUCCESS => {},
else => |errno| log.warn("ptrace failure: {s}", .{@tagName(errno)}),
}
},
else => return error.HotSwapUnavailableOnHostOperatingSystem,
}
}
base.file = try emit.directory.handle.createFile(emit.sub_path, .{
@ -444,9 +448,14 @@ pub const File = struct {
base.file = null;
if (base.child_pid) |pid| {
switch (std.os.errno(std.os.linux.ptrace(std.os.linux.PTRACE.DETACH, pid, 0, 0, 0))) {
.SUCCESS => {},
else => |errno| log.warn("ptrace failure: {s}", .{@tagName(errno)}),
switch (builtin.os.tag) {
.linux => {
switch (std.os.errno(std.os.linux.ptrace(std.os.linux.PTRACE.DETACH, pid, 0, 0, 0))) {
.SUCCESS => {},
else => |errno| log.warn("ptrace failure: {s}", .{@tagName(errno)}),
}
},
else => return error.HotSwapUnavailableOnHostOperatingSystem,
}
}
},
@ -487,6 +496,7 @@ pub const File = struct {
NetNameDeleted,
DeviceBusy,
InvalidArgument,
HotSwapUnavailableOnHostOperatingSystem,
};
/// Called from within the CodeGen to lower a local variable instantion as an unnamed

View file

@ -2453,18 +2453,23 @@ fn updateDeclCode(self: *Elf, decl_index: Module.Decl.Index, code: []const u8, s
const file_offset = self.sections.items(.shdr)[shdr_index].sh_offset + section_offset;
if (self.base.child_pid) |pid| {
var code_vec: [1]std.os.iovec_const = .{.{
.iov_base = code.ptr,
.iov_len = code.len,
}};
var remote_vec: [1]std.os.iovec_const = .{.{
.iov_base = @intToPtr([*]u8, local_sym.st_value),
.iov_len = code.len,
}};
const rc = std.os.linux.process_vm_writev(pid, &code_vec, &remote_vec, 0);
switch (std.os.errno(rc)) {
.SUCCESS => assert(rc == code.len),
else => |errno| log.warn("process_vm_writev failure: {s}", .{@tagName(errno)}),
switch (builtin.os.tag) {
.linux => {
var code_vec: [1]std.os.iovec_const = .{.{
.iov_base = code.ptr,
.iov_len = code.len,
}};
var remote_vec: [1]std.os.iovec_const = .{.{
.iov_base = @intToPtr([*]u8, local_sym.st_value),
.iov_len = code.len,
}};
const rc = std.os.linux.process_vm_writev(pid, &code_vec, &remote_vec, 0);
switch (std.os.errno(rc)) {
.SUCCESS => assert(rc == code.len),
else => |errno| log.warn("process_vm_writev failure: {s}", .{@tagName(errno)}),
}
},
else => return error.HotSwapUnavailableOnHostOperatingSystem,
}
}
@ -2856,18 +2861,23 @@ fn writeOffsetTableEntry(self: *Elf, index: usize) !void {
try self.base.file.?.pwriteAll(&buf, off);
if (self.base.child_pid) |pid| {
var local_vec: [1]std.os.iovec_const = .{.{
.iov_base = &buf,
.iov_len = buf.len,
}};
var remote_vec: [1]std.os.iovec_const = .{.{
.iov_base = @intToPtr([*]u8, vaddr),
.iov_len = buf.len,
}};
const rc = std.os.linux.process_vm_writev(pid, &local_vec, &remote_vec, 0);
switch (std.os.errno(rc)) {
.SUCCESS => assert(rc == buf.len),
else => |errno| log.warn("process_vm_writev failure: {s}", .{@tagName(errno)}),
switch (builtin.os.tag) {
.linux => {
var local_vec: [1]std.os.iovec_const = .{.{
.iov_base = &buf,
.iov_len = buf.len,
}};
var remote_vec: [1]std.os.iovec_const = .{.{
.iov_base = @intToPtr([*]u8, vaddr),
.iov_len = buf.len,
}};
const rc = std.os.linux.process_vm_writev(pid, &local_vec, &remote_vec, 0);
switch (std.os.errno(rc)) {
.SUCCESS => assert(rc == buf.len),
else => |errno| log.warn("process_vm_writev failure: {s}", .{@tagName(errno)}),
}
},
else => return error.HotSwapUnavailableOnHostOperatingSystem,
}
}
},

View file

@ -3534,7 +3534,7 @@ fn serve(
try serveStringMessage(out, .zig_version, build_options.version);
var child_pid: ?i32 = null;
var child_pid: ?std.ChildProcess.Id = null;
var receive_fifo = std.fifo.LinearFifo(u8, .Dynamic).init(gpa);
defer receive_fifo.deinit();
@ -3978,7 +3978,7 @@ fn runOrTestHotSwap(
arg_mode: ArgMode,
all_args: []const []const u8,
runtime_args_start: ?usize,
) !i32 {
) !std.ChildProcess.Id {
const exe_emit = comp.bin_file.options.emit.?;
// A naive `directory.join` here will indeed get the correct path to the binary,
// however, in the case of cwd, we actually want `./foo` so that the path can be executed.
@ -4023,7 +4023,7 @@ fn runOrTestHotSwap(
try child.spawn();
return child.pid;
return child.id;
}
const AfterUpdateHook = union(enum) {

View file

@ -1606,9 +1606,8 @@ pub const TestContext = struct {
var module_node = update_node.start("parse/analysis/codegen", 0);
module_node.activate();
module_node.context.refresh();
try comp.makeBinFileWritable();
try comp.update();
try comp.update(&module_node);
module_node.end();
if (update.case != .Error) {