| 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,6 +2081,10 @@ fn dirOpenFileWindowsInner( |
| 2081 | const create_file_flags: w.ULONG = file_or_dir_flag | | 2081 | const create_file_flags: w.ULONG = file_or_dir_flag | |
| 2082 | if (flags.follow_symlinks) blocking_flag else w.FILE_OPEN_REPARSE_POINT; | 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 | const handle = while (true) { | 2088 | const handle = while (true) { |
| 2085 | try t.checkCancel(); | 2089 | try t.checkCancel(); |
| 2086 | 2090 | ||
| ... | @@ -2110,7 +2114,17 @@ fn dirOpenFileWindowsInner( | ... | @@ -2110,7 +2114,17 @@ fn dirOpenFileWindowsInner( |
| 2110 | .NO_MEDIA_IN_DEVICE => return error.NoDevice, | 2114 | .NO_MEDIA_IN_DEVICE => return error.NoDevice, |
| 2111 | .INVALID_PARAMETER => |err| return w.statusBug(err), | 2115 | .INVALID_PARAMETER => |err| return w.statusBug(err), |
| 2112 | .SHARING_VIOLATION => return error.AccessDenied, | 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 | .PIPE_BUSY => return error.PipeBusy, | 2128 | .PIPE_BUSY => return error.PipeBusy, |
| 2115 | .PIPE_NOT_AVAILABLE => return error.NoDevice, | 2129 | .PIPE_NOT_AVAILABLE => return error.NoDevice, |
| 2116 | .OBJECT_PATH_SYNTAX_BAD => |err| return w.statusBug(err), | 2130 | .OBJECT_PATH_SYNTAX_BAD => |err| return w.statusBug(err), |
| ... | @@ -2123,10 +2137,11 @@ fn dirOpenFileWindowsInner( | ... | @@ -2123,10 +2137,11 @@ fn dirOpenFileWindowsInner( |
| 2123 | // This error means that there *was* a file in this location on | 2137 | // This error means that there *was* a file in this location on |
| 2124 | // the file system, but it was deleted. However, the OS is not | 2138 | // the file system, but it was deleted. However, the OS is not |
| 2125 | // finished with the deletion operation, and so this CreateFile | 2139 | // finished with the deletion operation, and so this CreateFile |
| 2126 | // call has failed. There is not really a sane way to handle | 2140 | // call has failed. Here, we simulate the kernel bug being |
| 2127 | // this other than retrying the creation after the OS finishes | 2141 | // fixed by sleeping and retrying until the error goes away. |
| 2128 | // the deletion. | 2142 | if (attempt - max_attempts == 0) return error.AccessDenied; |
| 2129 | _ = w.kernel32.SleepEx(1, w.FALSE); | 2143 | _ = w.kernel32.SleepEx((@as(u32, 1) << attempt) >> 1, w.TRUE); |
| 2144 | attempt += 1; | ||
| 2130 | continue; | 2145 | continue; |
| 2131 | }, | 2146 | }, |
| 2132 | .VIRUS_INFECTED, .VIRUS_DELETED => return error.AntivirusInterference, | 2147 | .VIRUS_INFECTED, .VIRUS_DELETED => return error.AntivirusInterference, |
src/link.zig+11-20| ... | @@ -1,19 +1,22 @@ | ... | @@ -1,19 +1,22 @@ |
| 1 | const std = @import("std"); | ||
| 2 | const build_options = @import("build_options"); | ||
| 3 | const builtin = @import("builtin"); | 1 | const builtin = @import("builtin"); |
| 2 | const build_options = @import("build_options"); | ||
| 3 | |||
| 4 | const std = @import("std"); | ||
| 5 | const Io = std.Io; | ||
| 4 | const assert = std.debug.assert; | 6 | const assert = std.debug.assert; |
| 5 | const fs = std.fs; | 7 | const fs = std.fs; |
| 6 | const mem = std.mem; | 8 | const mem = std.mem; |
| 7 | const log = std.log.scoped(.link); | 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 | const Allocator = std.mem.Allocator; | 10 | const Allocator = std.mem.Allocator; |
| 12 | const Cache = std.Build.Cache; | 11 | const Cache = std.Build.Cache; |
| 13 | const Path = std.Build.Cache.Path; | 12 | const Path = std.Build.Cache.Path; |
| 14 | const Directory = std.Build.Cache.Directory; | 13 | const Directory = std.Build.Cache.Directory; |
| 15 | const Compilation = @import("Compilation.zig"); | 14 | const Compilation = @import("Compilation.zig"); |
| 16 | const LibCInstallation = std.zig.LibCInstallation; | 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 | const Zcu = @import("Zcu.zig"); | 20 | const Zcu = @import("Zcu.zig"); |
| 18 | const InternPool = @import("InternPool.zig"); | 21 | const InternPool = @import("InternPool.zig"); |
| 19 | const Type = @import("Type.zig"); | 22 | const Type = @import("Type.zig"); |
| ... | @@ -572,6 +575,7 @@ pub const File = struct { | ... | @@ -572,6 +575,7 @@ pub const File = struct { |
| 572 | dev.check(.make_writable); | 575 | dev.check(.make_writable); |
| 573 | const comp = base.comp; | 576 | const comp = base.comp; |
| 574 | const gpa = comp.gpa; | 577 | const gpa = comp.gpa; |
| 578 | const io = comp.io; | ||
| 575 | switch (base.tag) { | 579 | switch (base.tag) { |
| 576 | .lld => assert(base.file == null), | 580 | .lld => assert(base.file == null), |
| 577 | .elf, .macho, .wasm, .goff, .xcoff => { | 581 | .elf, .macho, .wasm, .goff, .xcoff => { |
| ... | @@ -616,22 +620,9 @@ pub const File = struct { | ... | @@ -616,22 +620,9 @@ pub const File = struct { |
| 616 | &coff.mf | 620 | &coff.mf |
| 617 | else | 621 | else |
| 618 | unreachable; | 622 | unreachable; |
| 619 | var attempt: u5 = 0; | 623 | mf.file = .adaptFromNewApi(try Io.Dir.openFile(base.emit.root_dir.handle.adaptToNewApi(), io, base.emit.sub_path, .{ |
| 620 | mf.file = while (true) break base.emit.root_dir.handle.openFile(base.emit.sub_path, .{ | ||
| 621 | .mode = .read_write, | 624 | .mode = .read_write, |
| 622 | }) catch |err| switch (err) { | 625 | })); |
| 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 | }; | ||
| 635 | base.file = mf.file; | 626 | base.file = mf.file; |
| 636 | try mf.ensureTotalCapacity(@intCast(mf.nodes.items[0].location().resolve(mf)[1])); | 627 | try mf.ensureTotalCapacity(@intCast(mf.nodes.items[0].location().resolve(mf)[1])); |
| 637 | }, | 628 | }, |