| author | |
| committer | |
| log | df4c30ca1631c26fce3bec1cba6a15a688745433 |
| tree | 589a2a20defbcef98ed41901074285f5d60bd635 |
| parent | 02119362d70bb16ae6ab00124928bde89834c83f |
2 files changed, 31 insertions(+), 25 deletions(-)
lib/std/Io/Threaded.zig+20-5| ... | ... | @@ -2081,6 +2081,10 @@ fn dirOpenFileWindowsInner( |
| 2081 | 2081 | const create_file_flags: w.ULONG = file_or_dir_flag | |
| 2082 | 2082 | if (flags.follow_symlinks) blocking_flag else w.FILE_OPEN_REPARSE_POINT; |
| 2083 | 2083 | |
| 2084 | // There are multiple kernel bugs being worked around with retries. | |
| 2085 | const max_attempts = 13; | |
| 2086 | var attempt: u5 = 0; | |
| 2087 | ||
| 2084 | 2088 | const handle = while (true) { |
| 2085 | 2089 | try t.checkCancel(); |
| 2086 | 2090 | |
| ... | ... | @@ -2110,7 +2114,17 @@ fn dirOpenFileWindowsInner( |
| 2110 | 2114 | .NO_MEDIA_IN_DEVICE => return error.NoDevice, |
| 2111 | 2115 | .INVALID_PARAMETER => |err| return w.statusBug(err), |
| 2112 | 2116 | .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 | }, | |
| 2114 | 2128 | .PIPE_BUSY => return error.PipeBusy, |
| 2115 | 2129 | .PIPE_NOT_AVAILABLE => return error.NoDevice, |
| 2116 | 2130 | .OBJECT_PATH_SYNTAX_BAD => |err| return w.statusBug(err), |
| ... | ... | @@ -2123,10 +2137,11 @@ fn dirOpenFileWindowsInner( |
| 2123 | 2137 | // This error means that there *was* a file in this location on |
| 2124 | 2138 | // the file system, but it was deleted. However, the OS is not |
| 2125 | 2139 | // 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; | |
| 2130 | 2145 | continue; |
| 2131 | 2146 | }, |
| 2132 | 2147 | .VIRUS_INFECTED, .VIRUS_DELETED => return error.AntivirusInterference, |
src/link.zig+11-20| ... | ... | @@ -1,19 +1,22 @@ |
| 1 | const std = @import("std"); | |
| 2 | const build_options = @import("build_options"); | |
| 3 | 1 | const builtin = @import("builtin"); |
| 2 | const build_options = @import("build_options"); | |
| 3 | ||
| 4 | const std = @import("std"); | |
| 5 | const Io = std.Io; | |
| 4 | 6 | const assert = std.debug.assert; |
| 5 | 7 | const fs = std.fs; |
| 6 | 8 | const mem = std.mem; |
| 7 | 9 | const log = std.log.scoped(.link); |
| 8 | const trace = @import("tracy.zig").trace; | |
| 9 | const wasi_libc = @import("libs/wasi_libc.zig"); | |
| 10 | ||
| 11 | 10 | const Allocator = std.mem.Allocator; |
| 12 | 11 | const Cache = std.Build.Cache; |
| 13 | 12 | const Path = std.Build.Cache.Path; |
| 14 | 13 | const Directory = std.Build.Cache.Directory; |
| 15 | 14 | const Compilation = @import("Compilation.zig"); |
| 16 | 15 | const LibCInstallation = std.zig.LibCInstallation; |
| 16 | ||
| 17 | const trace = @import("tracy.zig").trace; | |
| 18 | const wasi_libc = @import("libs/wasi_libc.zig"); | |
| 19 | ||
| 17 | 20 | const Zcu = @import("Zcu.zig"); |
| 18 | 21 | const InternPool = @import("InternPool.zig"); |
| 19 | 22 | const Type = @import("Type.zig"); |
| ... | ... | @@ -572,6 +575,7 @@ pub const File = struct { |
| 572 | 575 | dev.check(.make_writable); |
| 573 | 576 | const comp = base.comp; |
| 574 | 577 | const gpa = comp.gpa; |
| 578 | const io = comp.io; | |
| 575 | 579 | switch (base.tag) { |
| 576 | 580 | .lld => assert(base.file == null), |
| 577 | 581 | .elf, .macho, .wasm, .goff, .xcoff => { |
| ... | ... | @@ -616,22 +620,9 @@ pub const File = struct { |
| 616 | 620 | &coff.mf |
| 617 | 621 | else |
| 618 | 622 | 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, .{ | |
| 621 | 624 | .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 | })); | |
| 635 | 626 | base.file = mf.file; |
| 636 | 627 | try mf.ensureTotalCapacity(@intCast(mf.nodes.items[0].location().resolve(mf)[1])); |
| 637 | 628 | }, |