authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-01-22 18:08:13-08:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-01-22 18:08:13-08:00
log1badb2a840c47d49b49fa685db7a1553c0a40ee7
tree2c76cac07cb70044f199d3174deda145f3b4cc9d
parent305fd06756d0a90e330c957d85738f195b94bc10

std.Io.Threaded: dirCreateFileWindows uses NtCreateFile directly


8 files changed, 305 insertions(+), 132 deletions(-)

lib/std/Io/Dir.zig+3-3
...@@ -12,6 +12,8 @@ const Allocator = std.mem.Allocator;...@@ -12,6 +12,8 @@ const Allocator = std.mem.Allocator;
1212
13handle: Handle,13handle: Handle,
1414
15pub const Handle = std.posix.fd_t;
16
15pub const path = std.fs.path;17pub const path = std.fs.path;
1618
17/// The maximum length of a file path that the operating system will accept.19/// The maximum length of a file path that the operating system will accept.
...@@ -396,8 +398,6 @@ pub fn walk(dir: Dir, allocator: Allocator) Allocator.Error!Walker {...@@ -396,8 +398,6 @@ pub fn walk(dir: Dir, allocator: Allocator) Allocator.Error!Walker {
396 return .{ .inner = try walkSelectively(dir, allocator) };398 return .{ .inner = try walkSelectively(dir, allocator) };
397}399}
398400
399pub const Handle = std.posix.fd_t;
400
401pub const PathNameError = error{401pub const PathNameError = error{
402 /// Returned when an insufficient buffer is provided that cannot fit the402 /// Returned when an insufficient buffer is provided that cannot fit the
403 /// path name.403 /// path name.
...@@ -1698,7 +1698,7 @@ pub fn copyFile(...@@ -1698,7 +1698,7 @@ pub fn copyFile(
1698 options: CopyFileOptions,1698 options: CopyFileOptions,
1699) CopyFileError!void {1699) CopyFileError!void {
1700 const file = try source_dir.openFile(io, source_path, .{});1700 const file = try source_dir.openFile(io, source_path, .{});
1701 var file_reader: File.Reader = .init(.{ .handle = file.handle }, io, &.{});1701 var file_reader: File.Reader = .init(file, io, &.{});
1702 defer file_reader.file.close(io);1702 defer file_reader.file.close(io);
17031703
1704 const permissions = options.permissions orelse blk: {1704 const permissions = options.permissions orelse blk: {
lib/std/Io/File.zig+26-4
...@@ -11,13 +11,14 @@ const Dir = std.Io.Dir;...@@ -11,13 +11,14 @@ const Dir = std.Io.Dir;
1111
12handle: Handle,12handle: Handle,
1313
14pub const Handle = std.posix.fd_t;
15
14pub const Reader = @import("File/Reader.zig");16pub const Reader = @import("File/Reader.zig");
15pub const Writer = @import("File/Writer.zig");17pub const Writer = @import("File/Writer.zig");
16pub const Atomic = @import("File/Atomic.zig");18pub const Atomic = @import("File/Atomic.zig");
17/// Memory intended to remain consistent with file contents.19/// Memory intended to remain consistent with file contents.
18pub const MemoryMap = @import("File/MemoryMap.zig");20pub const MemoryMap = @import("File/MemoryMap.zig");
1921
20pub const Handle = std.posix.fd_t;
21pub const INode = std.posix.ino_t;22pub const INode = std.posix.ino_t;
22pub const NLink = std.posix.nlink_t;23pub const NLink = std.posix.nlink_t;
23pub const Uid = std.posix.uid_t;24pub const Uid = std.posix.uid_t;
...@@ -73,15 +74,36 @@ pub const Stat = struct {...@@ -73,15 +74,36 @@ pub const Stat = struct {
73};74};
7475
75pub fn stdout() File {76pub fn stdout() File {
76 return .{ .handle = if (is_windows) std.os.windows.peb().ProcessParameters.hStdOutput else std.posix.STDOUT_FILENO };77 return switch (native_os) {
78 .windows => .{
79 .handle = std.os.windows.peb().ProcessParameters.hStdOutput,
80 },
81 else => .{
82 .handle = std.posix.STDOUT_FILENO,
83 },
84 };
77}85}
7886
79pub fn stderr() File {87pub fn stderr() File {
80 return .{ .handle = if (is_windows) std.os.windows.peb().ProcessParameters.hStdError else std.posix.STDERR_FILENO };88 return switch (native_os) {
89 .windows => .{
90 .handle = std.os.windows.peb().ProcessParameters.hStdError,
91 },
92 else => .{
93 .handle = std.posix.STDERR_FILENO,
94 },
95 };
81}96}
8297
83pub fn stdin() File {98pub fn stdin() File {
84 return .{ .handle = if (is_windows) std.os.windows.peb().ProcessParameters.hStdInput else std.posix.STDIN_FILENO };99 return switch (native_os) {
100 .windows => .{
101 .handle = std.os.windows.peb().ProcessParameters.hStdInput,
102 },
103 else => .{
104 .handle = std.posix.STDIN_FILENO,
105 },
106 };
85}107}
86108
87pub const StatError = error{109pub const StatError = error{
lib/std/Io/File/Writer.zig+1-1
...@@ -101,7 +101,7 @@ pub fn moveToReader(w: *Writer) File.Reader {...@@ -101,7 +101,7 @@ pub fn moveToReader(w: *Writer) File.Reader {
101 defer w.* = undefined;101 defer w.* = undefined;
102 return .{102 return .{
103 .io = w.io,103 .io = w.io,
104 .file = .{ .handle = w.file.handle },104 .file = w.file,
105 .mode = w.mode,105 .mode = w.mode,
106 .pos = w.pos,106 .pos = w.pos,
107 .interface = File.Reader.initInterface(w.interface.buffer),107 .interface = File.Reader.initInterface(w.interface.buffer),
lib/std/Io/Threaded.zig+153-76
...@@ -571,7 +571,7 @@ const Future = struct {...@@ -571,7 +571,7 @@ const Future = struct {
571 num_completed: *std.atomic.Value(u32),571 num_completed: *std.atomic.Value(u32),
572 thread: ?*Thread,572 thread: ?*Thread,
573 ) void {573 ) void {
574 var need_signal: bool = thread != null and thread.?.cancelAwaitable(.fromFuture(future));574 var need_signal: bool = if (thread) |th| th.cancelAwaitable(.fromFuture(future)) else false;
575 var timeout_ns: u64 = 1 << 10;575 var timeout_ns: u64 = 1 << 10;
576 while (true) {576 while (true) {
577 need_signal = need_signal and thread.?.signalCanceledSyscall(t, .fromFuture(future));577 need_signal = need_signal and thread.?.signalCanceledSyscall(t, .fromFuture(future));
...@@ -628,7 +628,7 @@ const Thread = struct {...@@ -628,7 +628,7 @@ const Thread = struct {
628628
629 const Handle = Handle: {629 const Handle = Handle: {
630 if (std.Thread.use_pthreads) break :Handle std.c.pthread_t;630 if (std.Thread.use_pthreads) break :Handle std.c.pthread_t;
631 if (builtin.target.os.tag == .windows) break :Handle windows.HANDLE;631 if (is_windows) break :Handle windows.HANDLE;
632 break :Handle void;632 break :Handle void;
633 };633 };
634634
...@@ -1364,7 +1364,7 @@ fn worker(t: *Threaded) void {...@@ -1364,7 +1364,7 @@ fn worker(t: *Threaded) void {
1364 .id = std.Thread.getCurrentId(),1364 .id = std.Thread.getCurrentId(),
1365 .handle = handle: {1365 .handle = handle: {
1366 if (std.Thread.use_pthreads) break :handle std.c.pthread_self();1366 if (std.Thread.use_pthreads) break :handle std.c.pthread_self();
1367 if (builtin.target.os.tag == .windows) break :handle undefined; // populated below1367 if (is_windows) break :handle undefined; // populated below
1368 },1368 },
1369 .status = .init(.{1369 .status = .init(.{
1370 .cancelation = .none,1370 .cancelation = .none,
...@@ -1376,7 +1376,7 @@ fn worker(t: *Threaded) void {...@@ -1376,7 +1376,7 @@ fn worker(t: *Threaded) void {
1376 };1376 };
1377 Thread.current = &thread;1377 Thread.current = &thread;
13781378
1379 if (builtin.target.os.tag == .windows) {1379 if (is_windows) {
1380 assert(windows.ntdll.NtOpenThread(1380 assert(windows.ntdll.NtOpenThread(
1381 &thread.handle,1381 &thread.handle,
1382 .{1382 .{
...@@ -1397,7 +1397,7 @@ fn worker(t: *Threaded) void {...@@ -1397,7 +1397,7 @@ fn worker(t: *Threaded) void {
1397 &windows.teb().ClientId,1397 &windows.teb().ClientId,
1398 ) == .SUCCESS);1398 ) == .SUCCESS);
1399 }1399 }
1400 defer if (builtin.target.os.tag == .windows) {1400 defer if (is_windows) {
1401 windows.CloseHandle(thread.handle);1401 windows.CloseHandle(thread.handle);
1402 };1402 };
14031403
...@@ -3430,53 +3430,133 @@ fn dirCreateFileWindows(...@@ -3430,53 +3430,133 @@ fn dirCreateFileWindows(
3430 sub_path: []const u8,3430 sub_path: []const u8,
3431 flags: File.CreateFlags,3431 flags: File.CreateFlags,
3432) File.OpenError!File {3432) File.OpenError!File {
3433 const w = windows;
3434 const t: *Threaded = @ptrCast(@alignCast(userdata));3433 const t: *Threaded = @ptrCast(@alignCast(userdata));
3435 _ = t;3434 _ = t;
34363435
3437 const sub_path_w_array = try w.sliceToPrefixedFileW(dir.handle, sub_path);3436 if (std.mem.eql(u8, sub_path, ".")) return error.IsDir;
3437 if (std.mem.eql(u8, sub_path, "..")) return error.IsDir;
3438
3439 const sub_path_w_array = try windows.sliceToPrefixedFileW(dir.handle, sub_path);
3438 const sub_path_w = sub_path_w_array.span();3440 const sub_path_w = sub_path_w_array.span();
3441 const path_len_bytes = std.math.cast(u16, sub_path_w.len * 2) orelse return error.NameTooLong;
34393442
3440 const handle = handle: {3443 var nt_name: windows.UNICODE_STRING = .{
3441 const syscall: Syscall = try .start();3444 .Length = path_len_bytes,
3442 while (true) {3445 .MaximumLength = path_len_bytes,
3443 if (w.OpenFile(sub_path_w, .{3446 .Buffer = @constCast(sub_path_w.ptr),
3444 .dir = dir.handle,
3445 .access_mask = .{
3446 .STANDARD = .{ .SYNCHRONIZE = true },
3447 .GENERIC = .{
3448 .WRITE = true,
3449 .READ = flags.read,
3450 },
3451 },
3452 .creation = if (flags.exclusive)
3453 .CREATE
3454 else if (flags.truncate)
3455 .OVERWRITE_IF
3456 else
3457 .OPEN_IF,
3458 })) |handle| {
3459 syscall.finish();
3460 break :handle handle;
3461 } else |err| switch (err) {
3462 error.OperationCanceled => {
3463 try syscall.checkCancel();
3464 continue;
3465 },
3466 else => |e| return syscall.fail(e),
3467 }
3468 }
3469 };3447 };
3470 errdefer w.CloseHandle(handle);3448 const attr: windows.OBJECT_ATTRIBUTES = .{
3449 .Length = @sizeOf(windows.OBJECT_ATTRIBUTES),
3450 .RootDirectory = if (Dir.path.isAbsoluteWindowsWtf16(sub_path_w)) null else dir.handle,
3451 .Attributes = .{
3452 .INHERIT = false,
3453 },
3454 .ObjectName = &nt_name,
3455 .SecurityDescriptor = null,
3456 .SecurityQualityOfService = null,
3457 };
3458 const create_disposition: windows.FILE.CREATE_DISPOSITION = if (flags.exclusive)
3459 .CREATE
3460 else if (flags.truncate)
3461 .OVERWRITE_IF
3462 else
3463 .OPEN_IF;
3464
3465 const access_mask: windows.ACCESS_MASK = .{
3466 .STANDARD = .{ .SYNCHRONIZE = true },
3467 .GENERIC = .{
3468 .WRITE = true,
3469 .READ = flags.read,
3470 },
3471 };
3472
3473 var io_status_block: windows.IO_STATUS_BLOCK = undefined;
3474
3475 // There are multiple kernel bugs being worked around with retries.
3476 const max_attempts = 13;
3477 var attempt: u5 = 0;
3478
3479 var handle: windows.HANDLE = undefined;
3480 var syscall: Syscall = try .start();
3481 while (true) switch (windows.ntdll.NtCreateFile(
3482 &handle,
3483 access_mask,
3484 &attr,
3485 &io_status_block,
3486 null,
3487 .{ .NORMAL = true },
3488 .VALID_FLAGS, // share access
3489 create_disposition,
3490 .{
3491 .NON_DIRECTORY_FILE = true,
3492 .IO = .SYNCHRONOUS_NONALERT,
3493 },
3494 null,
3495 0,
3496 )) {
3497 .SUCCESS => {
3498 syscall.finish();
3499 break;
3500 },
3501 .CANCELLED => {
3502 try syscall.checkCancel();
3503 continue;
3504 },
3505 .SHARING_VIOLATION => {
3506 // This occurs if the file attempting to be opened is a running
3507 // executable. However, there's a kernel bug: the error may be
3508 // incorrectly returned for an indeterminate amount of time
3509 // after an executable file is closed. Here we work around the
3510 // kernel bug with retry attempts.
3511 syscall.finish();
3512 if (max_attempts - attempt == 0) return error.SharingViolation;
3513 try parking_sleep.windowsRetrySleep((@as(u32, 1) << attempt) >> 1);
3514 attempt += 1;
3515 syscall = try .start();
3516 continue;
3517 },
3518 .DELETE_PENDING => {
3519 // This error means that there *was* a file in this location on
3520 // the file system, but it was deleted. However, the OS is not
3521 // finished with the deletion operation, and so this CreateFile
3522 // call has failed. Here, we simulate the kernel bug being
3523 // fixed by sleeping and retrying until the error goes away.
3524 syscall.finish();
3525 if (max_attempts - attempt == 0) return error.SharingViolation;
3526 try parking_sleep.windowsRetrySleep((@as(u32, 1) << attempt) >> 1);
3527 attempt += 1;
3528 syscall = try .start();
3529 continue;
3530 },
3531 .OBJECT_NAME_INVALID => return syscall.fail(error.BadPathName),
3532 .OBJECT_NAME_NOT_FOUND => return syscall.fail(error.FileNotFound),
3533 .OBJECT_PATH_NOT_FOUND => return syscall.fail(error.FileNotFound),
3534 .BAD_NETWORK_PATH => return syscall.fail(error.NetworkNotFound), // \\server was not found
3535 .BAD_NETWORK_NAME => return syscall.fail(error.NetworkNotFound), // \\server was found but \\server\share wasn't
3536 .NO_MEDIA_IN_DEVICE => return syscall.fail(error.NoDevice),
3537 .ACCESS_DENIED => return syscall.fail(error.AccessDenied),
3538 .PIPE_BUSY => return syscall.fail(error.PipeBusy),
3539 .PIPE_NOT_AVAILABLE => return syscall.fail(error.NoDevice),
3540 .OBJECT_NAME_COLLISION => return syscall.fail(error.PathAlreadyExists),
3541 .FILE_IS_A_DIRECTORY => return syscall.fail(error.IsDir),
3542 .NOT_A_DIRECTORY => return syscall.fail(error.NotDir),
3543 .USER_MAPPED_FILE => return syscall.fail(error.AccessDenied),
3544 .VIRUS_INFECTED, .VIRUS_DELETED => return syscall.fail(error.AntivirusInterference),
3545 .INVALID_PARAMETER => |err| return syscall.ntstatusBug(err),
3546 .OBJECT_PATH_SYNTAX_BAD => |err| return syscall.ntstatusBug(err),
3547 .INVALID_HANDLE => |err| return syscall.ntstatusBug(err),
3548 else => |err| return syscall.unexpectedNtstatus(err),
3549 };
3550 errdefer windows.CloseHandle(handle);
34713551
3472 var io_status_block: w.IO_STATUS_BLOCK = undefined;
3473 const exclusive = switch (flags.lock) {3552 const exclusive = switch (flags.lock) {
3474 .none => return .{ .handle = handle },3553 .none => return .{ .handle = handle },
3475 .shared => false,3554 .shared => false,
3476 .exclusive => true,3555 .exclusive => true,
3477 };3556 };
3478 const syscall: Syscall = try .start();3557
3479 while (true) switch (w.ntdll.NtLockFile(3558 syscall = try .start();
3559 while (true) switch (windows.ntdll.NtLockFile(
3480 handle,3560 handle,
3481 null,3561 null,
3482 null,3562 null,
...@@ -3968,7 +4048,10 @@ pub fn dirOpenFileWtf16(...@@ -3968,7 +4048,10 @@ pub fn dirOpenFileWtf16(
3968 var attr: w.OBJECT_ATTRIBUTES = .{4048 var attr: w.OBJECT_ATTRIBUTES = .{
3969 .Length = @sizeOf(w.OBJECT_ATTRIBUTES),4049 .Length = @sizeOf(w.OBJECT_ATTRIBUTES),
3970 .RootDirectory = dir_handle,4050 .RootDirectory = dir_handle,
3971 .Attributes = .{},4051 .Attributes = .{
4052 // TODO should we set INHERIT=false?
4053 //.INHERIT = false,
4054 },
3972 .ObjectName = &nt_name,4055 .ObjectName = &nt_name,
3973 .SecurityDescriptor = null,4056 .SecurityDescriptor = null,
3974 .SecurityQualityOfService = null,4057 .SecurityQualityOfService = null,
...@@ -7923,15 +8006,14 @@ fn fileClose(userdata: ?*anyopaque, files: []const File) void {...@@ -7923,15 +8006,14 @@ fn fileClose(userdata: ?*anyopaque, files: []const File) void {
7923 for (files) |file| posix.close(file.handle);8006 for (files) |file| posix.close(file.handle);
7924}8007}
79258008
7926const fileReadStreaming = switch (native_os) {8009fn fileReadStreaming(userdata: ?*anyopaque, file: File, data: []const []u8) File.Reader.Error!usize {
7927 .windows => fileReadStreamingWindows,
7928 else => fileReadStreamingPosix,
7929};
7930
7931fn fileReadStreamingPosix(userdata: ?*anyopaque, file: File, data: []const []u8) File.Reader.Error!usize {
7932 const t: *Threaded = @ptrCast(@alignCast(userdata));8010 const t: *Threaded = @ptrCast(@alignCast(userdata));
7933 _ = t;8011 _ = t;
8012 if (is_windows) return fileReadStreamingWindows(file, data);
8013 return fileReadStreamingPosix(file, data);
8014}
79348015
8016fn fileReadStreamingPosix(file: File, data: []const []u8) File.Reader.Error!usize {
7935 var iovecs_buffer: [max_iovecs_len]posix.iovec = undefined;8017 var iovecs_buffer: [max_iovecs_len]posix.iovec = undefined;
7936 var i: usize = 0;8018 var i: usize = 0;
7937 for (data) |buf| {8019 for (data) |buf| {
...@@ -8013,10 +8095,7 @@ fn fileReadStreamingPosix(userdata: ?*anyopaque, file: File, data: []const []u8)...@@ -8013,10 +8095,7 @@ fn fileReadStreamingPosix(userdata: ?*anyopaque, file: File, data: []const []u8)
8013 }8095 }
8014}8096}
80158097
8016fn fileReadStreamingWindows(userdata: ?*anyopaque, file: File, data: []const []u8) File.Reader.Error!usize {8098fn fileReadStreamingWindows(file: File, data: []const []u8) File.Reader.Error!usize {
8017 const t: *Threaded = @ptrCast(@alignCast(userdata));
8018 _ = t;
8019
8020 const DWORD = windows.DWORD;8099 const DWORD = windows.DWORD;
8021 var index: usize = 0;8100 var index: usize = 0;
8022 while (index < data.len and data[index].len == 0) index += 1;8101 while (index < data.len and data[index].len == 0) index += 1;
...@@ -8059,10 +8138,7 @@ fn fileReadStreamingWindows(userdata: ?*anyopaque, file: File, data: []const []u...@@ -8059,10 +8138,7 @@ fn fileReadStreamingWindows(userdata: ?*anyopaque, file: File, data: []const []u
8059 }8138 }
8060}8139}
80618140
8062fn fileReadPositionalPosix(userdata: ?*anyopaque, file: File, data: []const []u8, offset: u64) File.ReadPositionalError!usize {8141fn fileReadPositionalPosix(file: File, data: []const []u8, offset: u64) File.ReadPositionalError!usize {
8063 const t: *Threaded = @ptrCast(@alignCast(userdata));
8064 _ = t;
8065
8066 if (!have_preadv) @compileError("TODO implement fileReadPositionalPosix for cursed operating systems that don't support preadv (it's only Haiku)");8142 if (!have_preadv) @compileError("TODO implement fileReadPositionalPosix for cursed operating systems that don't support preadv (it's only Haiku)");
80678143
8068 var iovecs_buffer: [max_iovecs_len]posix.iovec = undefined;8144 var iovecs_buffer: [max_iovecs_len]posix.iovec = undefined;
...@@ -8144,15 +8220,14 @@ fn fileReadPositionalPosix(userdata: ?*anyopaque, file: File, data: []const []u8...@@ -8144,15 +8220,14 @@ fn fileReadPositionalPosix(userdata: ?*anyopaque, file: File, data: []const []u8
8144 }8220 }
8145}8221}
81468222
8147const fileReadPositional = switch (native_os) {8223fn fileReadPositional(userdata: ?*anyopaque, file: File, data: []const []u8, offset: u64) File.ReadPositionalError!usize {
8148 .windows => fileReadPositionalWindows,
8149 else => fileReadPositionalPosix,
8150};
8151
8152fn fileReadPositionalWindows(userdata: ?*anyopaque, file: File, data: []const []u8, offset: u64) File.ReadPositionalError!usize {
8153 const t: *Threaded = @ptrCast(@alignCast(userdata));8224 const t: *Threaded = @ptrCast(@alignCast(userdata));
8154 _ = t;8225 _ = t;
8226 if (is_windows) return fileReadPositionalWindows(file, data, offset);
8227 return fileReadPositionalPosix(file, data, offset);
8228}
81558229
8230fn fileReadPositionalWindows(file: File, data: []const []u8, offset: u64) File.ReadPositionalError!usize {
8156 var index: usize = 0;8231 var index: usize = 0;
8157 while (index < data.len and data[index].len == 0) index += 1;8232 while (index < data.len and data[index].len == 0) index += 1;
8158 if (index == data.len) return 0;8233 if (index == data.len) return 0;
...@@ -8244,7 +8319,7 @@ fn fileSeekBy(userdata: ?*anyopaque, file: File, offset: i64) File.SeekError!voi...@@ -8244,7 +8319,7 @@ fn fileSeekBy(userdata: ?*anyopaque, file: File, offset: i64) File.SeekError!voi
8244 }8319 }
8245 }8320 }
82468321
8247 if (native_os == .windows) {8322 if (is_windows) {
8248 const syscall: Syscall = try .start();8323 const syscall: Syscall = try .start();
8249 while (true) {8324 while (true) {
8250 if (windows.kernel32.SetFilePointerEx(fd, offset, null, windows.FILE_CURRENT) != 0) {8325 if (windows.kernel32.SetFilePointerEx(fd, offset, null, windows.FILE_CURRENT) != 0) {
...@@ -8329,7 +8404,7 @@ fn fileSeekTo(userdata: ?*anyopaque, file: File, offset: u64) File.SeekError!voi...@@ -8329,7 +8404,7 @@ fn fileSeekTo(userdata: ?*anyopaque, file: File, offset: u64) File.SeekError!voi
8329 _ = t;8404 _ = t;
8330 const fd = file.handle;8405 const fd = file.handle;
83318406
8332 if (native_os == .windows) {8407 if (is_windows) {
8333 // "The starting point is zero or the beginning of the file. If [FILE_BEGIN]8408 // "The starting point is zero or the beginning of the file. If [FILE_BEGIN]
8334 // is specified, then the liDistanceToMove parameter is interpreted as an unsigned value."8409 // is specified, then the liDistanceToMove parameter is interpreted as an unsigned value."
8335 // https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-setfilepointerex8410 // https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-setfilepointerex
...@@ -11628,7 +11703,7 @@ fn netWriteWindows(...@@ -11628,7 +11703,7 @@ fn netWriteWindows(
11628 splat: usize,11703 splat: usize,
11629) net.Stream.Writer.Error!usize {11704) net.Stream.Writer.Error!usize {
11630 const t: *Threaded = @ptrCast(@alignCast(userdata));11705 const t: *Threaded = @ptrCast(@alignCast(userdata));
11631 comptime assert(native_os == .windows);11706 comptime assert(is_windows);
1163211707
11633 var iovecs: [max_iovecs_len]ws2_32.WSABUF = undefined;11708 var iovecs: [max_iovecs_len]ws2_32.WSABUF = undefined;
11634 var len: u32 = 0;11709 var len: u32 = 0;
...@@ -11896,7 +11971,7 @@ fn netInterfaceNameResolve(...@@ -11896,7 +11971,7 @@ fn netInterfaceNameResolve(
11896 }11971 }
11897 }11972 }
1189811973
11899 if (native_os == .windows) {11974 if (is_windows) {
11900 try Thread.checkCancel();11975 try Thread.checkCancel();
11901 @panic("TODO implement netInterfaceNameResolve for Windows");11976 @panic("TODO implement netInterfaceNameResolve for Windows");
11902 }11977 }
...@@ -11930,7 +12005,7 @@ fn netInterfaceName(userdata: ?*anyopaque, interface: net.Interface) net.Interfa...@@ -11930,7 +12005,7 @@ fn netInterfaceName(userdata: ?*anyopaque, interface: net.Interface) net.Interfa
11930 @panic("TODO implement netInterfaceName for linux");12005 @panic("TODO implement netInterfaceName for linux");
11931 }12006 }
1193212007
11933 if (native_os == .windows) {12008 if (is_windows) {
11934 @panic("TODO implement netInterfaceName for windows");12009 @panic("TODO implement netInterfaceName for windows");
11935 }12010 }
1193612011
...@@ -15247,11 +15322,13 @@ fn progressParentFile(userdata: ?*anyopaque) std.Progress.ParentFileError!File {...@@ -15247,11 +15322,13 @@ fn progressParentFile(userdata: ?*anyopaque) std.Progress.ParentFileError!File {
1524715322
15248 const int = try t.environ.zig_progress_handle;15323 const int = try t.environ.zig_progress_handle;
1524915324
15250 return .{ .handle = switch (@typeInfo(Io.File.Handle)) {15325 return .{
15251 .int => int,15326 .handle = switch (@typeInfo(Io.File.Handle)) {
15252 .pointer => @ptrFromInt(int),15327 .int => int,
15253 else => return error.UnsupportedOperation,15328 .pointer => @ptrFromInt(int),
15254 } };15329 else => return error.UnsupportedOperation,
15330 },
15331 };
15255}15332}
1525615333
15257pub fn environString(t: *Threaded, comptime name: []const u8) ?[:0]const u8 {15334pub fn environString(t: *Threaded, comptime name: []const u8) ?[:0]const u8 {
...@@ -15562,13 +15639,13 @@ test {...@@ -15562,13 +15639,13 @@ test {
15562 _ = @import("Threaded/test.zig");15639 _ = @import("Threaded/test.zig");
15563}15640}
1556415641
15565const use_parking_futex = switch (builtin.target.os.tag) {15642const use_parking_futex = switch (native_os) {
15566 .windows => true, // RtlWaitOnAddress is a userland implementation anyway15643 .windows => true, // RtlWaitOnAddress is a userland implementation anyway
15567 .netbsd => true, // NetBSD has `futex(2)`, but it's historically been quite buggy. TODO: evaluate whether it's okay to use now.15644 .netbsd => true, // NetBSD has `futex(2)`, but it's historically been quite buggy. TODO: evaluate whether it's okay to use now.
15568 .illumos => true, // Illumos has no futex mechanism15645 .illumos => true, // Illumos has no futex mechanism
15569 else => false,15646 else => false,
15570};15647};
15571const use_parking_sleep = switch (builtin.target.os.tag) {15648const use_parking_sleep = switch (native_os) {
15572 // On Windows, we can implement sleep either with `NtDelayExecution` (which is how `SleepEx` in15649 // On Windows, we can implement sleep either with `NtDelayExecution` (which is how `SleepEx` in
15573 // kernel32 works) or `NtWaitForAlertByThreadId` (thread parking). We're already using the15650 // kernel32 works) or `NtWaitForAlertByThreadId` (thread parking). We're already using the
15574 // latter for futex, so we may as well use it for sleeping too, to maximise code reuse. I'm15651 // latter for futex, so we may as well use it for sleeping too, to maximise code reuse. I'm
...@@ -15926,7 +16003,7 @@ const parking_sleep = struct {...@@ -15926,7 +16003,7 @@ const parking_sleep = struct {
15926/// `addr_hint` has no semantic effect, but may allow the OS to optimize this operation.16003/// `addr_hint` has no semantic effect, but may allow the OS to optimize this operation.
15927fn park(opt_deadline: ?std.Io.Clock.Timestamp, addr_hint: ?*const anyopaque) error{Timeout}!void {16004fn park(opt_deadline: ?std.Io.Clock.Timestamp, addr_hint: ?*const anyopaque) error{Timeout}!void {
15928 comptime assert(use_parking_futex or use_parking_sleep);16005 comptime assert(use_parking_futex or use_parking_sleep);
15929 switch (builtin.target.os.tag) {16006 switch (native_os) {
15930 .windows => {16007 .windows => {
15931 var timeout_buf: windows.LARGE_INTEGER = undefined;16008 var timeout_buf: windows.LARGE_INTEGER = undefined;
15932 const raw_timeout: ?*windows.LARGE_INTEGER = if (opt_deadline) |deadline| timeout: {16009 const raw_timeout: ?*windows.LARGE_INTEGER = if (opt_deadline) |deadline| timeout: {
...@@ -15980,7 +16057,7 @@ fn park(opt_deadline: ?std.Io.Clock.Timestamp, addr_hint: ?*const anyopaque) err...@@ -15980,7 +16057,7 @@ fn park(opt_deadline: ?std.Io.Clock.Timestamp, addr_hint: ?*const anyopaque) err
15980 }16057 }
15981}16058}
1598216059
15983const UnparkTid = switch (builtin.target.os.tag) {16060const UnparkTid = switch (native_os) {
15984 // `NtAlertMultipleThreadByThreadId` is weird and wants 64-bit thread handles?16061 // `NtAlertMultipleThreadByThreadId` is weird and wants 64-bit thread handles?
15985 .windows => usize,16062 .windows => usize,
15986 else => std.Thread.Id,16063 else => std.Thread.Id,
...@@ -15988,7 +16065,7 @@ const UnparkTid = switch (builtin.target.os.tag) {...@@ -15988,7 +16065,7 @@ const UnparkTid = switch (builtin.target.os.tag) {
15988/// `addr_hint` has no semantic effect, but may allow the OS to optimize this operation.16065/// `addr_hint` has no semantic effect, but may allow the OS to optimize this operation.
15989fn unpark(tids: []const UnparkTid, addr_hint: ?*const anyopaque) void {16066fn unpark(tids: []const UnparkTid, addr_hint: ?*const anyopaque) void {
15990 comptime assert(use_parking_futex or use_parking_sleep);16067 comptime assert(use_parking_futex or use_parking_sleep);
15991 switch (builtin.target.os.tag) {16068 switch (native_os) {
15992 .windows => {16069 .windows => {
15993 // TODO: this condition is currently disabled because mingw-w64 does not contain this16070 // TODO: this condition is currently disabled because mingw-w64 does not contain this
15994 // symbol. Once it's added, enable this check to use the new bulk API where possible.16071 // symbol. Once it's added, enable this check to use the new bulk API where possible.
lib/std/Progress.zig+3-1
...@@ -977,7 +977,9 @@ fn serializeIpc(start_serialized_len: usize, serialized_buffer: *Serialized.Buff...@@ -977,7 +977,9 @@ fn serializeIpc(start_serialized_len: usize, serialized_buffer: *Serialized.Buff
977 0..,977 0..,
978 ) |main_parent, *main_storage, main_index| {978 ) |main_parent, *main_storage, main_index| {
979 if (main_parent == .unused) continue;979 if (main_parent == .unused) continue;
980 const file: Io.File = .{ .handle = main_storage.getIpcFd() orelse continue };980 const file: Io.File = .{
981 .handle = main_storage.getIpcFd() orelse continue,
982 };
981 const opt_saved_metadata = findOld(file.handle, old_ipc_metadata_fds, old_ipc_metadata);983 const opt_saved_metadata = findOld(file.handle, old_ipc_metadata_fds, old_ipc_metadata);
982 var bytes_read: usize = 0;984 var bytes_read: usize = 0;
983 while (true) {985 while (true) {
lib/std/os/windows.zig+93-41
...@@ -392,6 +392,8 @@ pub const FILE = struct {...@@ -392,6 +392,8 @@ pub const FILE = struct {
392 Characteristics: ULONG,392 Characteristics: ULONG,
393 };393 };
394394
395 pub const USE_FILE_POINTER_POSITION = -2;
396
395 // ref: um/WinBase.h397 // ref: um/WinBase.h
396398
397 pub const ATTRIBUTE_TAG_INFO = extern struct {399 pub const ATTRIBUTE_TAG_INFO = extern struct {
...@@ -466,9 +468,11 @@ pub const FILE = struct {...@@ -466,9 +468,11 @@ pub const FILE = struct {
466 pub const CREATE_DISPOSITION = enum(ULONG) {468 pub const CREATE_DISPOSITION = enum(ULONG) {
467 /// If the file already exists, replace it with the given file. If it does not, create the given file.469 /// If the file already exists, replace it with the given file. If it does not, create the given file.
468 SUPERSEDE = 0x00000000,470 SUPERSEDE = 0x00000000,
469 /// If the file already exists, open it instead of creating a new file. If it does not, fail the request and do not create a new file.471 /// If the file already exists, open it instead of creating a new file.
472 /// If it does not, fail the request and do not create a new file.
470 OPEN = 0x00000001,473 OPEN = 0x00000001,
471 /// If the file already exists, fail the request and do not create or open the given file. If it does not, create the given file.474 /// If the file already exists, fail the request and do not create or
475 /// open the given file. If it does not, create the given file.
472 CREATE = 0x00000002,476 CREATE = 0x00000002,
473 /// If the file already exists, open it. If it does not, create the given file.477 /// If the file already exists, open it. If it does not, create the given file.
474 OPEN_IF = 0x00000003,478 OPEN_IF = 0x00000003,
...@@ -482,75 +486,122 @@ pub const FILE = struct {...@@ -482,75 +486,122 @@ pub const FILE = struct {
482486
483 /// Define the create/open option flags487 /// Define the create/open option flags
484 pub const MODE = packed struct(ULONG) {488 pub const MODE = packed struct(ULONG) {
485 /// The file being created or opened is a directory file. With this flag, the CreateDisposition parameter must be set to `.CREATE`, `.FILE_OPEN`, or `.OPEN_IF`.489 /// The file being created or opened is a directory file. With this
486 /// With this flag, other compatible CreateOptions flags include only the following: `SYNCHRONOUS_IO`, `WRITE_THROUGH`, `OPEN_FOR_BACKUP_INTENT`, and `OPEN_BY_FILE_ID`.490 /// flag, the CreateDisposition parameter must be set to `.CREATE`,
491 /// `.FILE_OPEN`, or `.OPEN_IF`. With this flag, other compatible
492 /// CreateOptions flags include only the following: `SYNCHRONOUS_IO`,
493 /// `WRITE_THROUGH`, `OPEN_FOR_BACKUP_INTENT`, and `OPEN_BY_FILE_ID`.
487 DIRECTORY_FILE: bool = false,494 DIRECTORY_FILE: bool = false,
488 /// Applications that write data to the file must actually transfer the data into the file before any requested write operation is considered complete.495 /// Applications that write data to the file must actually transfer the
489 /// This flag is automatically set if the CreateOptions flag `NO_INTERMEDIATE_BUFFERING` is set.496 /// data into the file before any requested write operation is
497 /// considered complete. This flag is automatically set if the
498 /// CreateOptions flag `NO_INTERMEDIATE_BUFFERING` is set.
490 WRITE_THROUGH: bool = false,499 WRITE_THROUGH: bool = false,
491 /// All accesses to the file are sequential.500 /// All accesses to the file are sequential.
492 SEQUENTIAL_ONLY: bool = false,501 SEQUENTIAL_ONLY: bool = false,
493 /// The file cannot be cached or buffered in a driver's internal buffers. This flag is incompatible with the DesiredAccess `FILE_APPEND_DATA` flag.502 /// The file cannot be cached or buffered in a driver's internal
503 /// buffers. This flag is incompatible with the DesiredAccess
504 /// `FILE_APPEND_DATA` flag.
494 NO_INTERMEDIATE_BUFFERING: bool = false,505 NO_INTERMEDIATE_BUFFERING: bool = false,
495 IO: enum(u2) {506 IO: enum(u2) {
496 /// All operations on the file are performed asynchronously.507 /// All operations on the file are performed asynchronously.
497 ASYNCHRONOUS = 0b00,508 ASYNCHRONOUS = 0b00,
498 /// All operations on the file are performed synchronously. Any wait on behalf of the caller is subject to premature termination from alerts.509 /// All operations on the file are performed synchronously. Any
499 /// This flag also causes the I/O system to maintain the file position context. If this flag is set, the DesiredAccess `SYNCHRONIZE` flag also must be set.510 /// wait on behalf of the caller is subject to premature
511 /// termination from alerts. This flag also causes the I/O system
512 /// to maintain the file position context. If this flag is set, the
513 /// DesiredAccess `SYNCHRONIZE` flag also must be set.
500 SYNCHRONOUS_ALERT = 0b01,514 SYNCHRONOUS_ALERT = 0b01,
501 /// All operations on the file are performed synchronously. Waits in the system to synchronize I/O queuing and completion are not subject to alerts.515 /// All operations on the file are performed synchronously. Waits
502 /// This flag also causes the I/O system to maintain the file position context. If this flag is set, the DesiredAccess `SYNCHRONIZE` flag also must be set.516 /// in the system to synchronize I/O queuing and completion are not
517 /// subject to alerts. This flag also causes the I/O system to
518 /// maintain the file position context. If this flag is set, the
519 /// DesiredAccess `SYNCHRONIZE` flag also must be set.
503 SYNCHRONOUS_NONALERT = 0b10,520 SYNCHRONOUS_NONALERT = 0b10,
504 _,521 _,
505522
506 pub const VALID_FLAGS: @This() = @enumFromInt(0b11);523 pub const VALID_FLAGS: @This() = @enumFromInt(0b11);
507 } = .ASYNCHRONOUS,524 } = .ASYNCHRONOUS,
508 /// The file being opened must not be a directory file or this call fails. The file object being opened can represent a data file, a logical, virtual, or physical525 /// The file being opened must not be a directory file or this call
509 /// device, or a volume.526 /// fails. The file object being opened can represent a data file, a
527 /// logical, virtual, or physical device, or a volume.
510 NON_DIRECTORY_FILE: bool = false,528 NON_DIRECTORY_FILE: bool = false,
511 /// Create a tree connection for this file in order to open it over the network. This flag is not used by device and intermediate drivers.529 /// Create a tree connection for this file in order to open it over the
530 /// network. This flag is not used by device and intermediate drivers.
512 CREATE_TREE_CONNECTION: bool = false,531 CREATE_TREE_CONNECTION: bool = false,
513 /// Complete this operation immediately with an alternate success code of `STATUS_OPLOCK_BREAK_IN_PROGRESS` if the target file is oplocked, rather than blocking532 /// Complete this operation immediately with an alternate success code
514 /// the caller's thread. If the file is oplocked, another caller already has access to the file. This flag is not used by device and intermediate drivers.533 /// of `STATUS_OPLOCK_BREAK_IN_PROGRESS` if the target file is
534 /// oplocked, rather than blocking the caller's thread. If the file is
535 /// oplocked, another caller already has access to the file. This flag
536 /// is not used by device and intermediate drivers.
515 COMPLETE_IF_OPLOCKED: bool = false,537 COMPLETE_IF_OPLOCKED: bool = false,
516 /// If the extended attributes on an existing file being opened indicate that the caller must understand EAs to properly interpret the file, fail this request538 /// If the extended attributes on an existing file being opened
517 /// because the caller does not understand how to deal with EAs. This flag is irrelevant for device and intermediate drivers.539 /// indicate that the caller must understand EAs to properly interpret
540 /// the file, fail this request because the caller does not understand
541 /// how to deal with EAs. This flag is irrelevant for device and
542 /// intermediate drivers.
518 NO_EA_KNOWLEDGE: bool = false,543 NO_EA_KNOWLEDGE: bool = false,
519 OPEN_REMOTE_INSTANCE: bool = false,544 OPEN_REMOTE_INSTANCE: bool = false,
520 /// Accesses to the file can be random, so no sequential read-ahead operations should be performed on the file by FSDs or the system.545 /// Accesses to the file can be random, so no sequential read-ahead
546 /// operations should be performed on the file by FSDs or the system.
521 RANDOM_ACCESS: bool = false,547 RANDOM_ACCESS: bool = false,
522 /// Delete the file when the last handle to it is passed to `NtClose`. If this flag is set, the `DELETE` flag must be set in the DesiredAccess parameter.548 /// Delete the file when the last handle to it is passed to `NtClose`.
549 /// If this flag is set, the `DELETE` flag must be set in the
550 /// DesiredAccess parameter.
523 DELETE_ON_CLOSE: bool = false,551 DELETE_ON_CLOSE: bool = false,
524 /// The file name that is specified by the `ObjectAttributes` parameter includes the 8-byte file reference number for the file. This number is assigned by and552 /// The file name that is specified by the `ObjectAttributes` parameter
525 /// specific to the particular file system. If the file is a reparse point, the file name will also include the name of a device. Note that the FAT file system553 /// includes the 8-byte file reference number for the file. This number
526 /// does not support this flag. This flag is not used by device and intermediate drivers.554 /// is assigned by and specific to the particular file system. If the
555 /// file is a reparse point, the file name will also include the name
556 /// of a device. Note that the FAT file system does not support this
557 /// flag. This flag is not used by device and intermediate drivers.
527 OPEN_BY_FILE_ID: bool = false,558 OPEN_BY_FILE_ID: bool = false,
528 /// The file is being opened for backup intent. Therefore, the system should check for certain access rights and grant the caller the appropriate access to the559 /// The file is being opened for backup intent. Therefore, the system
529 /// file before checking the DesiredAccess parameter against the file's security descriptor. This flag not used by device and intermediate drivers.560 /// should check for certain access rights and grant the caller the
561 /// appropriate access to the file before checking the DesiredAccess
562 /// parameter against the file's security descriptor. This flag not
563 /// used by device and intermediate drivers.
530 OPEN_FOR_BACKUP_INTENT: bool = false,564 OPEN_FOR_BACKUP_INTENT: bool = false,
531 /// Suppress inheritance of `FILE_ATTRIBUTE.COMPRESSED` from the parent directory. This allows creation of a non-compressed file in a directory that is marked565 /// Suppress inheritance of `FILE_ATTRIBUTE.COMPRESSED` from the parent
532 /// compressed.566 /// directory. This allows creation of a non-compressed file in a
567 /// directory that is marked compressed.
533 NO_COMPRESSION: bool = false,568 NO_COMPRESSION: bool = false,
534 /// The file is being opened and an opportunistic lock on the file is being requested as a single atomic operation. The file system checks for oplocks before it569 /// The file is being opened and an opportunistic lock on the file is
535 /// performs the create operation and will fail the create with a return code of STATUS_CANNOT_BREAK_OPLOCK if the result would be to break an existing oplock.570 /// being requested as a single atomic operation. The file system
536 /// For more information, see the Remarks section.571 /// checks for oplocks before it performs the create operation and will
572 /// fail the create with a return code of STATUS_CANNOT_BREAK_OPLOCK if
573 /// the result would be to break an existing oplock. For more
574 /// information, see the Remarks section.
537 ///575 ///
538 /// Windows Server 2008, Windows Vista, Windows Server 2003 and Windows XP: This flag is not supported.576 /// Windows Server 2008, Windows Vista, Windows Server 2003 and Windows
577 /// XP: This flag is not supported.
539 ///578 ///
540 /// This flag is supported on the following file systems: NTFS, FAT, and exFAT.579 /// This flag is supported on the following file systems: NTFS, FAT,
580 /// and exFAT.
541 OPEN_REQUIRING_OPLOCK: bool = false,581 OPEN_REQUIRING_OPLOCK: bool = false,
542 Reserved17: u3 = 0,582 Reserved17: u3 = 0,
543 /// This flag allows an application to request a filter opportunistic lock to prevent other applications from getting share violations. If there are already open583 /// This flag allows an application to request a filter opportunistic
544 /// handles, the create request will fail with STATUS_OPLOCK_NOT_GRANTED. For more information, see the Remarks section.584 /// lock to prevent other applications from getting share violations.
585 /// If there are already open handles, the create request will fail
586 /// with STATUS_OPLOCK_NOT_GRANTED. For more information, see the
587 /// Remarks section.
545 RESERVE_OPFILTER: bool = false,588 RESERVE_OPFILTER: bool = false,
546 /// Open a file with a reparse point and bypass normal reparse point processing for the file. For more information, see the Remarks section.589 /// Open a file with a reparse point and bypass normal reparse point
590 /// processing for the file. For more information, see the Remarks
591 /// section.
547 OPEN_REPARSE_POINT: bool = false,592 OPEN_REPARSE_POINT: bool = false,
548 /// Instructs any filters that perform offline storage or virtualization to not recall the contents of the file as a result of this open.593 /// Instructs any filters that perform offline storage or
594 /// virtualization to not recall the contents of the file as a result
595 /// of this open.
549 OPEN_NO_RECALL: bool = false,596 OPEN_NO_RECALL: bool = false,
550 /// This flag instructs the file system to capture the user associated with the calling thread. Any subsequent calls to `FltQueryVolumeInformation` or597 /// This flag instructs the file system to capture the user associated
551 /// `ZwQueryVolumeInformationFile` using the returned handle will assume the captured user, rather than the calling user at the time, for purposes of computing598 /// with the calling thread. Any subsequent calls to
552 /// the free space available to the caller. This applies to the following FsInformationClass values: `FileFsSizeInformation`, `FileFsFullSizeInformation`, and599 /// `FltQueryVolumeInformation` or `ZwQueryVolumeInformationFile` using
553 /// `FileFsFullSizeInformationEx`.600 /// the returned handle will assume the captured user, rather than the
601 /// calling user at the time, for purposes of computing the free space
602 /// available to the caller. This applies to the following
603 /// FsInformationClass values: `FileFsSizeInformation`,
604 /// `FileFsFullSizeInformation`, and `FileFsFullSizeInformationEx`.
554 OPEN_FOR_FREE_SPACE_QUERY: bool = false,605 OPEN_FOR_FREE_SPACE_QUERY: bool = false,
555 Reserved24: u8 = 0,606 Reserved24: u8 = 0,
556607
...@@ -597,7 +648,8 @@ pub const FILE = struct {...@@ -597,7 +648,8 @@ pub const FILE = struct {
597 // ref: km/ntifs.h648 // ref: km/ntifs.h
598649
599 pub const INFORMATION = extern struct {650 pub const INFORMATION = extern struct {
600 /// The set of flags that specify the mode in which the file can be accessed. These flags are a subset of `MODE`.651 /// The set of flags that specify the mode in which the file can be
652 /// accessed. These flags are a subset of `MODE`.
601 Mode: MODE,653 Mode: MODE,
602 };654 };
603 };655 };
lib/std/os/windows/ntdll.zig+15-3
...@@ -567,9 +567,8 @@ pub extern "ntdll" fn NtWaitForAlertByThreadId(...@@ -567,9 +567,8 @@ pub extern "ntdll" fn NtWaitForAlertByThreadId(
567 Address: ?*const anyopaque,567 Address: ?*const anyopaque,
568 Timeout: ?*const LARGE_INTEGER,568 Timeout: ?*const LARGE_INTEGER,
569) callconv(.winapi) NTSTATUS;569) callconv(.winapi) NTSTATUS;
570pub extern "ntdll" fn NtAlertThreadByThreadId(570pub extern "ntdll" fn NtAlertThreadByThreadId(ThreadId: DWORD) callconv(.winapi) NTSTATUS;
571 ThreadId: DWORD,571pub extern "ntdll" fn NtAlertThread(ThreadHandle: HANDLE) callconv(.winapi) NTSTATUS;
572) callconv(.winapi) NTSTATUS;
573pub extern "ntdll" fn NtAlertMultipleThreadByThreadId(572pub extern "ntdll" fn NtAlertMultipleThreadByThreadId(
574 ThreadIds: [*]const ULONG_PTR,573 ThreadIds: [*]const ULONG_PTR,
575 ThreadCount: ULONG,574 ThreadCount: ULONG,
...@@ -589,3 +588,16 @@ pub extern "ntdll" fn NtCancelSynchronousIoFile(...@@ -589,3 +588,16 @@ pub extern "ntdll" fn NtCancelSynchronousIoFile(
589 RequestToCancel: ?*IO_STATUS_BLOCK,588 RequestToCancel: ?*IO_STATUS_BLOCK,
590 IoStatusBlock: *IO_STATUS_BLOCK,589 IoStatusBlock: *IO_STATUS_BLOCK,
591) callconv(.winapi) NTSTATUS;590) callconv(.winapi) NTSTATUS;
591
592pub extern "ntdll" fn NtDelayExecution(
593 Alertable: BOOLEAN,
594 DelayInterval: *const LARGE_INTEGER,
595) callconv(.winapi) NTSTATUS;
596
597pub extern "ntdll" fn NtCancelIoFileEx(
598 FileHandle: HANDLE,
599 /// Documentation has this as IO_STATUS_BLOCK but it's actually the APC
600 /// context parameter.
601 IoRequestToCancel: ?*anyopaque,
602 IoStatusBlock: *IO_STATUS_BLOCK,
603) callconv(.winapi) NTSTATUS;
src/link/Lld.zig+11-3
...@@ -278,7 +278,7 @@ pub fn flush(...@@ -278,7 +278,7 @@ pub fn flush(
278 };278 };
279 result catch |err| switch (err) {279 result catch |err| switch (err) {
280 error.OutOfMemory, error.LinkFailure => |e| return e,280 error.OutOfMemory, error.LinkFailure => |e| return e,
281 else => |e| return lld.base.comp.link_diags.fail("failed to link with LLD: {s}", .{@errorName(e)}),281 else => |e| return lld.base.comp.link_diags.fail("failed to link with LLD: {t}", .{e}),
282 };282 };
283}283}
284284
...@@ -1630,7 +1630,11 @@ fn spawnLld(comp: *Compilation, arena: Allocator, argv: []const []const u8) !voi...@@ -1630,7 +1630,11 @@ fn spawnLld(comp: *Compilation, arena: Allocator, argv: []const []const u8) !voi
1630 }) catch |err| break :term err;1630 }) catch |err| break :term err;
16311631
1632 var stderr_reader = child.stderr.?.readerStreaming(io, &.{});1632 var stderr_reader = child.stderr.?.readerStreaming(io, &.{});
1633 stderr = try stderr_reader.interface.allocRemaining(gpa, .unlimited);1633 stderr = stderr_reader.interface.allocRemaining(gpa, .unlimited) catch |err| switch (err) {
1634 error.StreamTooLong => unreachable, // unlimited
1635 error.OutOfMemory => |e| return e,
1636 error.ReadFailed => return stderr_reader.err.?,
1637 };
1634 break :term child.wait(io);1638 break :term child.wait(io);
1635 }) catch |first_err| term: {1639 }) catch |first_err| term: {
1636 const err = switch (first_err) {1640 const err = switch (first_err) {
...@@ -1682,7 +1686,11 @@ fn spawnLld(comp: *Compilation, arena: Allocator, argv: []const []const u8) !voi...@@ -1682,7 +1686,11 @@ fn spawnLld(comp: *Compilation, arena: Allocator, argv: []const []const u8) !voi
1682 break :term rsp_child.wait(io) catch |err| break :err err;1686 break :term rsp_child.wait(io) catch |err| break :err err;
1683 } else {1687 } else {
1684 var stderr_reader = rsp_child.stderr.?.readerStreaming(io, &.{});1688 var stderr_reader = rsp_child.stderr.?.readerStreaming(io, &.{});
1685 stderr = try stderr_reader.interface.allocRemaining(gpa, .unlimited);1689 stderr = stderr_reader.interface.allocRemaining(gpa, .unlimited) catch |err| switch (err) {
1690 error.StreamTooLong => unreachable, // unlimited
1691 error.OutOfMemory => |e| return e,
1692 error.ReadFailed => return stderr_reader.err.?,
1693 };
1686 break :term rsp_child.wait(io) catch |err| break :err err;1694 break :term rsp_child.wait(io) catch |err| break :err err;
1687 }1695 }
1688 },1696 },