| author | |
| committer | |
| log | 45bce27b8fecda4fba1c22dd191030af29ccbc6f |
| tree | 946b5080cbe75dd1ef150ac830522a1ce40c526b |
| parent | 988031c07c1959b05682f007ed3bc848a75a43d0 |
10 files changed, 137 insertions(+), 119 deletions(-)
lib/std/child_process.zig+7-16| ... | ... | @@ -433,26 +433,17 @@ pub const ChildProcess = struct { |
| 433 | 433 | // we are the parent |
| 434 | 434 | const pid = @intCast(i32, pid_result); |
| 435 | 435 | if (self.stdin_behavior == StdIo.Pipe) { |
| 436 | self.stdin = File{ | |
| 437 | .handle = stdin_pipe[1], | |
| 438 | .io_mode = std.io.mode, | |
| 439 | }; | |
| 436 | self.stdin = File{ .handle = stdin_pipe[1] }; | |
| 440 | 437 | } else { |
| 441 | 438 | self.stdin = null; |
| 442 | 439 | } |
| 443 | 440 | if (self.stdout_behavior == StdIo.Pipe) { |
| 444 | self.stdout = File{ | |
| 445 | .handle = stdout_pipe[0], | |
| 446 | .io_mode = std.io.mode, | |
| 447 | }; | |
| 441 | self.stdout = File{ .handle = stdout_pipe[0] }; | |
| 448 | 442 | } else { |
| 449 | 443 | self.stdout = null; |
| 450 | 444 | } |
| 451 | 445 | if (self.stderr_behavior == StdIo.Pipe) { |
| 452 | self.stderr = File{ | |
| 453 | .handle = stderr_pipe[0], | |
| 454 | .io_mode = std.io.mode, | |
| 455 | }; | |
| 446 | self.stderr = File{ .handle = stderr_pipe[0] }; | |
| 456 | 447 | } else { |
| 457 | 448 | self.stderr = null; |
| 458 | 449 | } |
| ... | ... | @@ -835,8 +826,8 @@ const ErrInt = std.meta.Int(false, @sizeOf(anyerror) * 8); |
| 835 | 826 | fn writeIntFd(fd: i32, value: ErrInt) !void { |
| 836 | 827 | const file = File{ |
| 837 | 828 | .handle = fd, |
| 838 | .io_mode = .blocking, | |
| 839 | .async_block_allowed = File.async_block_allowed_yes, | |
| 829 | .capable_io_mode = .blocking, | |
| 830 | .intended_io_mode = .blocking, | |
| 840 | 831 | }; |
| 841 | 832 | file.outStream().writeIntNative(u64, @intCast(u64, value)) catch return error.SystemResources; |
| 842 | 833 | } |
| ... | ... | @@ -844,8 +835,8 @@ fn writeIntFd(fd: i32, value: ErrInt) !void { |
| 844 | 835 | fn readIntFd(fd: i32) !ErrInt { |
| 845 | 836 | const file = File{ |
| 846 | 837 | .handle = fd, |
| 847 | .io_mode = .blocking, | |
| 848 | .async_block_allowed = File.async_block_allowed_yes, | |
| 838 | .capable_io_mode = .blocking, | |
| 839 | .intended_io_mode = .blocking, | |
| 849 | 840 | }; |
| 850 | 841 | return @intCast(ErrInt, file.inStream().readIntNative(u64) catch return error.SystemResources); |
| 851 | 842 | } |
lib/std/debug.zig+3-3| ... | ... | @@ -667,7 +667,7 @@ pub fn openSelfDebugInfo(allocator: *mem.Allocator) anyerror!DebugInfo { |
| 667 | 667 | /// TODO resources https://github.com/ziglang/zig/issues/4353 |
| 668 | 668 | fn openCoffDebugInfo(allocator: *mem.Allocator, coff_file_path: [:0]const u16) !ModuleDebugInfo { |
| 669 | 669 | noasync { |
| 670 | const coff_file = try std.fs.openFileAbsoluteW(coff_file_path.ptr, .{}); | |
| 670 | const coff_file = try std.fs.openFileAbsoluteW(coff_file_path, .{ .intended_io_mode = .blocking }); | |
| 671 | 671 | errdefer coff_file.close(); |
| 672 | 672 | |
| 673 | 673 | const coff_obj = try allocator.create(coff.Coff); |
| ... | ... | @@ -1003,7 +1003,7 @@ fn openMachODebugInfo(allocator: *mem.Allocator, macho_file_path: []const u8) !M |
| 1003 | 1003 | fn printLineFromFileAnyOs(out_stream: var, line_info: LineInfo) !void { |
| 1004 | 1004 | // Need this to always block even in async I/O mode, because this could potentially |
| 1005 | 1005 | // be called from e.g. the event loop code crashing. |
| 1006 | var f = try fs.cwd().openFile(line_info.file_name, .{ .always_blocking = true }); | |
| 1006 | var f = try fs.cwd().openFile(line_info.file_name, .{ .intended_io_mode = .blocking }); | |
| 1007 | 1007 | defer f.close(); |
| 1008 | 1008 | // TODO fstat and make sure that the file has the correct size |
| 1009 | 1009 | |
| ... | ... | @@ -1051,7 +1051,7 @@ const MachoSymbol = struct { |
| 1051 | 1051 | |
| 1052 | 1052 | fn mapWholeFile(path: []const u8) ![]align(mem.page_size) const u8 { |
| 1053 | 1053 | noasync { |
| 1054 | const file = try fs.cwd().openFile(path, .{ .always_blocking = true }); | |
| 1054 | const file = try fs.cwd().openFile(path, .{ .intended_io_mode = .blocking }); | |
| 1055 | 1055 | defer file.close(); |
| 1056 | 1056 | |
| 1057 | 1057 | const file_len = try math.cast(usize, try file.getEndPos()); |
lib/std/fs.zig+32-25| ... | ... | @@ -8,6 +8,8 @@ const Allocator = std.mem.Allocator; |
| 8 | 8 | const assert = std.debug.assert; |
| 9 | 9 | const math = std.math; |
| 10 | 10 | |
| 11 | const is_darwin = std.Target.current.os.tag.isDarwin(); | |
| 12 | ||
| 11 | 13 | pub const path = @import("fs/path.zig"); |
| 12 | 14 | pub const File = @import("fs/file.zig").File; |
| 13 | 15 | |
| ... | ... | @@ -597,8 +599,11 @@ pub const Dir = struct { |
| 597 | 599 | |
| 598 | 600 | // Use the O_ locking flags if the os supports them |
| 599 | 601 | // (Or if it's darwin, as darwin's `open` doesn't support the O_SYNC flag) |
| 600 | const has_flock_open_flags = @hasDecl(os, "O_EXLOCK") and !builtin.os.tag.isDarwin(); | |
| 601 | const nonblocking_lock_flag = if (has_flock_open_flags and flags.lock_nonblocking) (os.O_NONBLOCK | os.O_SYNC) else @as(u32, 0); | |
| 602 | const has_flock_open_flags = @hasDecl(os, "O_EXLOCK") and !is_darwin; | |
| 603 | const nonblocking_lock_flag = if (has_flock_open_flags and flags.lock_nonblocking) | |
| 604 | os.O_NONBLOCK | os.O_SYNC | |
| 605 | else | |
| 606 | @as(u32, 0); | |
| 602 | 607 | const lock_flag: u32 = if (has_flock_open_flags) switch (flags.lock) { |
| 603 | 608 | .None => @as(u32, 0), |
| 604 | 609 | .Shared => os.O_SHLOCK | nonblocking_lock_flag, |
| ... | ... | @@ -612,7 +617,7 @@ pub const Dir = struct { |
| 612 | 617 | @as(u32, os.O_WRONLY) |
| 613 | 618 | else |
| 614 | 619 | @as(u32, os.O_RDONLY); |
| 615 | const fd = if (need_async_thread and !flags.always_blocking) | |
| 620 | const fd = if (flags.intended_io_mode != .blocking) | |
| 616 | 621 | try std.event.Loop.instance.?.openatZ(self.fd, sub_path, os_flags, 0) |
| 617 | 622 | else |
| 618 | 623 | try os.openatZ(self.fd, sub_path, os_flags, 0); |
| ... | ... | @@ -629,11 +634,8 @@ pub const Dir = struct { |
| 629 | 634 | |
| 630 | 635 | return File{ |
| 631 | 636 | .handle = fd, |
| 632 | .io_mode = .blocking, | |
| 633 | .async_block_allowed = if (flags.always_blocking) | |
| 634 | File.async_block_allowed_yes | |
| 635 | else | |
| 636 | File.async_block_allowed_no, | |
| 637 | .capable_io_mode = .blocking, | |
| 638 | .intended_io_mode = flags.intended_io_mode, | |
| 637 | 639 | }; |
| 638 | 640 | } |
| 639 | 641 | |
| ... | ... | @@ -648,19 +650,16 @@ pub const Dir = struct { |
| 648 | 650 | (if (flags.read) @as(u32, w.GENERIC_READ) else 0) | |
| 649 | 651 | (if (flags.write) @as(u32, w.GENERIC_WRITE) else 0), |
| 650 | 652 | .share_access = switch (flags.lock) { |
| 651 | .None => @as(?w.ULONG, null), | |
| 653 | .None => w.FILE_SHARE_WRITE | w.FILE_SHARE_READ | w.FILE_SHARE_DELETE, | |
| 652 | 654 | .Shared => w.FILE_SHARE_READ | w.FILE_SHARE_DELETE, |
| 653 | 655 | .Exclusive => w.FILE_SHARE_DELETE, |
| 654 | 656 | }, |
| 655 | 657 | .share_access_nonblocking = flags.lock_nonblocking, |
| 656 | 658 | .creation = w.FILE_OPEN, |
| 657 | .enable_async_io = std.io.is_async and !flags.always_blocking, | |
| 659 | .io_mode = flags.intended_io_mode, | |
| 658 | 660 | }), |
| 659 | .io_mode = .blocking, | |
| 660 | .async_block_allowed = if (flags.always_blocking) | |
| 661 | File.async_block_allowed_yes | |
| 662 | else | |
| 663 | File.async_block_allowed_no, | |
| 661 | .capable_io_mode = std.io.default_mode, | |
| 662 | .intended_io_mode = flags.intended_io_mode, | |
| 664 | 663 | }); |
| 665 | 664 | } |
| 666 | 665 | |
| ... | ... | @@ -687,8 +686,11 @@ pub const Dir = struct { |
| 687 | 686 | |
| 688 | 687 | // Use the O_ locking flags if the os supports them |
| 689 | 688 | // (Or if it's darwin, as darwin's `open` doesn't support the O_SYNC flag) |
| 690 | const has_flock_open_flags = @hasDecl(os, "O_EXLOCK") and !builtin.os.tag.isDarwin(); | |
| 691 | const nonblocking_lock_flag = if (has_flock_open_flags and flags.lock_nonblocking) (os.O_NONBLOCK | os.O_SYNC) else @as(u32, 0); | |
| 689 | const has_flock_open_flags = @hasDecl(os, "O_EXLOCK") and !is_darwin; | |
| 690 | const nonblocking_lock_flag: u32 = if (has_flock_open_flags and flags.lock_nonblocking) | |
| 691 | os.O_NONBLOCK | os.O_SYNC | |
| 692 | else | |
| 693 | 0; | |
| 692 | 694 | const lock_flag: u32 = if (has_flock_open_flags) switch (flags.lock) { |
| 693 | 695 | .None => @as(u32, 0), |
| 694 | 696 | .Shared => os.O_SHLOCK, |
| ... | ... | @@ -700,7 +702,7 @@ pub const Dir = struct { |
| 700 | 702 | (if (flags.truncate) @as(u32, os.O_TRUNC) else 0) | |
| 701 | 703 | (if (flags.read) @as(u32, os.O_RDWR) else os.O_WRONLY) | |
| 702 | 704 | (if (flags.exclusive) @as(u32, os.O_EXCL) else 0); |
| 703 | const fd = if (need_async_thread) | |
| 705 | const fd = if (flags.intended_io_mode != .blocking) | |
| 704 | 706 | try std.event.Loop.instance.?.openatZ(self.fd, sub_path_c, os_flags, flags.mode) |
| 705 | 707 | else |
| 706 | 708 | try os.openatZ(self.fd, sub_path_c, os_flags, flags.mode); |
| ... | ... | @@ -715,7 +717,11 @@ pub const Dir = struct { |
| 715 | 717 | }); |
| 716 | 718 | } |
| 717 | 719 | |
| 718 | return File{ .handle = fd, .io_mode = .blocking }; | |
| 720 | return File{ | |
| 721 | .handle = fd, | |
| 722 | .capable_io_mode = .blocking, | |
| 723 | .intended_io_mode = flags.intended_io_mode, | |
| 724 | }; | |
| 719 | 725 | } |
| 720 | 726 | |
| 721 | 727 | /// Same as `createFile` but Windows-only and the path parameter is |
| ... | ... | @@ -739,9 +745,10 @@ pub const Dir = struct { |
| 739 | 745 | @as(u32, w.FILE_OVERWRITE_IF) |
| 740 | 746 | else |
| 741 | 747 | @as(u32, w.FILE_OPEN_IF), |
| 742 | .enable_async_io = std.io.is_async, | |
| 748 | .io_mode = flags.intended_io_mode, | |
| 743 | 749 | }), |
| 744 | .io_mode = .blocking, | |
| 750 | .capable_io_mode = std.io.default_mode, | |
| 751 | .intended_io_mode = flags.intended_io_mode, | |
| 745 | 752 | }); |
| 746 | 753 | } |
| 747 | 754 | |
| ... | ... | @@ -1257,7 +1264,7 @@ pub const Dir = struct { |
| 1257 | 1264 | @as(u32, os.W_OK) |
| 1258 | 1265 | else |
| 1259 | 1266 | @as(u32, os.F_OK); |
| 1260 | const result = if (need_async_thread) | |
| 1267 | const result = if (need_async_thread and flags.intended_io_mode != .blocking) | |
| 1261 | 1268 | std.event.Loop.instance.?.faccessatZ(self.fd, sub_path, os_mode, 0) |
| 1262 | 1269 | else |
| 1263 | 1270 | os.faccessatZ(self.fd, sub_path, os_mode, 0); |
| ... | ... | @@ -1399,8 +1406,8 @@ pub fn openFileAbsoluteZ(absolute_path_c: [*:0]const u8, flags: File.OpenFlags) |
| 1399 | 1406 | } |
| 1400 | 1407 | |
| 1401 | 1408 | /// Same as `openFileAbsolute` but the path parameter is WTF-16 encoded. |
| 1402 | pub fn openFileAbsoluteW(absolute_path_w: [*:0]const u16, flags: File.OpenFlags) File.OpenError!File { | |
| 1403 | assert(path.isAbsoluteWindowsW(absolute_path_w)); | |
| 1409 | pub fn openFileAbsoluteW(absolute_path_w: []const u16, flags: File.OpenFlags) File.OpenError!File { | |
| 1410 | assert(path.isAbsoluteWindowsWTF16(absolute_path_w)); | |
| 1404 | 1411 | return cwd().openFileW(absolute_path_w, flags); |
| 1405 | 1412 | } |
| 1406 | 1413 | |
| ... | ... | @@ -1617,7 +1624,7 @@ pub fn selfExePathAlloc(allocator: *Allocator) ![]u8 { |
| 1617 | 1624 | /// been deleted, the file path looks something like `/a/b/c/exe (deleted)`. |
| 1618 | 1625 | /// TODO make the return type of this a null terminated pointer |
| 1619 | 1626 | pub fn selfExePath(out_buffer: *[MAX_PATH_BYTES]u8) SelfExePathError![]u8 { |
| 1620 | if (comptime std.Target.current.isDarwin()) { | |
| 1627 | if (is_darwin) { | |
| 1621 | 1628 | var u32_len: u32 = out_buffer.len; |
| 1622 | 1629 | const rc = std.c._NSGetExecutablePath(out_buffer, &u32_len); |
| 1623 | 1630 | if (rc != 0) return error.NameTooLong; |
lib/std/fs/file.zig+33-44| ... | ... | @@ -8,7 +8,6 @@ const assert = std.debug.assert; |
| 8 | 8 | const windows = os.windows; |
| 9 | 9 | const Os = builtin.Os; |
| 10 | 10 | const maxInt = std.math.maxInt; |
| 11 | const need_async_thread = std.fs.need_async_thread; | |
| 12 | 11 | |
| 13 | 12 | pub const File = struct { |
| 14 | 13 | /// The OS-specific file descriptor or file handle. |
| ... | ... | @@ -17,15 +16,14 @@ pub const File = struct { |
| 17 | 16 | /// On some systems, such as Linux, file system file descriptors are incapable of non-blocking I/O. |
| 18 | 17 | /// This forces us to perform asynchronous I/O on a dedicated thread, to achieve non-blocking |
| 19 | 18 | /// file-system I/O. To do this, `File` must be aware of whether it is a file system file descriptor, |
| 20 | /// or, more specifically, whether the I/O is blocking. | |
| 21 | io_mode: io.Mode, | |
| 19 | /// or, more specifically, whether the I/O is always blocking. | |
| 20 | capable_io_mode: io.ModeOverride = io.default_mode, | |
| 22 | 21 | |
| 23 | /// Even when 'std.io.mode' is async, it is still sometimes desirable to perform blocking I/O, although | |
| 24 | /// not by default. For example, when printing a stack trace to stderr. | |
| 25 | async_block_allowed: @TypeOf(async_block_allowed_no) = async_block_allowed_no, | |
| 26 | ||
| 27 | pub const async_block_allowed_yes = if (io.is_async) true else {}; | |
| 28 | pub const async_block_allowed_no = if (io.is_async) false else {}; | |
| 22 | /// Furthermore, even when `std.io.mode` is async, it is still sometimes desirable to perform blocking I/O, | |
| 23 | /// although not by default. For example, when printing a stack trace to stderr. | |
| 24 | /// This field tracks both by acting as an overriding I/O mode. When not building in async I/O mode, | |
| 25 | /// the type only has the `.blocking` tag, making it a zero-bit type. | |
| 26 | intended_io_mode: io.ModeOverride = io.default_mode, | |
| 29 | 27 | |
| 30 | 28 | pub const Mode = os.mode_t; |
| 31 | 29 | |
| ... | ... | @@ -36,9 +34,7 @@ pub const File = struct { |
| 36 | 34 | |
| 37 | 35 | pub const OpenError = windows.CreateFileError || os.OpenError || os.FlockError; |
| 38 | 36 | |
| 39 | pub const Lock = enum { | |
| 40 | None, Shared, Exclusive | |
| 41 | }; | |
| 37 | pub const Lock = enum { None, Shared, Exclusive }; | |
| 42 | 38 | |
| 43 | 39 | /// TODO https://github.com/ziglang/zig/issues/3802 |
| 44 | 40 | pub const OpenFlags = struct { |
| ... | ... | @@ -62,15 +58,16 @@ pub const File = struct { |
| 62 | 58 | |
| 63 | 59 | /// Sets whether or not to wait until the file is locked to return. If set to true, |
| 64 | 60 | /// `error.WouldBlock` will be returned. Otherwise, the file will wait until the file |
| 65 | /// is available to proceed. In async I/O mode, non-blocking at the OS level is always | |
| 66 | /// used, and `true` means `error.WouldBlock` is returned, and `false` means | |
| 67 | /// `error.WouldBlock` is handled by the event loop. | |
| 61 | /// is available to proceed. | |
| 62 | /// In async I/O mode, non-blocking at the OS level is | |
| 63 | /// determined by `intended_io_mode`, and `true` means `error.WouldBlock` is returned, | |
| 64 | /// and `false` means `error.WouldBlock` is handled by the event loop. | |
| 68 | 65 | lock_nonblocking: bool = false, |
| 69 | 66 | |
| 70 | /// This prevents `O_NONBLOCK` from being passed even if `std.io.is_async`. | |
| 71 | /// It allows the use of `noasync` when calling functions related to opening | |
| 72 | /// the file, reading, writing, as well as locking functionality. | |
| 73 | always_blocking: bool = false, | |
| 67 | /// Setting this to `.blocking` prevents `O_NONBLOCK` from being passed even | |
| 68 | /// if `std.io.is_async`. It allows the use of `noasync` when calling functions | |
| 69 | /// related to opening the file, reading, writing, and locking. | |
| 70 | intended_io_mode: io.ModeOverride = io.default_mode, | |
| 74 | 71 | }; |
| 75 | 72 | |
| 76 | 73 | /// TODO https://github.com/ziglang/zig/issues/3802 |
| ... | ... | @@ -104,17 +101,25 @@ pub const File = struct { |
| 104 | 101 | /// Sets whether or not to wait until the file is locked to return. If set to true, |
| 105 | 102 | /// `error.WouldBlock` will be returned. Otherwise, the file will wait until the file |
| 106 | 103 | /// is available to proceed. |
| 104 | /// In async I/O mode, non-blocking at the OS level is | |
| 105 | /// determined by `intended_io_mode`, and `true` means `error.WouldBlock` is returned, | |
| 106 | /// and `false` means `error.WouldBlock` is handled by the event loop. | |
| 107 | 107 | lock_nonblocking: bool = false, |
| 108 | 108 | |
| 109 | 109 | /// For POSIX systems this is the file system mode the file will |
| 110 | 110 | /// be created with. |
| 111 | 111 | mode: Mode = default_mode, |
| 112 | ||
| 113 | /// Setting this to `.blocking` prevents `O_NONBLOCK` from being passed even | |
| 114 | /// if `std.io.is_async`. It allows the use of `noasync` when calling functions | |
| 115 | /// related to opening the file, reading, writing, and locking. | |
| 116 | intended_io_mode: io.ModeOverride = io.default_mode, | |
| 112 | 117 | }; |
| 113 | 118 | |
| 114 | 119 | /// Upon success, the stream is in an uninitialized state. To continue using it, |
| 115 | 120 | /// you must use the open() function. |
| 116 | 121 | pub fn close(self: File) void { |
| 117 | if (need_async_thread and self.io_mode == .blocking and !self.async_block_allowed) { | |
| 122 | if (self.capable_io_mode != self.intended_io_mode) { | |
| 118 | 123 | std.event.Loop.instance.?.close(self.handle); |
| 119 | 124 | } else { |
| 120 | 125 | os.close(self.handle); |
| ... | ... | @@ -297,11 +302,7 @@ pub const File = struct { |
| 297 | 302 | pub const PReadError = os.PReadError; |
| 298 | 303 | |
| 299 | 304 | pub fn read(self: File, buffer: []u8) ReadError!usize { |
| 300 | if (builtin.os.tag == .windows) { | |
| 301 | const enable_async_io = std.io.is_async and !self.async_block_allowed; | |
| 302 | return windows.ReadFile(self.handle, buffer, null, enable_async_io); | |
| 303 | } | |
| 304 | if (need_async_thread and self.io_mode == .blocking and !self.async_block_allowed) { | |
| 305 | if (self.capable_io_mode != self.intended_io_mode) { | |
| 305 | 306 | return std.event.Loop.instance.?.read(self.handle, buffer); |
| 306 | 307 | } else { |
| 307 | 308 | return os.read(self.handle, buffer); |
| ... | ... | @@ -321,11 +322,7 @@ pub const File = struct { |
| 321 | 322 | } |
| 322 | 323 | |
| 323 | 324 | pub fn pread(self: File, buffer: []u8, offset: u64) PReadError!usize { |
| 324 | if (builtin.os.tag == .windows) { | |
| 325 | const enable_async_io = std.io.is_async and !self.async_block_allowed; | |
| 326 | return windows.ReadFile(self.handle, buffer, offset, enable_async_io); | |
| 327 | } | |
| 328 | if (need_async_thread and self.io_mode == .blocking and !self.async_block_allowed) { | |
| 325 | if (self.capable_io_mode != self.intended_io_mode) { | |
| 329 | 326 | return std.event.Loop.instance.?.pread(self.handle, buffer, offset); |
| 330 | 327 | } else { |
| 331 | 328 | return os.pread(self.handle, buffer, offset); |
| ... | ... | @@ -345,7 +342,7 @@ pub const File = struct { |
| 345 | 342 | } |
| 346 | 343 | |
| 347 | 344 | pub fn readv(self: File, iovecs: []const os.iovec) ReadError!usize { |
| 348 | if (need_async_thread and self.io_mode == .blocking and !self.async_block_allowed) { | |
| 345 | if (self.capable_io_mode != self.intended_io_mode) { | |
| 349 | 346 | return std.event.Loop.instance.?.readv(self.handle, iovecs); |
| 350 | 347 | } else { |
| 351 | 348 | return os.readv(self.handle, iovecs); |
| ... | ... | @@ -379,7 +376,7 @@ pub const File = struct { |
| 379 | 376 | } |
| 380 | 377 | |
| 381 | 378 | pub fn preadv(self: File, iovecs: []const os.iovec, offset: u64) PReadError!usize { |
| 382 | if (need_async_thread and self.io_mode == .blocking and !self.async_block_allowed) { | |
| 379 | if (self.capable_io_mode != self.intended_io_mode) { | |
| 383 | 380 | return std.event.Loop.instance.?.preadv(self.handle, iovecs, offset); |
| 384 | 381 | } else { |
| 385 | 382 | return os.preadv(self.handle, iovecs, offset); |
| ... | ... | @@ -416,11 +413,7 @@ pub const File = struct { |
| 416 | 413 | pub const PWriteError = os.PWriteError; |
| 417 | 414 | |
| 418 | 415 | pub fn write(self: File, bytes: []const u8) WriteError!usize { |
| 419 | if (builtin.os.tag == .windows) { | |
| 420 | const enable_async_io = std.io.is_async and !self.async_block_allowed; | |
| 421 | return windows.WriteFile(self.handle, bytes, null, enable_async_io); | |
| 422 | } | |
| 423 | if (need_async_thread and self.io_mode == .blocking and !self.async_block_allowed) { | |
| 416 | if (self.capable_io_mode != self.intended_io_mode) { | |
| 424 | 417 | return std.event.Loop.instance.?.write(self.handle, bytes); |
| 425 | 418 | } else { |
| 426 | 419 | return os.write(self.handle, bytes); |
| ... | ... | @@ -435,11 +428,7 @@ pub const File = struct { |
| 435 | 428 | } |
| 436 | 429 | |
| 437 | 430 | pub fn pwrite(self: File, bytes: []const u8, offset: u64) PWriteError!usize { |
| 438 | if (builtin.os.tag == .windows) { | |
| 439 | const enable_async_io = std.io.is_async and !self.async_block_allowed; | |
| 440 | return windows.WriteFile(self.handle, bytes, offset, enable_async_io); | |
| 441 | } | |
| 442 | if (need_async_thread and self.io_mode == .blocking and !self.async_block_allowed) { | |
| 431 | if (self.capable_io_mode != self.intended_io_mode) { | |
| 443 | 432 | return std.event.Loop.instance.?.pwrite(self.handle, bytes, offset); |
| 444 | 433 | } else { |
| 445 | 434 | return os.pwrite(self.handle, bytes, offset); |
| ... | ... | @@ -454,7 +443,7 @@ pub const File = struct { |
| 454 | 443 | } |
| 455 | 444 | |
| 456 | 445 | pub fn writev(self: File, iovecs: []const os.iovec_const) WriteError!usize { |
| 457 | if (need_async_thread and self.io_mode == .blocking and !self.async_block_allowed) { | |
| 446 | if (self.capable_io_mode != self.intended_io_mode) { | |
| 458 | 447 | return std.event.Loop.instance.?.writev(self.handle, iovecs); |
| 459 | 448 | } else { |
| 460 | 449 | return os.writev(self.handle, iovecs); |
| ... | ... | @@ -480,7 +469,7 @@ pub const File = struct { |
| 480 | 469 | } |
| 481 | 470 | |
| 482 | 471 | pub fn pwritev(self: File, iovecs: []os.iovec_const, offset: usize) PWriteError!usize { |
| 483 | if (need_async_thread and self.io_mode == .blocking and !self.async_block_allowed) { | |
| 472 | if (self.capable_io_mode != self.intended_io_mode) { | |
| 484 | 473 | return std.event.Loop.instance.?.pwritev(self.handle, iovecs, offset); |
| 485 | 474 | } else { |
| 486 | 475 | return os.pwritev(self.handle, iovecs, offset); |
lib/std/fs/test.zig+11-1| ... | ... | @@ -27,7 +27,12 @@ test "open file with exclusive nonblocking lock twice" { |
| 27 | 27 | } |
| 28 | 28 | |
| 29 | 29 | test "open file with lock twice, make sure it wasn't open at the same time" { |
| 30 | if (builtin.single_threaded) return; | |
| 30 | if (builtin.single_threaded) return error.SkipZigTest; | |
| 31 | ||
| 32 | if (std.io.is_async) { | |
| 33 | // This test starts its own threads and is not compatible with async I/O. | |
| 34 | return error.SkipZigTest; | |
| 35 | } | |
| 31 | 36 | |
| 32 | 37 | const filename = "file_lock_test.txt"; |
| 33 | 38 | |
| ... | ... | @@ -58,6 +63,11 @@ test "open file with lock twice, make sure it wasn't open at the same time" { |
| 58 | 63 | test "create file, lock and read from multiple process at once" { |
| 59 | 64 | if (builtin.single_threaded) return error.SkipZigTest; |
| 60 | 65 | |
| 66 | if (std.io.is_async) { | |
| 67 | // This test starts its own threads and is not compatible with async I/O. | |
| 68 | return error.SkipZigTest; | |
| 69 | } | |
| 70 | ||
| 61 | 71 | if (true) { |
| 62 | 72 | // https://github.com/ziglang/zig/issues/5006 |
| 63 | 73 | return error.SkipZigTest; |
lib/std/io.zig+17-8| ... | ... | @@ -30,6 +30,11 @@ else |
| 30 | 30 | Mode.blocking; |
| 31 | 31 | pub const is_async = mode != .blocking; |
| 32 | 32 | |
| 33 | /// This is an enum value to use for I/O mode at runtime, since it takes up zero bytes at runtime, | |
| 34 | /// and makes expressions comptime-known when `is_async` is `false`. | |
| 35 | pub const ModeOverride = if (is_async) Mode else enum { blocking }; | |
| 36 | pub const default_mode: ModeOverride = if (is_async) Mode.evented else .blocking; | |
| 37 | ||
| 33 | 38 | fn getStdOutHandle() os.fd_t { |
| 34 | 39 | if (builtin.os.tag == .windows) { |
| 35 | 40 | return os.windows.peb().ProcessParameters.hStdOutput; |
| ... | ... | @@ -42,12 +47,13 @@ fn getStdOutHandle() os.fd_t { |
| 42 | 47 | return os.STDOUT_FILENO; |
| 43 | 48 | } |
| 44 | 49 | |
| 45 | // TODO: async stdout on windows (https://github.com/ziglang/zig/pull/4816#issuecomment-604521023) | |
| 50 | /// TODO: async stdout on windows without a dedicated thread. | |
| 51 | /// https://github.com/ziglang/zig/pull/4816#issuecomment-604521023 | |
| 46 | 52 | pub fn getStdOut() File { |
| 47 | 53 | return File{ |
| 48 | 54 | .handle = getStdOutHandle(), |
| 49 | .io_mode = .blocking, | |
| 50 | .async_block_allowed = if (builtin.os.tag == .windows) File.async_block_allowed_yes else File.async_block_allowed_no, | |
| 55 | .capable_io_mode = .blocking, | |
| 56 | .intended_io_mode = default_mode, | |
| 51 | 57 | }; |
| 52 | 58 | } |
| 53 | 59 | |
| ... | ... | @@ -63,11 +69,13 @@ fn getStdErrHandle() os.fd_t { |
| 63 | 69 | return os.STDERR_FILENO; |
| 64 | 70 | } |
| 65 | 71 | |
| 72 | /// This returns a `File` that is configured to block with every write, in order | |
| 73 | /// to facilitate better debugging. This can be changed by modifying the `intended_io_mode` field. | |
| 66 | 74 | pub fn getStdErr() File { |
| 67 | 75 | return File{ |
| 68 | 76 | .handle = getStdErrHandle(), |
| 69 | .io_mode = .blocking, | |
| 70 | .async_block_allowed = File.async_block_allowed_yes, | |
| 77 | .capable_io_mode = .blocking, | |
| 78 | .intended_io_mode = .blocking, | |
| 71 | 79 | }; |
| 72 | 80 | } |
| 73 | 81 | |
| ... | ... | @@ -83,12 +91,13 @@ fn getStdInHandle() os.fd_t { |
| 83 | 91 | return os.STDIN_FILENO; |
| 84 | 92 | } |
| 85 | 93 | |
| 86 | // TODO: async stdin on windows (https://github.com/ziglang/zig/pull/4816#issuecomment-604521023) | |
| 94 | /// TODO: async stdin on windows without a dedicated thread. | |
| 95 | /// https://github.com/ziglang/zig/pull/4816#issuecomment-604521023 | |
| 87 | 96 | pub fn getStdIn() File { |
| 88 | 97 | return File{ |
| 89 | 98 | .handle = getStdInHandle(), |
| 90 | .io_mode = .blocking, | |
| 91 | .async_block_allowed = if (builtin.os.tag == .windows) File.async_block_allowed_yes else File.async_block_allowed_no, | |
| 99 | .capable_io_mode = .blocking, | |
| 100 | .intended_io_mode = default_mode, | |
| 92 | 101 | }; |
| 93 | 102 | } |
| 94 | 103 |
lib/std/net.zig+2-5| ... | ... | @@ -412,7 +412,7 @@ pub fn tcpConnectToAddress(address: Address) !fs.File { |
| 412 | 412 | errdefer os.close(sockfd); |
| 413 | 413 | try os.connect(sockfd, &address.any, address.getOsSockLen()); |
| 414 | 414 | |
| 415 | return fs.File{ .handle = sockfd, .io_mode = std.io.mode }; | |
| 415 | return fs.File{ .handle = sockfd }; | |
| 416 | 416 | } |
| 417 | 417 | |
| 418 | 418 | /// Call `AddressList.deinit` on the result. |
| ... | ... | @@ -1381,10 +1381,7 @@ pub const StreamServer = struct { |
| 1381 | 1381 | var adr_len: os.socklen_t = @sizeOf(Address); |
| 1382 | 1382 | if (os.accept4(self.sockfd.?, &accepted_addr.any, &adr_len, accept_flags)) |fd| { |
| 1383 | 1383 | return Connection{ |
| 1384 | .file = fs.File{ | |
| 1385 | .handle = fd, | |
| 1386 | .io_mode = std.io.mode, | |
| 1387 | }, | |
| 1384 | .file = fs.File{ .handle = fd }, | |
| 1388 | 1385 | .address = accepted_addr, |
| 1389 | 1386 | }; |
| 1390 | 1387 | } else |err| switch (err) { |
lib/std/os.zig+6-6| ... | ... | @@ -173,8 +173,8 @@ fn getRandomBytesDevURandom(buf: []u8) !void { |
| 173 | 173 | |
| 174 | 174 | const file = std.fs.File{ |
| 175 | 175 | .handle = fd, |
| 176 | .io_mode = .blocking, | |
| 177 | .async_block_allowed = std.fs.File.async_block_allowed_yes, | |
| 176 | .capable_io_mode = .blocking, | |
| 177 | .intended_io_mode = .blocking, | |
| 178 | 178 | }; |
| 179 | 179 | const stream = file.inStream(); |
| 180 | 180 | stream.readNoEof(buf) catch return error.Unexpected; |
| ... | ... | @@ -305,7 +305,7 @@ pub const ReadError = error{ |
| 305 | 305 | /// For POSIX the limit is `math.maxInt(isize)`. |
| 306 | 306 | pub fn read(fd: fd_t, buf: []u8) ReadError!usize { |
| 307 | 307 | if (builtin.os.tag == .windows) { |
| 308 | return windows.ReadFile(fd, buf, null, false); | |
| 308 | return windows.ReadFile(fd, buf, null, std.io.default_mode); | |
| 309 | 309 | } |
| 310 | 310 | |
| 311 | 311 | if (builtin.os.tag == .wasi and !builtin.link_libc) { |
| ... | ... | @@ -408,7 +408,7 @@ pub const PReadError = ReadError || error{Unseekable}; |
| 408 | 408 | /// used to perform the I/O. `error.WouldBlock` is not possible on Windows. |
| 409 | 409 | pub fn pread(fd: fd_t, buf: []u8, offset: u64) PReadError!usize { |
| 410 | 410 | if (builtin.os.tag == .windows) { |
| 411 | return windows.ReadFile(fd, buf, offset, false); | |
| 411 | return windows.ReadFile(fd, buf, offset, std.io.default_mode); | |
| 412 | 412 | } |
| 413 | 413 | |
| 414 | 414 | while (true) { |
| ... | ... | @@ -584,7 +584,7 @@ pub const WriteError = error{ |
| 584 | 584 | /// The corresponding POSIX limit is `math.maxInt(isize)`. |
| 585 | 585 | pub fn write(fd: fd_t, bytes: []const u8) WriteError!usize { |
| 586 | 586 | if (builtin.os.tag == .windows) { |
| 587 | return windows.WriteFile(fd, bytes, null, false); | |
| 587 | return windows.WriteFile(fd, bytes, null, std.io.default_mode); | |
| 588 | 588 | } |
| 589 | 589 | |
| 590 | 590 | if (builtin.os.tag == .wasi and !builtin.link_libc) { |
| ... | ... | @@ -709,7 +709,7 @@ pub const PWriteError = WriteError || error{Unseekable}; |
| 709 | 709 | /// The corresponding POSIX limit is `math.maxInt(isize)`. |
| 710 | 710 | pub fn pwrite(fd: fd_t, bytes: []const u8, offset: u64) PWriteError!usize { |
| 711 | 711 | if (std.Target.current.os.tag == .windows) { |
| 712 | return windows.WriteFile(fd, bytes, offset, false); | |
| 712 | return windows.WriteFile(fd, bytes, offset, std.io.default_mode); | |
| 713 | 713 | } |
| 714 | 714 | |
| 715 | 715 | // Prevent EINVAL. |
lib/std/os/windows.zig+25-10| ... | ... | @@ -110,7 +110,7 @@ pub const OpenFileOptions = struct { |
| 110 | 110 | share_access: ULONG = FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_SHARE_DELETE, |
| 111 | 111 | share_access_nonblocking: bool = false, |
| 112 | 112 | creation: ULONG, |
| 113 | enable_async_io: bool = std.io.is_async, | |
| 113 | io_mode: std.io.ModeOverride, | |
| 114 | 114 | }; |
| 115 | 115 | |
| 116 | 116 | /// TODO when share_access_nonblocking is false, this implementation uses |
| ... | ... | @@ -145,7 +145,7 @@ pub fn OpenFile(sub_path_w: []const u16, options: OpenFileOptions) OpenError!HAN |
| 145 | 145 | |
| 146 | 146 | var delay: usize = 1; |
| 147 | 147 | while (true) { |
| 148 | const blocking_flag: ULONG = if (!options.enable_async_io) FILE_SYNCHRONOUS_IO_NONALERT else 0; | |
| 148 | const blocking_flag: ULONG = if (options.io_mode == .blocking) FILE_SYNCHRONOUS_IO_NONALERT else 0; | |
| 149 | 149 | const rc = ntdll.NtCreateFile( |
| 150 | 150 | &result, |
| 151 | 151 | options.access_mask, |
| ... | ... | @@ -451,11 +451,11 @@ pub const ReadFileError = error{ |
| 451 | 451 | |
| 452 | 452 | /// If buffer's length exceeds what a Windows DWORD integer can hold, it will be broken into |
| 453 | 453 | /// multiple non-atomic reads. |
| 454 | pub fn ReadFile(in_hFile: HANDLE, buffer: []u8, offset: ?u64, enable_async_io: bool) ReadFileError!usize { | |
| 455 | if (std.event.Loop.instance != null and enable_async_io) { | |
| 454 | pub fn ReadFile(in_hFile: HANDLE, buffer: []u8, offset: ?u64, io_mode: std.io.ModeOverride) ReadFileError!usize { | |
| 455 | if (io_mode != .blocking) { | |
| 456 | 456 | const loop = std.event.Loop.instance.?; |
| 457 | // TODO support async ReadFile with no offset | |
| 458 | const off = if (offset == null) 0 else offset.?; | |
| 457 | // TODO make getting the file position non-blocking | |
| 458 | const off = if (offset) |o| o else try SetFilePointerEx_CURRENT_get(in_hFile); | |
| 459 | 459 | var resume_node = std.event.Loop.ResumeNode.Basic{ |
| 460 | 460 | .base = .{ |
| 461 | 461 | .id = .Basic, |
| ... | ... | @@ -486,6 +486,11 @@ pub fn ReadFile(in_hFile: HANDLE, buffer: []u8, offset: ?u64, enable_async_io: b |
| 486 | 486 | else => |err| return unexpectedError(err), |
| 487 | 487 | } |
| 488 | 488 | } |
| 489 | if (offset == null) { | |
| 490 | // TODO make setting the file position non-blocking | |
| 491 | const new_off = off + bytes_transferred; | |
| 492 | try SetFilePointerEx_CURRENT(in_hFile, @bitCast(i64, new_off)); | |
| 493 | } | |
| 489 | 494 | return @as(usize, bytes_transferred); |
| 490 | 495 | } else { |
| 491 | 496 | var index: usize = 0; |
| ... | ... | @@ -525,11 +530,16 @@ pub const WriteFileError = error{ |
| 525 | 530 | Unexpected, |
| 526 | 531 | }; |
| 527 | 532 | |
| 528 | pub fn WriteFile(handle: HANDLE, bytes: []const u8, offset: ?u64, enable_async_io: bool) WriteFileError!usize { | |
| 529 | if (std.event.Loop.instance != null and enable_async_io) { | |
| 533 | pub fn WriteFile( | |
| 534 | handle: HANDLE, | |
| 535 | bytes: []const u8, | |
| 536 | offset: ?u64, | |
| 537 | io_mode: std.io.ModeOverride, | |
| 538 | ) WriteFileError!usize { | |
| 539 | if (std.event.Loop.instance != null and io_mode != .blocking) { | |
| 530 | 540 | const loop = std.event.Loop.instance.?; |
| 531 | // TODO support async WriteFile with no offset | |
| 532 | const off = if (offset == null) 0 else offset.?; | |
| 541 | // TODO make getting the file position non-blocking | |
| 542 | const off = if (offset) |o| o else try SetFilePointerEx_CURRENT_get(handle); | |
| 533 | 543 | var resume_node = std.event.Loop.ResumeNode.Basic{ |
| 534 | 544 | .base = .{ |
| 535 | 545 | .id = .Basic, |
| ... | ... | @@ -562,6 +572,11 @@ pub fn WriteFile(handle: HANDLE, bytes: []const u8, offset: ?u64, enable_async_i |
| 562 | 572 | else => |err| return unexpectedError(err), |
| 563 | 573 | } |
| 564 | 574 | } |
| 575 | if (offset == null) { | |
| 576 | // TODO make setting the file position non-blocking | |
| 577 | const new_off = off + bytes_transferred; | |
| 578 | try SetFilePointerEx_CURRENT(handle, @bitCast(i64, new_off)); | |
| 579 | } | |
| 565 | 580 | return bytes_transferred; |
| 566 | 581 | } else { |
| 567 | 582 | var bytes_written: DWORD = undefined; |
lib/std/pdb.zig+1-1| ... | ... | @@ -470,7 +470,7 @@ pub const Pdb = struct { |
| 470 | 470 | msf: Msf, |
| 471 | 471 | |
| 472 | 472 | pub fn openFile(self: *Pdb, coff_ptr: *coff.Coff, file_name: []u8) !void { |
| 473 | self.in_file = try fs.cwd().openFile(file_name, .{ .always_blocking = true }); | |
| 473 | self.in_file = try fs.cwd().openFile(file_name, .{ .intended_io_mode = .blocking }); | |
| 474 | 474 | self.allocator = coff_ptr.allocator; |
| 475 | 475 | self.coff = coff_ptr; |
| 476 | 476 |