Skip to content

Commit b2bc607

Browse files
jacobly0andrewrk
authored andcommitted
windows: workaround kernel race condition
This was causing flaky CI failures.
1 parent c17e186 commit b2bc607

File tree

3 files changed

+22
-3
lines changed

3 files changed

+22
-3
lines changed

lib/std/os/windows.zig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1912,6 +1912,7 @@ pub const CreateProcessError = error{
19121912
NameTooLong,
19131913
InvalidExe,
19141914
SystemResources,
1915+
FileBusy,
19151916
Unexpected,
19161917
};
19171918

@@ -1982,6 +1983,7 @@ pub fn CreateProcessW(
19821983
.INVALID_PARAMETER => unreachable,
19831984
.INVALID_NAME => return error.InvalidName,
19841985
.FILENAME_EXCED_RANGE => return error.NameTooLong,
1986+
.SHARING_VIOLATION => return error.FileBusy,
19851987
// These are all the system errors that are mapped to ENOEXEC by
19861988
// the undocumented _dosmaperr (old CRT) or __acrt_errno_map_os_error
19871989
// (newer CRT) functions. Their code can be found in crt/src/dosmap.c (old SDK)

src/link.zig

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -616,9 +616,19 @@ pub const File = struct {
616616
&coff.mf
617617
else
618618
unreachable;
619-
mf.file = try base.emit.root_dir.handle.openFile(base.emit.sub_path, .{
619+
mf.file = for (0..2) |_| break base.emit.root_dir.handle.openFile(base.emit.sub_path, .{
620620
.mode = .read_write,
621-
});
621+
}) catch |err| switch (err) {
622+
error.AccessDenied => switch (builtin.os.tag) {
623+
.windows => {
624+
// give the kernel a chance to finish closing the executable handle
625+
std.os.windows.kernel32.Sleep(0);
626+
continue;
627+
},
628+
else => return error.AccessDenied,
629+
},
630+
else => |e| return e,
631+
} else return error.AccessDenied;
622632
base.file = mf.file;
623633
try mf.ensureTotalCapacity(@intCast(mf.nodes.items[0].location().resolve(mf)[1]));
624634
},

test/standalone/windows_spawn/main.zig

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,14 @@ pub fn main() anyerror!void {
7171
try testExec(allocator, "heLLo", "hello from exe\n");
7272

7373
// now rename the exe to not have an extension
74-
try tmp.dir.rename("hello.exe", "hello");
74+
for (0..2) |_| break tmp.dir.rename("hello.exe", "hello") catch |err| switch (err) {
75+
error.AccessDenied => {
76+
// give the kernel a chance to finish closing the executable handle
77+
std.os.windows.kernel32.Sleep(0);
78+
continue;
79+
},
80+
else => |e| return e,
81+
} else return error.AccessDenied;
7582

7683
// with extension should now fail
7784
try testExecError(error.FileNotFound, allocator, "hello.exe");

0 commit comments

Comments
 (0)