authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2025-10-12 13:54:00-04:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2025-10-12 13:55:57-04:00
log958faa7031c7b50a544e151fea4d486e1c4926c1
treeeeb3f0238b95ec4c6fd1647798ae877b4701873c
parentea694bfdb762a4dd18654c73aaaaf1b917d99cc3

windows: workaround kernel race condition the most


2 files changed, 19 insertions(+), 11 deletions(-)

src/link.zig+6-3
...@@ -616,19 +616,22 @@ pub const File = struct {...@@ -616,19 +616,22 @@ pub const File = struct {
616 &coff.mf616 &coff.mf
617 else617 else
618 unreachable;618 unreachable;
619 mf.file = for (0..10) |_| break base.emit.root_dir.handle.openFile(base.emit.sub_path, .{619 var attempt: u5 = 0;
620 mf.file = while (true) break base.emit.root_dir.handle.openFile(base.emit.sub_path, .{
620 .mode = .read_write,621 .mode = .read_write,
621 }) catch |err| switch (err) {622 }) catch |err| switch (err) {
622 error.AccessDenied => switch (builtin.os.tag) {623 error.AccessDenied => switch (builtin.os.tag) {
623 .windows => {624 .windows => {
625 if (attempt == 13) return error.AccessDenied;
624 // give the kernel a chance to finish closing the executable handle626 // give the kernel a chance to finish closing the executable handle
625 std.os.windows.kernel32.Sleep(10);627 std.os.windows.kernel32.Sleep(@as(u32, 1) << attempt >> 1);
628 attempt += 1;
626 continue;629 continue;
627 },630 },
628 else => return error.AccessDenied,631 else => return error.AccessDenied,
629 },632 },
630 else => |e| return e,633 else => |e| return e,
631 } else return error.AccessDenied;634 };
632 base.file = mf.file;635 base.file = mf.file;
633 try mf.ensureTotalCapacity(@intCast(mf.nodes.items[0].location().resolve(mf)[1]));636 try mf.ensureTotalCapacity(@intCast(mf.nodes.items[0].location().resolve(mf)[1]));
634 },637 },
test/standalone/windows_spawn/main.zig+13-8
...@@ -71,14 +71,19 @@ pub fn main() anyerror!void {...@@ -71,14 +71,19 @@ pub fn main() anyerror!void {
71 try testExec(allocator, "heLLo", "hello from exe\n");71 try testExec(allocator, "heLLo", "hello from exe\n");
7272
73 // now rename the exe to not have an extension73 // now rename the exe to not have an extension
74 for (0..10) |_| break tmp.dir.rename("hello.exe", "hello") catch |err| switch (err) {74 {
75 error.AccessDenied => {75 var attempt: u5 = 0;
76 // give the kernel a chance to finish closing the executable handle76 while (true) break tmp.dir.rename("hello.exe", "hello") catch |err| switch (err) {
77 std.os.windows.kernel32.Sleep(10);77 error.AccessDenied => {
78 continue;78 if (attempt == 13) return error.AccessDenied;
79 },79 // give the kernel a chance to finish closing the executable handle
80 else => |e| return e,80 std.os.windows.kernel32.Sleep(@as(u32, 1) << attempt >> 1);
81 } else return error.AccessDenied;81 attempt += 1;
82 continue;
83 },
84 else => |e| return e,
85 };
86 }
8287
83 // with extension should now fail88 // with extension should now fail
84 try testExecError(error.FileNotFound, allocator, "hello.exe");89 try testExecError(error.FileNotFound, allocator, "hello.exe");