diff --git a/lib/std/Io/Threaded.zig b/lib/std/Io/Threaded.zig index 7b5d765bbf..2af24dbf17 100644 --- a/lib/std/Io/Threaded.zig +++ b/lib/std/Io/Threaded.zig @@ -2081,6 +2081,10 @@ fn dirOpenFileWindowsInner( const create_file_flags: w.ULONG = file_or_dir_flag | if (flags.follow_symlinks) blocking_flag else w.FILE_OPEN_REPARSE_POINT; + // There are multiple kernel bugs being worked around with retries. + const max_attempts = 13; + var attempt: u5 = 0; + const handle = while (true) { try t.checkCancel(); @@ -2110,7 +2114,17 @@ fn dirOpenFileWindowsInner( .NO_MEDIA_IN_DEVICE => return error.NoDevice, .INVALID_PARAMETER => |err| return w.statusBug(err), .SHARING_VIOLATION => return error.AccessDenied, - .ACCESS_DENIED => return error.AccessDenied, + .ACCESS_DENIED => { + // This occurs if the file attempting to be opened is a running + // executable. However, there's a kernel bug: the error may be + // incorrectly returned for an indeterminate amount of time + // after an executable file is closed. Here we work around the + // kernel bug with retry attempts. + if (attempt - max_attempts == 0) return error.AccessDenied; + _ = w.kernel32.SleepEx((@as(u32, 1) << attempt) >> 1, w.TRUE); + attempt += 1; + continue; + }, .PIPE_BUSY => return error.PipeBusy, .PIPE_NOT_AVAILABLE => return error.NoDevice, .OBJECT_PATH_SYNTAX_BAD => |err| return w.statusBug(err), @@ -2123,10 +2137,11 @@ fn dirOpenFileWindowsInner( // This error means that there *was* a file in this location on // the file system, but it was deleted. However, the OS is not // finished with the deletion operation, and so this CreateFile - // call has failed. There is not really a sane way to handle - // this other than retrying the creation after the OS finishes - // the deletion. - _ = w.kernel32.SleepEx(1, w.FALSE); + // call has failed. Here, we simulate the kernel bug being + // fixed by sleeping and retrying until the error goes away. + if (attempt - max_attempts == 0) return error.AccessDenied; + _ = w.kernel32.SleepEx((@as(u32, 1) << attempt) >> 1, w.TRUE); + attempt += 1; continue; }, .VIRUS_INFECTED, .VIRUS_DELETED => return error.AntivirusInterference, diff --git a/src/link.zig b/src/link.zig index a0acce1073..485384e05d 100644 --- a/src/link.zig +++ b/src/link.zig @@ -1,19 +1,22 @@ -const std = @import("std"); -const build_options = @import("build_options"); const builtin = @import("builtin"); +const build_options = @import("build_options"); + +const std = @import("std"); +const Io = std.Io; const assert = std.debug.assert; const fs = std.fs; const mem = std.mem; const log = std.log.scoped(.link); -const trace = @import("tracy.zig").trace; -const wasi_libc = @import("libs/wasi_libc.zig"); - const Allocator = std.mem.Allocator; const Cache = std.Build.Cache; const Path = std.Build.Cache.Path; const Directory = std.Build.Cache.Directory; const Compilation = @import("Compilation.zig"); const LibCInstallation = std.zig.LibCInstallation; + +const trace = @import("tracy.zig").trace; +const wasi_libc = @import("libs/wasi_libc.zig"); + const Zcu = @import("Zcu.zig"); const InternPool = @import("InternPool.zig"); const Type = @import("Type.zig"); @@ -572,6 +575,7 @@ pub const File = struct { dev.check(.make_writable); const comp = base.comp; const gpa = comp.gpa; + const io = comp.io; switch (base.tag) { .lld => assert(base.file == null), .elf, .macho, .wasm, .goff, .xcoff => { @@ -616,22 +620,9 @@ pub const File = struct { &coff.mf else unreachable; - var attempt: u5 = 0; - mf.file = while (true) break base.emit.root_dir.handle.openFile(base.emit.sub_path, .{ + mf.file = .adaptFromNewApi(try Io.Dir.openFile(base.emit.root_dir.handle.adaptToNewApi(), io, base.emit.sub_path, .{ .mode = .read_write, - }) catch |err| switch (err) { - error.AccessDenied => switch (builtin.os.tag) { - .windows => { - if (attempt == 13) return error.AccessDenied; - // give the kernel a chance to finish closing the executable handle - std.os.windows.kernel32.Sleep(@as(u32, 1) << attempt >> 1); - attempt += 1; - continue; - }, - else => return error.AccessDenied, - }, - else => |e| return e, - }; + })); base.file = mf.file; try mf.ensureTotalCapacity(@intCast(mf.nodes.items[0].location().resolve(mf)[1])); },