Commit 958faa7031

Jacob Young <jacobly0@users.noreply.github.com>
2025-10-12 19:54:00
windows: workaround kernel race condition the most
1 parent ea694bf
Changed files (2)
src
test
standalone
windows_spawn
src/link.zig
@@ -616,19 +616,22 @@ pub const File = struct {
                     &coff.mf
                 else
                     unreachable;
-                mf.file = for (0..10) |_| break base.emit.root_dir.handle.openFile(base.emit.sub_path, .{
+                var attempt: u5 = 0;
+                mf.file = while (true) break base.emit.root_dir.handle.openFile(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(10);
+                            std.os.windows.kernel32.Sleep(@as(u32, 1) << attempt >> 1);
+                            attempt += 1;
                             continue;
                         },
                         else => return error.AccessDenied,
                     },
                     else => |e| return e,
-                } else return error.AccessDenied;
+                };
                 base.file = mf.file;
                 try mf.ensureTotalCapacity(@intCast(mf.nodes.items[0].location().resolve(mf)[1]));
             },
test/standalone/windows_spawn/main.zig
@@ -71,14 +71,19 @@ pub fn main() anyerror!void {
     try testExec(allocator, "heLLo", "hello from exe\n");
 
     // now rename the exe to not have an extension
-    for (0..10) |_| break tmp.dir.rename("hello.exe", "hello") catch |err| switch (err) {
-        error.AccessDenied => {
-            // give the kernel a chance to finish closing the executable handle
-            std.os.windows.kernel32.Sleep(10);
-            continue;
-        },
-        else => |e| return e,
-    } else return error.AccessDenied;
+    {
+        var attempt: u5 = 0;
+        while (true) break tmp.dir.rename("hello.exe", "hello") catch |err| switch (err) {
+            error.AccessDenied => {
+                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 => |e| return e,
+        };
+    }
 
     // with extension should now fail
     try testExecError(error.FileNotFound, allocator, "hello.exe");