authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-03-02 22:37:07-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-03-15 10:48:13-07:00
log9bf63b09963ca6ea1179dfaa9142498556bfac9d
tree61bc3e7308c21eb2dab6432a358be97e896edb1b
parent7ffdbb3b855ef9e4aa25a8ac911fce752a71e16d

stage2: avoid linux-only APIs on other operating systems


5 files changed, 57 insertions(+), 38 deletions(-)

src/Compilation.zig+1-1
......@@ -1847,7 +1847,7 @@ fn cleanupTmpArtifactDirectory(
18471847 }
18481848}
18491849
1850pub fn hotCodeSwap(comp: *Compilation, prog_node: *std.Progress.Node, pid: std.os.pid_t) !void {
1850pub fn hotCodeSwap(comp: *Compilation, prog_node: *std.Progress.Node, pid: std.ChildProcess.Id) !void {
18511851 comp.bin_file.child_pid = pid;
18521852 try comp.makeBinFileWritable();
18531853 try comp.update(prog_node);
src/link.zig+18-8
......@@ -264,7 +264,7 @@ pub const File = struct {
264264 /// of this linking operation.
265265 lock: ?Cache.Lock = null,
266266
267 child_pid: ?std.os.pid_t = null,
267 child_pid: ?std.ChildProcess.Id = null,
268268
269269 /// Attempts incremental linking, if the file already exists. If
270270 /// incremental linking fails, falls back to truncating the file and
......@@ -388,10 +388,14 @@ pub const File = struct {
388388 });
389389 try emit.directory.handle.copyFile(emit.sub_path, emit.directory.handle, tmp_sub_path, .{});
390390 try emit.directory.handle.rename(tmp_sub_path, emit.sub_path);
391
392 switch (std.os.errno(std.os.linux.ptrace(std.os.linux.PTRACE.ATTACH, pid, 0, 0, 0))) {
393 .SUCCESS => {},
394 else => |errno| log.warn("ptrace failure: {s}", .{@tagName(errno)}),
391 switch (builtin.os.tag) {
392 .linux => {
393 switch (std.os.errno(std.os.linux.ptrace(std.os.linux.PTRACE.ATTACH, pid, 0, 0, 0))) {
394 .SUCCESS => {},
395 else => |errno| log.warn("ptrace failure: {s}", .{@tagName(errno)}),
396 }
397 },
398 else => return error.HotSwapUnavailableOnHostOperatingSystem,
395399 }
396400 }
397401 base.file = try emit.directory.handle.createFile(emit.sub_path, .{
......@@ -444,9 +448,14 @@ pub const File = struct {
444448 base.file = null;
445449
446450 if (base.child_pid) |pid| {
447 switch (std.os.errno(std.os.linux.ptrace(std.os.linux.PTRACE.DETACH, pid, 0, 0, 0))) {
448 .SUCCESS => {},
449 else => |errno| log.warn("ptrace failure: {s}", .{@tagName(errno)}),
451 switch (builtin.os.tag) {
452 .linux => {
453 switch (std.os.errno(std.os.linux.ptrace(std.os.linux.PTRACE.DETACH, pid, 0, 0, 0))) {
454 .SUCCESS => {},
455 else => |errno| log.warn("ptrace failure: {s}", .{@tagName(errno)}),
456 }
457 },
458 else => return error.HotSwapUnavailableOnHostOperatingSystem,
450459 }
451460 }
452461 },
......@@ -487,6 +496,7 @@ pub const File = struct {
487496 NetNameDeleted,
488497 DeviceBusy,
489498 InvalidArgument,
499 HotSwapUnavailableOnHostOperatingSystem,
490500 };
491501
492502 /// Called from within the CodeGen to lower a local variable instantion as an unnamed
src/link/Elf.zig+34-24
......@@ -2453,18 +2453,23 @@ fn updateDeclCode(self: *Elf, decl_index: Module.Decl.Index, code: []const u8, s
24532453 const file_offset = self.sections.items(.shdr)[shdr_index].sh_offset + section_offset;
24542454
24552455 if (self.base.child_pid) |pid| {
2456 var code_vec: [1]std.os.iovec_const = .{.{
2457 .iov_base = code.ptr,
2458 .iov_len = code.len,
2459 }};
2460 var remote_vec: [1]std.os.iovec_const = .{.{
2461 .iov_base = @intToPtr([*]u8, local_sym.st_value),
2462 .iov_len = code.len,
2463 }};
2464 const rc = std.os.linux.process_vm_writev(pid, &code_vec, &remote_vec, 0);
2465 switch (std.os.errno(rc)) {
2466 .SUCCESS => assert(rc == code.len),
2467 else => |errno| log.warn("process_vm_writev failure: {s}", .{@tagName(errno)}),
2456 switch (builtin.os.tag) {
2457 .linux => {
2458 var code_vec: [1]std.os.iovec_const = .{.{
2459 .iov_base = code.ptr,
2460 .iov_len = code.len,
2461 }};
2462 var remote_vec: [1]std.os.iovec_const = .{.{
2463 .iov_base = @intToPtr([*]u8, local_sym.st_value),
2464 .iov_len = code.len,
2465 }};
2466 const rc = std.os.linux.process_vm_writev(pid, &code_vec, &remote_vec, 0);
2467 switch (std.os.errno(rc)) {
2468 .SUCCESS => assert(rc == code.len),
2469 else => |errno| log.warn("process_vm_writev failure: {s}", .{@tagName(errno)}),
2470 }
2471 },
2472 else => return error.HotSwapUnavailableOnHostOperatingSystem,
24682473 }
24692474 }
24702475
......@@ -2856,18 +2861,23 @@ fn writeOffsetTableEntry(self: *Elf, index: usize) !void {
28562861 try self.base.file.?.pwriteAll(&buf, off);
28572862
28582863 if (self.base.child_pid) |pid| {
2859 var local_vec: [1]std.os.iovec_const = .{.{
2860 .iov_base = &buf,
2861 .iov_len = buf.len,
2862 }};
2863 var remote_vec: [1]std.os.iovec_const = .{.{
2864 .iov_base = @intToPtr([*]u8, vaddr),
2865 .iov_len = buf.len,
2866 }};
2867 const rc = std.os.linux.process_vm_writev(pid, &local_vec, &remote_vec, 0);
2868 switch (std.os.errno(rc)) {
2869 .SUCCESS => assert(rc == buf.len),
2870 else => |errno| log.warn("process_vm_writev failure: {s}", .{@tagName(errno)}),
2864 switch (builtin.os.tag) {
2865 .linux => {
2866 var local_vec: [1]std.os.iovec_const = .{.{
2867 .iov_base = &buf,
2868 .iov_len = buf.len,
2869 }};
2870 var remote_vec: [1]std.os.iovec_const = .{.{
2871 .iov_base = @intToPtr([*]u8, vaddr),
2872 .iov_len = buf.len,
2873 }};
2874 const rc = std.os.linux.process_vm_writev(pid, &local_vec, &remote_vec, 0);
2875 switch (std.os.errno(rc)) {
2876 .SUCCESS => assert(rc == buf.len),
2877 else => |errno| log.warn("process_vm_writev failure: {s}", .{@tagName(errno)}),
2878 }
2879 },
2880 else => return error.HotSwapUnavailableOnHostOperatingSystem,
28712881 }
28722882 }
28732883 },
src/main.zig+3-3
......@@ -3534,7 +3534,7 @@ fn serve(
35343534
35353535 try serveStringMessage(out, .zig_version, build_options.version);
35363536
3537 var child_pid: ?i32 = null;
3537 var child_pid: ?std.ChildProcess.Id = null;
35383538 var receive_fifo = std.fifo.LinearFifo(u8, .Dynamic).init(gpa);
35393539 defer receive_fifo.deinit();
35403540
......@@ -3978,7 +3978,7 @@ fn runOrTestHotSwap(
39783978 arg_mode: ArgMode,
39793979 all_args: []const []const u8,
39803980 runtime_args_start: ?usize,
3981) !i32 {
3981) !std.ChildProcess.Id {
39823982 const exe_emit = comp.bin_file.options.emit.?;
39833983 // A naive `directory.join` here will indeed get the correct path to the binary,
39843984 // however, in the case of cwd, we actually want `./foo` so that the path can be executed.
......@@ -4023,7 +4023,7 @@ fn runOrTestHotSwap(
40234023
40244024 try child.spawn();
40254025
4026 return child.pid;
4026 return child.id;
40274027}
40284028
40294029const AfterUpdateHook = union(enum) {
src/test.zig+1-2
......@@ -1606,9 +1606,8 @@ pub const TestContext = struct {
16061606
16071607 var module_node = update_node.start("parse/analysis/codegen", 0);
16081608 module_node.activate();
1609 module_node.context.refresh();
16101609 try comp.makeBinFileWritable();
1611 try comp.update();
1610 try comp.update(&module_node);
16121611 module_node.end();
16131612
16141613 if (update.case != .Error) {