authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-10-27 13:21:49-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-10-29 06:20:51-07:00
logdf4c30ca1631c26fce3bec1cba6a15a688745433
tree589a2a20defbcef98ed41901074285f5d60bd635
parent02119362d70bb16ae6ab00124928bde89834c83f

link: move the windows kernel bug workaround to Io implementation


2 files changed, 31 insertions(+), 25 deletions(-)

lib/std/Io/Threaded.zig+20-5
......@@ -2081,6 +2081,10 @@ fn dirOpenFileWindowsInner(
20812081 const create_file_flags: w.ULONG = file_or_dir_flag |
20822082 if (flags.follow_symlinks) blocking_flag else w.FILE_OPEN_REPARSE_POINT;
20832083
2084 // There are multiple kernel bugs being worked around with retries.
2085 const max_attempts = 13;
2086 var attempt: u5 = 0;
2087
20842088 const handle = while (true) {
20852089 try t.checkCancel();
20862090
......@@ -2110,7 +2114,17 @@ fn dirOpenFileWindowsInner(
21102114 .NO_MEDIA_IN_DEVICE => return error.NoDevice,
21112115 .INVALID_PARAMETER => |err| return w.statusBug(err),
21122116 .SHARING_VIOLATION => return error.AccessDenied,
2113 .ACCESS_DENIED => return error.AccessDenied,
2117 .ACCESS_DENIED => {
2118 // This occurs if the file attempting to be opened is a running
2119 // executable. However, there's a kernel bug: the error may be
2120 // incorrectly returned for an indeterminate amount of time
2121 // after an executable file is closed. Here we work around the
2122 // kernel bug with retry attempts.
2123 if (attempt - max_attempts == 0) return error.AccessDenied;
2124 _ = w.kernel32.SleepEx((@as(u32, 1) << attempt) >> 1, w.TRUE);
2125 attempt += 1;
2126 continue;
2127 },
21142128 .PIPE_BUSY => return error.PipeBusy,
21152129 .PIPE_NOT_AVAILABLE => return error.NoDevice,
21162130 .OBJECT_PATH_SYNTAX_BAD => |err| return w.statusBug(err),
......@@ -2123,10 +2137,11 @@ fn dirOpenFileWindowsInner(
21232137 // This error means that there *was* a file in this location on
21242138 // the file system, but it was deleted. However, the OS is not
21252139 // finished with the deletion operation, and so this CreateFile
2126 // call has failed. There is not really a sane way to handle
2127 // this other than retrying the creation after the OS finishes
2128 // the deletion.
2129 _ = w.kernel32.SleepEx(1, w.FALSE);
2140 // call has failed. Here, we simulate the kernel bug being
2141 // fixed by sleeping and retrying until the error goes away.
2142 if (attempt - max_attempts == 0) return error.AccessDenied;
2143 _ = w.kernel32.SleepEx((@as(u32, 1) << attempt) >> 1, w.TRUE);
2144 attempt += 1;
21302145 continue;
21312146 },
21322147 .VIRUS_INFECTED, .VIRUS_DELETED => return error.AntivirusInterference,
src/link.zig+11-20
......@@ -1,19 +1,22 @@
1const std = @import("std");
2const build_options = @import("build_options");
31const builtin = @import("builtin");
2const build_options = @import("build_options");
3
4const std = @import("std");
5const Io = std.Io;
46const assert = std.debug.assert;
57const fs = std.fs;
68const mem = std.mem;
79const log = std.log.scoped(.link);
8const trace = @import("tracy.zig").trace;
9const wasi_libc = @import("libs/wasi_libc.zig");
10
1110const Allocator = std.mem.Allocator;
1211const Cache = std.Build.Cache;
1312const Path = std.Build.Cache.Path;
1413const Directory = std.Build.Cache.Directory;
1514const Compilation = @import("Compilation.zig");
1615const LibCInstallation = std.zig.LibCInstallation;
16
17const trace = @import("tracy.zig").trace;
18const wasi_libc = @import("libs/wasi_libc.zig");
19
1720const Zcu = @import("Zcu.zig");
1821const InternPool = @import("InternPool.zig");
1922const Type = @import("Type.zig");
......@@ -572,6 +575,7 @@ pub const File = struct {
572575 dev.check(.make_writable);
573576 const comp = base.comp;
574577 const gpa = comp.gpa;
578 const io = comp.io;
575579 switch (base.tag) {
576580 .lld => assert(base.file == null),
577581 .elf, .macho, .wasm, .goff, .xcoff => {
......@@ -616,22 +620,9 @@ pub const File = struct {
616620 &coff.mf
617621 else
618622 unreachable;
619 var attempt: u5 = 0;
620 mf.file = while (true) break base.emit.root_dir.handle.openFile(base.emit.sub_path, .{
623 mf.file = .adaptFromNewApi(try Io.Dir.openFile(base.emit.root_dir.handle.adaptToNewApi(), io, base.emit.sub_path, .{
621624 .mode = .read_write,
622 }) catch |err| switch (err) {
623 error.AccessDenied => switch (builtin.os.tag) {
624 .windows => {
625 if (attempt == 13) return error.AccessDenied;
626 // give the kernel a chance to finish closing the executable handle
627 std.os.windows.kernel32.Sleep(@as(u32, 1) << attempt >> 1);
628 attempt += 1;
629 continue;
630 },
631 else => return error.AccessDenied,
632 },
633 else => |e| return e,
634 };
625 }));
635626 base.file = mf.file;
636627 try mf.ensureTotalCapacity(@intCast(mf.nodes.items[0].location().resolve(mf)[1]));
637628 },