From 9bf63b09963ca6ea1179dfaa9142498556bfac9d Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 2 Mar 2023 22:37:07 -0700 Subject: [PATCH] stage2: avoid linux-only APIs on other operating systems --- src/Compilation.zig | 2 +- src/link.zig | 26 +++++++++++++------- src/link/Elf.zig | 58 ++++++++++++++++++++++++++------------------- src/main.zig | 6 ++--- src/test.zig | 3 +-- 5 files changed, 57 insertions(+), 38 deletions(-) diff --git a/src/Compilation.zig b/src/Compilation.zig index 478f931718..28e7c43702 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -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); diff --git a/src/link.zig b/src/link.zig index 96931dd79e..e68f9c97d0 100644 --- a/src/link.zig +++ b/src/link.zig @@ -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 diff --git a/src/link/Elf.zig b/src/link/Elf.zig index b849dcc9d2..5943277908 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -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, } } }, diff --git a/src/main.zig b/src/main.zig index 6bf7177a9e..70051d2cc7 100644 --- a/src/main.zig +++ b/src/main.zig @@ -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) { diff --git a/src/test.zig b/src/test.zig index 663c4f1aff..5b73e516c6 100644 --- a/src/test.zig +++ b/src/test.zig @@ -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) {