From a4f27e8987ef3e2388839b6452b9f485ab82e7b7 Mon Sep 17 00:00:00 2001 From: Veikka Tuominen Date: Sun, 28 Jan 2024 01:04:38 +0200 Subject: [PATCH] remove std.io.Mode --- lib/std/Build/Step/Compile.zig | 5 - lib/std/Build/Step/Run.zig | 12 +- lib/std/builtin.zig | 1 - lib/std/child_process.zig | 15 +-- lib/std/debug.zig | 13 +-- lib/std/fs.zig | 7 -- lib/std/fs/Dir.zig | 71 ++---------- lib/std/fs/File.zig | 96 +++------------- lib/std/fs/test.zig | 5 - lib/std/io.zig | 39 +------ lib/std/net.zig | 79 +++---------- lib/std/net/test.zig | 48 -------- lib/std/os.zig | 35 +----- lib/std/os/windows.zig | 200 +++++++++------------------------ lib/std/pdb.zig | 2 +- lib/std/time.zig | 5 - lib/std/zig/Server.zig | 9 +- lib/std/zig/system/linux.zig | 2 +- lib/test_runner.zig | 28 +---- src/Builtin.zig | 12 -- src/Compilation.zig | 2 - src/Compilation/Config.zig | 3 - src/Module.zig | 6 - src/Package/Module.zig | 1 - src/main.zig | 2 - 25 files changed, 119 insertions(+), 579 deletions(-) diff --git a/lib/std/Build/Step/Compile.zig b/lib/std/Build/Step/Compile.zig index 72f9048485..9fb61d3572 100644 --- a/lib/std/Build/Step/Compile.zig +++ b/lib/std/Build/Step/Compile.zig @@ -55,7 +55,6 @@ global_base: ?u64 = null, zig_lib_dir: ?LazyPath, exec_cmd_args: ?[]const ?[]const u8, filter: ?[]const u8, -test_evented_io: bool = false, test_runner: ?[]const u8, test_server_mode: bool, wasi_exec_model: ?std.builtin.WasiExecModel = null, @@ -1294,10 +1293,6 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { try zig_args.append(filter); } - if (self.test_evented_io) { - try zig_args.append("--test-evented-io"); - } - if (self.test_runner) |test_runner| { try zig_args.append("--test-runner"); try zig_args.append(b.pathFromRoot(test_runner)); diff --git a/lib/std/Build/Step/Run.zig b/lib/std/Build/Step/Run.zig index de8f9816ab..3db531a36b 100644 --- a/lib/std/Build/Step/Run.zig +++ b/lib/std/Build/Step/Run.zig @@ -1147,19 +1147,14 @@ fn evalZigTest( test_count = tm_hdr.tests_len; const names_bytes = body[@sizeOf(TmHdr)..][0 .. test_count * @sizeOf(u32)]; - const async_frame_lens_bytes = body[@sizeOf(TmHdr) + names_bytes.len ..][0 .. test_count * @sizeOf(u32)]; - const expected_panic_msgs_bytes = body[@sizeOf(TmHdr) + names_bytes.len + async_frame_lens_bytes.len ..][0 .. test_count * @sizeOf(u32)]; - const string_bytes = body[@sizeOf(TmHdr) + names_bytes.len + async_frame_lens_bytes.len + expected_panic_msgs_bytes.len ..][0..tm_hdr.string_bytes_len]; + const expected_panic_msgs_bytes = body[@sizeOf(TmHdr) + names_bytes.len ..][0 .. test_count * @sizeOf(u32)]; + const string_bytes = body[@sizeOf(TmHdr) + names_bytes.len + expected_panic_msgs_bytes.len ..][0..tm_hdr.string_bytes_len]; const names = std.mem.bytesAsSlice(u32, names_bytes); - const async_frame_lens = std.mem.bytesAsSlice(u32, async_frame_lens_bytes); const expected_panic_msgs = std.mem.bytesAsSlice(u32, expected_panic_msgs_bytes); const names_aligned = try arena.alloc(u32, names.len); for (names_aligned, names) |*dest, src| dest.* = src; - const async_frame_lens_aligned = try arena.alloc(u32, async_frame_lens.len); - for (async_frame_lens_aligned, async_frame_lens) |*dest, src| dest.* = src; - const expected_panic_msgs_aligned = try arena.alloc(u32, expected_panic_msgs.len); for (expected_panic_msgs_aligned, expected_panic_msgs) |*dest, src| dest.* = src; @@ -1167,7 +1162,6 @@ fn evalZigTest( metadata = .{ .string_bytes = try arena.dupe(u8, string_bytes), .names = names_aligned, - .async_frame_lens = async_frame_lens_aligned, .expected_panic_msgs = expected_panic_msgs_aligned, .next_index = 0, .prog_node = prog_node, @@ -1237,7 +1231,6 @@ fn evalZigTest( const TestMetadata = struct { names: []const u32, - async_frame_lens: []const u32, expected_panic_msgs: []const u32, string_bytes: []const u8, next_index: u32, @@ -1253,7 +1246,6 @@ fn requestNextTest(in: fs.File, metadata: *TestMetadata, sub_prog_node: *?std.Pr const i = metadata.next_index; metadata.next_index += 1; - if (metadata.async_frame_lens[i] != 0) continue; if (metadata.expected_panic_msgs[i] != 0) continue; const name = metadata.testName(i); diff --git a/lib/std/builtin.zig b/lib/std/builtin.zig index 56ee990c5f..b7cd58d1e3 100644 --- a/lib/std/builtin.zig +++ b/lib/std/builtin.zig @@ -732,7 +732,6 @@ pub const CompilerBackend = enum(u64) { pub const TestFn = struct { name: []const u8, func: *const fn () anyerror!void, - async_frame_size: ?usize, }; /// This function type is used by the Zig language code generation and diff --git a/lib/std/child_process.zig b/lib/std/child_process.zig index 0a0c06ff89..6fecc4fd65 100644 --- a/lib/std/child_process.zig +++ b/lib/std/child_process.zig @@ -493,7 +493,7 @@ pub const ChildProcess = struct { } fn spawnPosix(self: *ChildProcess) SpawnError!void { - const pipe_flags = if (io.is_async) os.O.NONBLOCK else 0; + const pipe_flags = 0; const stdin_pipe = if (self.stdin_behavior == StdIo.Pipe) try os.pipe2(pipe_flags) else undefined; errdefer if (self.stdin_behavior == StdIo.Pipe) { destroyPipe(stdin_pipe); @@ -665,7 +665,6 @@ pub const ChildProcess = struct { .share_access = windows.FILE_SHARE_READ | windows.FILE_SHARE_WRITE, .sa = &saAttr, .creation = windows.OPEN_EXISTING, - .io_mode = .blocking, }) catch |err| switch (err) { error.PathAlreadyExists => unreachable, // not possible for "NUL" error.PipeBusy => unreachable, // not possible for "NUL" @@ -1491,20 +1490,12 @@ fn forkChildErrReport(fd: i32, err: ChildProcess.SpawnError) noreturn { const ErrInt = std.meta.Int(.unsigned, @sizeOf(anyerror) * 8); fn writeIntFd(fd: i32, value: ErrInt) !void { - const file = File{ - .handle = fd, - .capable_io_mode = .blocking, - .intended_io_mode = .blocking, - }; + const file = File{ .handle = fd }; file.writer().writeInt(u64, @intCast(value), .little) catch return error.SystemResources; } fn readIntFd(fd: i32) !ErrInt { - const file = File{ - .handle = fd, - .capable_io_mode = .blocking, - .intended_io_mode = .blocking, - }; + const file = File{ .handle = fd }; return @as(ErrInt, @intCast(file.reader().readInt(u64, .little) catch return error.SystemResources)); } diff --git a/lib/std/debug.zig b/lib/std/debug.zig index 5976e52684..216b1b20e6 100644 --- a/lib/std/debug.zig +++ b/lib/std/debug.zig @@ -1141,8 +1141,8 @@ pub fn readElfDebugInfo( ) !ModuleDebugInfo { nosuspend { const elf_file = (if (elf_filename) |filename| blk: { - break :blk fs.cwd().openFile(filename, .{ .intended_io_mode = .blocking }); - } else fs.openSelfExe(.{ .intended_io_mode = .blocking })) catch |err| switch (err) { + break :blk fs.cwd().openFile(filename, .{}); + } else fs.openSelfExe(.{})) catch |err| switch (err) { error.FileNotFound => return error.MissingDebugInfo, else => return err, }; @@ -1452,7 +1452,7 @@ fn readMachODebugInfo(allocator: mem.Allocator, macho_file: File) !ModuleDebugIn fn printLineFromFileAnyOs(out_stream: anytype, line_info: LineInfo) !void { // Need this to always block even in async I/O mode, because this could potentially // be called from e.g. the event loop code crashing. - var f = try fs.cwd().openFile(line_info.file_name, .{ .intended_io_mode = .blocking }); + var f = try fs.cwd().openFile(line_info.file_name, .{}); defer f.close(); // TODO fstat and make sure that the file has the correct size @@ -1640,7 +1640,6 @@ const MachoSymbol = struct { } }; -/// `file` is expected to have been opened with .intended_io_mode == .blocking. /// Takes ownership of file, even on error. /// TODO it's weird to take ownership even on error, rework this code. fn mapWholeFile(file: File) ![]align(mem.page_size) const u8 { @@ -1824,9 +1823,7 @@ pub const DebugInfo = struct { errdefer self.allocator.destroy(obj_di); const macho_path = mem.sliceTo(std.c._dyld_get_image_name(i), 0); - const macho_file = fs.cwd().openFile(macho_path, .{ - .intended_io_mode = .blocking, - }) catch |err| switch (err) { + const macho_file = fs.cwd().openFile(macho_path, .{}) catch |err| switch (err) { error.FileNotFound => return error.MissingDebugInfo, else => return err, }; @@ -2162,7 +2159,7 @@ pub const ModuleDebugInfo = switch (native_os) { } fn loadOFile(self: *@This(), allocator: mem.Allocator, o_file_path: []const u8) !*OFileInfo { - const o_file = try fs.cwd().openFile(o_file_path, .{ .intended_io_mode = .blocking }); + const o_file = try fs.cwd().openFile(o_file_path, .{}); const mapped_mem = try mapWholeFile(o_file); const hdr: *const macho.mach_header_64 = @ptrCast(@alignCast(mapped_mem.ptr)); diff --git a/lib/std/fs.zig b/lib/std/fs.zig index 89db4695b5..5222e5e5ca 100644 --- a/lib/std/fs.zig +++ b/lib/std/fs.zig @@ -84,13 +84,6 @@ pub const base64_encoder = base64.Base64Encoder.init(base64_alphabet, null); /// Base64 decoder, replacing the standard `+/` with `-_` so that it can be used in a file name on any filesystem. pub const base64_decoder = base64.Base64Decoder.init(base64_alphabet, null); -/// Whether or not async file system syscalls need a dedicated thread because the operating -/// system does not support non-blocking I/O on the file system. -pub const need_async_thread = std.io.is_async and switch (builtin.os.tag) { - .windows, .other => false, - else => true, -}; - /// TODO remove the allocator requirement from this API /// TODO move to Dir pub fn atomicSymLink(allocator: Allocator, existing_path: []const u8, new_path: []const u8) !void { diff --git a/lib/std/fs/Dir.zig b/lib/std/fs/Dir.zig index 0f996affcc..8449d88d75 100644 --- a/lib/std/fs/Dir.zig +++ b/lib/std/fs/Dir.zig @@ -751,11 +751,7 @@ pub const OpenError = error{ } || posix.UnexpectedError; pub fn close(self: *Dir) void { - if (fs.need_async_thread) { - std.event.Loop.instance.?.close(self.fd); - } else { - posix.close(self.fd); - } + posix.close(self.fd); self.* = undefined; } @@ -837,10 +833,7 @@ pub fn openFileZ(self: Dir, sub_path: [*:0]const u8, flags: File.OpenFlags) File .write_only => @as(u32, posix.O.WRONLY), .read_write => @as(u32, posix.O.RDWR), }; - const fd = if (flags.intended_io_mode != .blocking) - try std.event.Loop.instance.?.openatZ(self.fd, sub_path, os_flags, 0) - else - try posix.openatZ(self.fd, sub_path, os_flags, 0); + const fd = try posix.openatZ(self.fd, sub_path, os_flags, 0); errdefer posix.close(fd); // WASI doesn't have posix.flock so we intetinally check OS prior to the inner if block @@ -877,11 +870,7 @@ pub fn openFileZ(self: Dir, sub_path: [*:0]const u8, flags: File.OpenFlags) File }; } - return File{ - .handle = fd, - .capable_io_mode = .blocking, - .intended_io_mode = flags.intended_io_mode, - }; + return File{ .handle = fd }; } /// Same as `openFile` but Windows-only and the path parameter is @@ -895,10 +884,7 @@ pub fn openFileW(self: Dir, sub_path_w: []const u16, flags: File.OpenFlags) File (if (flags.isRead()) @as(u32, w.GENERIC_READ) else 0) | (if (flags.isWrite()) @as(u32, w.GENERIC_WRITE) else 0), .creation = w.FILE_OPEN, - .io_mode = flags.intended_io_mode, }), - .capable_io_mode = std.io.default_mode, - .intended_io_mode = flags.intended_io_mode, }; errdefer file.close(); var io: w.IO_STATUS_BLOCK = undefined; @@ -994,10 +980,7 @@ pub fn createFileZ(self: Dir, sub_path_c: [*:0]const u8, flags: File.CreateFlags (if (flags.truncate) @as(u32, posix.O.TRUNC) else 0) | (if (flags.read) @as(u32, posix.O.RDWR) else posix.O.WRONLY) | (if (flags.exclusive) @as(u32, posix.O.EXCL) else 0); - const fd = if (flags.intended_io_mode != .blocking) - try std.event.Loop.instance.?.openatZ(self.fd, sub_path_c, os_flags, flags.mode) - else - try posix.openatZ(self.fd, sub_path_c, os_flags, flags.mode); + const fd = try posix.openatZ(self.fd, sub_path_c, os_flags, flags.mode); errdefer posix.close(fd); // WASI doesn't have posix.flock so we intetinally check OS prior to the inner if block @@ -1034,11 +1017,7 @@ pub fn createFileZ(self: Dir, sub_path_c: [*:0]const u8, flags: File.CreateFlags }; } - return File{ - .handle = fd, - .capable_io_mode = .blocking, - .intended_io_mode = flags.intended_io_mode, - }; + return File{ .handle = fd }; } /// Same as `createFile` but Windows-only and the path parameter is @@ -1056,10 +1035,7 @@ pub fn createFileW(self: Dir, sub_path_w: []const u16, flags: File.CreateFlags) @as(u32, w.FILE_OVERWRITE_IF) else @as(u32, w.FILE_OPEN_IF), - .io_mode = flags.intended_io_mode, }), - .capable_io_mode = std.io.default_mode, - .intended_io_mode = flags.intended_io_mode, }; errdefer file.close(); var io: w.IO_STATUS_BLOCK = undefined; @@ -1276,7 +1252,6 @@ pub fn realpathW(self: Dir, pathname: []const u16, out_buffer: []u8) ![]u8 { .access_mask = access_mask, .share_access = share_access, .creation = creation, - .io_mode = .blocking, .filter = .any, }) catch |err| switch (err) { error.WouldBlock => unreachable, @@ -1449,11 +1424,7 @@ pub fn openDirW(self: Dir, sub_path_w: [*:0]const u16, args: OpenDirOptions) Ope /// `flags` must contain `posix.O.DIRECTORY`. fn openDirFlagsZ(self: Dir, sub_path_c: [*:0]const u8, flags: u32) OpenError!Dir { - const result = if (fs.need_async_thread) - std.event.Loop.instance.?.openatZ(self.fd, sub_path_c, flags, 0) - else - posix.openatZ(self.fd, sub_path_c, flags, 0); - const fd = result catch |err| switch (err) { + const fd = posix.openatZ(self.fd, sub_path_c, flags, 0) catch |err| switch (err) { error.FileTooBig => unreachable, // can't happen for directories error.IsDir => unreachable, // we're providing O.DIRECTORY error.NoSpaceLeft => unreachable, // not providing O.CREAT @@ -2270,10 +2241,7 @@ pub fn accessZ(self: Dir, sub_path: [*:0]const u8, flags: File.OpenFlags) Access .write_only => @as(u32, posix.W_OK), .read_write => @as(u32, posix.R_OK | posix.W_OK), }; - const result = if (fs.need_async_thread and flags.intended_io_mode != .blocking) - std.event.Loop.instance.?.faccessatZ(self.fd, sub_path, os_mode, 0) - else - posix.faccessatZ(self.fd, sub_path, os_mode, 0); + const result = posix.faccessatZ(self.fd, sub_path, os_mode, 0); return result; } @@ -2457,10 +2425,7 @@ pub const Stat = File.Stat; pub const StatError = File.StatError; pub fn stat(self: Dir) StatError!Stat { - const file: File = .{ - .handle = self.fd, - .capable_io_mode = .blocking, - }; + const file: File = .{ .handle = self.fd }; return file.stat(); } @@ -2496,10 +2461,7 @@ pub const ChmodError = File.ChmodError; /// of the directory. Additionally, the directory must have been opened /// with `OpenDirOptions{ .iterate = true }`. pub fn chmod(self: Dir, new_mode: File.Mode) ChmodError!void { - const file: File = .{ - .handle = self.fd, - .capable_io_mode = .blocking, - }; + const file: File = .{ .handle = self.fd }; try file.chmod(new_mode); } @@ -2510,10 +2472,7 @@ pub fn chmod(self: Dir, new_mode: File.Mode) ChmodError!void { /// must have been opened with `OpenDirOptions{ .iterate = true }`. If the /// owner or group is specified as `null`, the ID is not changed. pub fn chown(self: Dir, owner: ?File.Uid, group: ?File.Gid) ChownError!void { - const file: File = .{ - .handle = self.fd, - .capable_io_mode = .blocking, - }; + const file: File = .{ .handle = self.fd }; try file.chown(owner, group); } @@ -2525,10 +2484,7 @@ pub const SetPermissionsError = File.SetPermissionsError; /// Sets permissions according to the provided `Permissions` struct. /// This method is *NOT* available on WASI pub fn setPermissions(self: Dir, permissions: Permissions) SetPermissionsError!void { - const file: File = .{ - .handle = self.fd, - .capable_io_mode = .blocking, - }; + const file: File = .{ .handle = self.fd }; try file.setPermissions(permissions); } @@ -2537,10 +2493,7 @@ pub const MetadataError = File.MetadataError; /// Returns a `Metadata` struct, representing the permissions on the directory pub fn metadata(self: Dir) MetadataError!Metadata { - const file: File = .{ - .handle = self.fd, - .capable_io_mode = .blocking, - }; + const file: File = .{ .handle = self.fd }; return try file.metadata(); } diff --git a/lib/std/fs/File.zig b/lib/std/fs/File.zig index b286380c85..576222ce73 100644 --- a/lib/std/fs/File.zig +++ b/lib/std/fs/File.zig @@ -1,20 +1,6 @@ /// The OS-specific file descriptor or file handle. handle: Handle, -/// On some systems, such as Linux, file system file descriptors are incapable -/// of non-blocking I/O. This forces us to perform asynchronous I/O on a dedicated thread, -/// to achieve non-blocking file-system I/O. To do this, `File` must be aware of whether -/// it is a file system file descriptor, or, more specifically, whether the I/O is always -/// blocking. -capable_io_mode: io.ModeOverride = io.default_mode, - -/// Furthermore, even when `std.options.io_mode` is async, it is still sometimes desirable -/// to perform blocking I/O, although not by default. For example, when printing a -/// stack trace to stderr. This field tracks both by acting as an overriding I/O mode. -/// When not building in async I/O mode, the type only has the `.blocking` tag, making -/// it a zero-bit type. -intended_io_mode: io.ModeOverride = io.default_mode, - pub const Handle = posix.fd_t; pub const Mode = posix.mode_t; pub const INode = posix.ino_t; @@ -108,16 +94,8 @@ pub const OpenFlags = struct { /// Sets whether or not to wait until the file is locked to return. If set to true, /// `error.WouldBlock` will be returned. Otherwise, the file will wait until the file /// is available to proceed. - /// In async I/O mode, non-blocking at the OS level is - /// determined by `intended_io_mode`, and `true` means `error.WouldBlock` is returned, - /// and `false` means `error.WouldBlock` is handled by the event loop. lock_nonblocking: bool = false, - /// Setting this to `.blocking` prevents `O.NONBLOCK` from being passed even - /// if `std.io.is_async`. It allows the use of `nosuspend` when calling functions - /// related to opening the file, reading, writing, and locking. - intended_io_mode: io.ModeOverride = io.default_mode, - /// Set this to allow the opened file to automatically become the /// controlling TTY for the current process. allow_ctty: bool = false, @@ -172,19 +150,11 @@ pub const CreateFlags = struct { /// Sets whether or not to wait until the file is locked to return. If set to true, /// `error.WouldBlock` will be returned. Otherwise, the file will wait until the file /// is available to proceed. - /// In async I/O mode, non-blocking at the OS level is - /// determined by `intended_io_mode`, and `true` means `error.WouldBlock` is returned, - /// and `false` means `error.WouldBlock` is handled by the event loop. lock_nonblocking: bool = false, /// For POSIX systems this is the file system mode the file will /// be created with. On other systems this is always 0. mode: Mode = default_mode, - - /// Setting this to `.blocking` prevents `O.NONBLOCK` from being passed even - /// if `std.io.is_async`. It allows the use of `nosuspend` when calling functions - /// related to opening the file, reading, writing, and locking. - intended_io_mode: io.ModeOverride = io.default_mode, }; /// Upon success, the stream is in an uninitialized state. To continue using it, @@ -192,8 +162,6 @@ pub const CreateFlags = struct { pub fn close(self: File) void { if (is_windows) { windows.CloseHandle(self.handle); - } else if (self.capable_io_mode != self.intended_io_mode) { - std.event.Loop.instance.?.close(self.handle); } else { posix.close(self.handle); } @@ -1013,14 +981,10 @@ pub const PReadError = posix.PReadError; pub fn read(self: File, buffer: []u8) ReadError!usize { if (is_windows) { - return windows.ReadFile(self.handle, buffer, null, self.intended_io_mode); + return windows.ReadFile(self.handle, buffer, null); } - if (self.intended_io_mode == .blocking) { - return posix.read(self.handle, buffer); - } else { - return std.event.Loop.instance.?.read(self.handle, buffer, self.capable_io_mode != self.intended_io_mode); - } + return posix.read(self.handle, buffer); } /// Returns the number of bytes read. If the number read is smaller than `buffer.len`, it @@ -1039,14 +1003,10 @@ pub fn readAll(self: File, buffer: []u8) ReadError!usize { /// https://github.com/ziglang/zig/issues/12783 pub fn pread(self: File, buffer: []u8, offset: u64) PReadError!usize { if (is_windows) { - return windows.ReadFile(self.handle, buffer, offset, self.intended_io_mode); + return windows.ReadFile(self.handle, buffer, offset); } - if (self.intended_io_mode == .blocking) { - return posix.pread(self.handle, buffer, offset); - } else { - return std.event.Loop.instance.?.pread(self.handle, buffer, offset, self.capable_io_mode != self.intended_io_mode); - } + return posix.pread(self.handle, buffer, offset); } /// Returns the number of bytes read. If the number read is smaller than `buffer.len`, it @@ -1069,14 +1029,10 @@ pub fn readv(self: File, iovecs: []const posix.iovec) ReadError!usize { // TODO improve this to use ReadFileScatter if (iovecs.len == 0) return @as(usize, 0); const first = iovecs[0]; - return windows.ReadFile(self.handle, first.iov_base[0..first.iov_len], null, self.intended_io_mode); + return windows.ReadFile(self.handle, first.iov_base[0..first.iov_len], null); } - if (self.intended_io_mode == .blocking) { - return posix.readv(self.handle, iovecs); - } else { - return std.event.Loop.instance.?.readv(self.handle, iovecs, self.capable_io_mode != self.intended_io_mode); - } + return posix.readv(self.handle, iovecs); } /// Returns the number of bytes read. If the number read is smaller than the total bytes @@ -1129,14 +1085,10 @@ pub fn preadv(self: File, iovecs: []const posix.iovec, offset: u64) PReadError!u // TODO improve this to use ReadFileScatter if (iovecs.len == 0) return @as(usize, 0); const first = iovecs[0]; - return windows.ReadFile(self.handle, first.iov_base[0..first.iov_len], offset, self.intended_io_mode); + return windows.ReadFile(self.handle, first.iov_base[0..first.iov_len], offset); } - if (self.intended_io_mode == .blocking) { - return posix.preadv(self.handle, iovecs, offset); - } else { - return std.event.Loop.instance.?.preadv(self.handle, iovecs, offset, self.capable_io_mode != self.intended_io_mode); - } + return posix.preadv(self.handle, iovecs, offset); } /// Returns the number of bytes read. If the number read is smaller than the total bytes @@ -1173,14 +1125,10 @@ pub const PWriteError = posix.PWriteError; pub fn write(self: File, bytes: []const u8) WriteError!usize { if (is_windows) { - return windows.WriteFile(self.handle, bytes, null, self.intended_io_mode); + return windows.WriteFile(self.handle, bytes, null); } - if (self.intended_io_mode == .blocking) { - return posix.write(self.handle, bytes); - } else { - return std.event.Loop.instance.?.write(self.handle, bytes, self.capable_io_mode != self.intended_io_mode); - } + return posix.write(self.handle, bytes); } pub fn writeAll(self: File, bytes: []const u8) WriteError!void { @@ -1194,14 +1142,10 @@ pub fn writeAll(self: File, bytes: []const u8) WriteError!void { /// https://github.com/ziglang/zig/issues/12783 pub fn pwrite(self: File, bytes: []const u8, offset: u64) PWriteError!usize { if (is_windows) { - return windows.WriteFile(self.handle, bytes, offset, self.intended_io_mode); + return windows.WriteFile(self.handle, bytes, offset); } - if (self.intended_io_mode == .blocking) { - return posix.pwrite(self.handle, bytes, offset); - } else { - return std.event.Loop.instance.?.pwrite(self.handle, bytes, offset, self.capable_io_mode != self.intended_io_mode); - } + return posix.pwrite(self.handle, bytes, offset); } /// On Windows, this function currently does alter the file pointer. @@ -1220,14 +1164,10 @@ pub fn writev(self: File, iovecs: []const posix.iovec_const) WriteError!usize { // TODO improve this to use WriteFileScatter if (iovecs.len == 0) return @as(usize, 0); const first = iovecs[0]; - return windows.WriteFile(self.handle, first.iov_base[0..first.iov_len], null, self.intended_io_mode); + return windows.WriteFile(self.handle, first.iov_base[0..first.iov_len], null); } - if (self.intended_io_mode == .blocking) { - return posix.writev(self.handle, iovecs); - } else { - return std.event.Loop.instance.?.writev(self.handle, iovecs, self.capable_io_mode != self.intended_io_mode); - } + return posix.writev(self.handle, iovecs); } /// The `iovecs` parameter is mutable because: @@ -1271,14 +1211,10 @@ pub fn pwritev(self: File, iovecs: []posix.iovec_const, offset: u64) PWriteError // TODO improve this to use WriteFileScatter if (iovecs.len == 0) return @as(usize, 0); const first = iovecs[0]; - return windows.WriteFile(self.handle, first.iov_base[0..first.iov_len], offset, self.intended_io_mode); + return windows.WriteFile(self.handle, first.iov_base[0..first.iov_len], offset); } - if (self.intended_io_mode == .blocking) { - return posix.pwritev(self.handle, iovecs, offset); - } else { - return std.event.Loop.instance.?.pwritev(self.handle, iovecs, offset, self.capable_io_mode != self.intended_io_mode); - } + return posix.pwritev(self.handle, iovecs, offset); } /// The `iovecs` parameter is mutable because this function needs to mutate the fields in diff --git a/lib/std/fs/test.zig b/lib/std/fs/test.zig index 28d1d111d9..46bce69151 100644 --- a/lib/std/fs/test.zig +++ b/lib/std/fs/test.zig @@ -1508,11 +1508,6 @@ test "open file with exclusive and shared nonblocking lock" { test "open file with exclusive lock twice, make sure second lock waits" { if (builtin.single_threaded) return error.SkipZigTest; - if (std.io.is_async) { - // This test starts its own threads and is not compatible with async I/O. - return error.SkipZigTest; - } - try testWithAllSupportedPathTypes(struct { fn impl(ctx: *TestContext) !void { const filename = try ctx.transformPath("file_lock_test.txt"); diff --git a/lib/std/io.zig b/lib/std/io.zig index 8caacab993..9c14aa762e 100644 --- a/lib/std/io.zig +++ b/lib/std/io.zig @@ -12,21 +12,6 @@ const meta = std.meta; const File = std.fs.File; const Allocator = std.mem.Allocator; -pub const Mode = enum { - /// I/O operates normally, waiting for the operating system syscalls to complete. - blocking, - - /// I/O functions are generated async and rely on a global event loop. Event-based I/O. - evented, -}; - -pub const is_async = false; - -/// This is an enum value to use for I/O mode at runtime, since it takes up zero bytes at runtime, -/// and makes expressions comptime-known when `is_async` is `false`. -pub const ModeOverride = if (is_async) Mode else enum { blocking }; -pub const default_mode: ModeOverride = if (is_async) Mode.evented else .blocking; - fn getStdOutHandle() os.fd_t { if (builtin.os.tag == .windows) { if (builtin.zig_backend == .stage2_aarch64) { @@ -43,14 +28,8 @@ fn getStdOutHandle() os.fd_t { return os.STDOUT_FILENO; } -/// TODO: async stdout on windows without a dedicated thread. -/// https://github.com/ziglang/zig/pull/4816#issuecomment-604521023 pub fn getStdOut() File { - return File{ - .handle = getStdOutHandle(), - .capable_io_mode = .blocking, - .intended_io_mode = default_mode, - }; + return File{ .handle = getStdOutHandle() }; } fn getStdErrHandle() os.fd_t { @@ -69,14 +48,8 @@ fn getStdErrHandle() os.fd_t { return os.STDERR_FILENO; } -/// This returns a `File` that is configured to block with every write, in order -/// to facilitate better debugging. This can be changed by modifying the `intended_io_mode` field. pub fn getStdErr() File { - return File{ - .handle = getStdErrHandle(), - .capable_io_mode = .blocking, - .intended_io_mode = .blocking, - }; + return File{ .handle = getStdErrHandle() }; } fn getStdInHandle() os.fd_t { @@ -95,14 +68,8 @@ fn getStdInHandle() os.fd_t { return os.STDIN_FILENO; } -/// TODO: async stdin on windows without a dedicated thread. -/// https://github.com/ziglang/zig/pull/4816#issuecomment-604521023 pub fn getStdIn() File { - return File{ - .handle = getStdInHandle(), - .capable_io_mode = .blocking, - .intended_io_mode = default_mode, - }; + return File{ .handle = getStdInHandle() }; } pub fn GenericReader( diff --git a/lib/std/net.zig b/lib/std/net.zig index 28967cba55..154e2f7375 100644 --- a/lib/std/net.zig +++ b/lib/std/net.zig @@ -651,7 +651,7 @@ pub const Ip6Address = extern struct { }; pub fn connectUnixSocket(path: []const u8) !Stream { - const opt_non_block = if (std.io.is_async) os.SOCK.NONBLOCK else 0; + const opt_non_block = 0; const sockfd = try os.socket( os.AF.UNIX, os.SOCK.STREAM | os.SOCK.CLOEXEC | opt_non_block, @@ -660,17 +660,9 @@ pub fn connectUnixSocket(path: []const u8) !Stream { errdefer os.closeSocket(sockfd); var addr = try std.net.Address.initUnix(path); + try os.connect(sockfd, &addr.any, addr.getOsSockLen()); - if (std.io.is_async) { - const loop = std.event.Loop.instance orelse return error.WouldBlock; - try loop.connect(sockfd, &addr.any, addr.getOsSockLen()); - } else { - try os.connect(sockfd, &addr.any, addr.getOsSockLen()); - } - - return Stream{ - .handle = sockfd, - }; + return Stream{ .handle = sockfd }; } fn if_nametoindex(name: []const u8) IPv6InterfaceError!u32 { @@ -742,18 +734,13 @@ pub fn tcpConnectToHost(allocator: mem.Allocator, name: []const u8, port: u16) T pub const TcpConnectToAddressError = std.os.SocketError || std.os.ConnectError; pub fn tcpConnectToAddress(address: Address) TcpConnectToAddressError!Stream { - const nonblock = if (std.io.is_async) os.SOCK.NONBLOCK else 0; + const nonblock = 0; const sock_flags = os.SOCK.STREAM | nonblock | (if (builtin.target.os.tag == .windows) 0 else os.SOCK.CLOEXEC); const sockfd = try os.socket(address.any.family, sock_flags, os.IPPROTO.TCP); errdefer os.closeSocket(sockfd); - if (std.io.is_async) { - const loop = std.event.Loop.instance orelse return error.WouldBlock; - try loop.connect(sockfd, &address.any, address.getOsSockLen()); - } else { - try os.connect(sockfd, &address.any, address.getOsSockLen()); - } + try os.connect(sockfd, &address.any, address.getOsSockLen()); return Stream{ .handle = sockfd }; } @@ -1618,11 +1605,7 @@ fn resMSendRc( if (answers[i].len == 0) { var j: usize = 0; while (j < ns.len) : (j += 1) { - if (std.io.is_async) { - _ = std.event.Loop.instance.?.sendto(fd, queries[i], os.MSG.NOSIGNAL, &ns[j].any, sl) catch undefined; - } else { - _ = os.sendto(fd, queries[i], os.MSG.NOSIGNAL, &ns[j].any, sl) catch undefined; - } + _ = os.sendto(fd, queries[i], os.MSG.NOSIGNAL, &ns[j].any, sl) catch undefined; } } } @@ -1637,10 +1620,7 @@ fn resMSendRc( while (true) { var sl_copy = sl; - const rlen = if (std.io.is_async) - std.event.Loop.instance.?.recvfrom(fd, answer_bufs[next], 0, &sa.any, &sl_copy) catch break - else - os.recvfrom(fd, answer_bufs[next], 0, &sa.any, &sl_copy) catch break; + const rlen = os.recvfrom(fd, answer_bufs[next], 0, &sa.any, &sl_copy) catch break; // Ignore non-identifiable packets if (rlen < 4) continue; @@ -1666,11 +1646,7 @@ fn resMSendRc( 0, 3 => {}, 2 => if (servfail_retry != 0) { servfail_retry -= 1; - if (std.io.is_async) { - _ = std.event.Loop.instance.?.sendto(fd, queries[i], os.MSG.NOSIGNAL, &ns[j].any, sl) catch undefined; - } else { - _ = os.sendto(fd, queries[i], os.MSG.NOSIGNAL, &ns[j].any, sl) catch undefined; - } + _ = os.sendto(fd, queries[i], os.MSG.NOSIGNAL, &ns[j].any, sl) catch undefined; }, else => continue, } @@ -1778,14 +1754,10 @@ pub const Stream = struct { pub fn read(self: Stream, buffer: []u8) ReadError!usize { if (builtin.os.tag == .windows) { - return os.windows.ReadFile(self.handle, buffer, null, io.default_mode); + return os.windows.ReadFile(self.handle, buffer, null); } - if (std.io.is_async) { - return std.event.Loop.instance.?.read(self.handle, buffer, false); - } else { - return os.read(self.handle, buffer); - } + return os.read(self.handle, buffer); } pub fn readv(s: Stream, iovecs: []const os.iovec) ReadError!usize { @@ -1793,7 +1765,7 @@ pub const Stream = struct { // TODO improve this to use ReadFileScatter if (iovecs.len == 0) return @as(usize, 0); const first = iovecs[0]; - return os.windows.ReadFile(s.handle, first.iov_base[0..first.iov_len], null, io.default_mode); + return os.windows.ReadFile(s.handle, first.iov_base[0..first.iov_len], null); } return os.readv(s.handle, iovecs); @@ -1827,14 +1799,10 @@ pub const Stream = struct { /// use non-blocking I/O. pub fn write(self: Stream, buffer: []const u8) WriteError!usize { if (builtin.os.tag == .windows) { - return os.windows.WriteFile(self.handle, buffer, null, io.default_mode); + return os.windows.WriteFile(self.handle, buffer, null); } - if (std.io.is_async) { - return std.event.Loop.instance.?.write(self.handle, buffer, false); - } else { - return os.write(self.handle, buffer); - } + return os.write(self.handle, buffer); } pub fn writeAll(self: Stream, bytes: []const u8) WriteError!void { @@ -1847,15 +1815,7 @@ pub const Stream = struct { /// See https://github.com/ziglang/zig/issues/7699 /// See equivalent function: `std.fs.File.writev`. pub fn writev(self: Stream, iovecs: []const os.iovec_const) WriteError!usize { - if (std.io.is_async) { - // TODO improve to actually take advantage of writev syscall, if available. - if (iovecs.len == 0) return 0; - const first_buffer = iovecs[0].iov_base[0..iovecs[0].iov_len]; - try self.write(first_buffer); - return first_buffer.len; - } else { - return os.writev(self.handle, iovecs); - } + return os.writev(self.handle, iovecs); } /// The `iovecs` parameter is mutable because this function needs to mutate the fields in @@ -1927,7 +1887,7 @@ pub const StreamServer = struct { } pub fn listen(self: *StreamServer, address: Address) !void { - const nonblock = if (std.io.is_async) os.SOCK.NONBLOCK else 0; + const nonblock = 0; const sock_flags = os.SOCK.STREAM | os.SOCK.CLOEXEC | nonblock; var use_sock_flags: u32 = sock_flags; if (self.force_nonblocking) use_sock_flags |= os.SOCK.NONBLOCK; @@ -2016,14 +1976,7 @@ pub const StreamServer = struct { pub fn accept(self: *StreamServer) AcceptError!Connection { var accepted_addr: Address = undefined; var adr_len: os.socklen_t = @sizeOf(Address); - const accept_result = blk: { - if (std.io.is_async) { - const loop = std.event.Loop.instance orelse return error.UnexpectedError; - break :blk loop.accept(self.sockfd.?, &accepted_addr.any, &adr_len, os.SOCK.CLOEXEC); - } else { - break :blk os.accept(self.sockfd.?, &accepted_addr.any, &adr_len, os.SOCK.CLOEXEC); - } - }; + const accept_result = os.accept(self.sockfd.?, &accepted_addr.any, &adr_len, os.SOCK.CLOEXEC); if (accept_result) |fd| { return Connection{ diff --git a/lib/std/net/test.zig b/lib/std/net/test.zig index 8cc2a09d10..e359abb6d5 100644 --- a/lib/std/net/test.zig +++ b/lib/std/net/test.zig @@ -207,54 +207,6 @@ test "listen on a port, send bytes, receive bytes" { try testing.expectEqualSlices(u8, "Hello world!", buf[0..n]); } -test "listen on a port, send bytes, receive bytes, async-only" { - if (!std.io.is_async) return error.SkipZigTest; - - if (builtin.os.tag != .linux and !builtin.os.tag.isDarwin()) { - // TODO build abstractions for other operating systems - return error.SkipZigTest; - } - - // TODO doing this at comptime crashed the compiler - const localhost = try net.Address.parseIp("127.0.0.1", 0); - - var server = net.StreamServer.init(net.StreamServer.Options{}); - defer server.deinit(); - try server.listen(localhost); - - var server_frame = async testServer(&server); - var client_frame = async testClient(server.listen_address); - - try await server_frame; - try await client_frame; -} - -test "listen on ipv4 try connect on ipv6 then ipv4" { - if (!std.io.is_async) return error.SkipZigTest; - - if (builtin.os.tag != .linux and !builtin.os.tag.isDarwin()) { - // TODO build abstractions for other operating systems - return error.SkipZigTest; - } - - // TODO doing this at comptime crashed the compiler - const localhost = try net.Address.parseIp("127.0.0.1", 0); - - var server = net.StreamServer.init(net.StreamServer.Options{}); - defer server.deinit(); - try server.listen(localhost); - - var server_frame = async testServer(&server); - var client_frame = async testClientToHost( - testing.allocator, - "localhost", - server.listen_address.getPort(), - ); - - try await server_frame; - try await client_frame; -} - test "listen on an in use port" { if (builtin.os.tag != .linux and comptime !builtin.os.tag.isDarwin()) { // TODO build abstractions for other operating systems diff --git a/lib/std/os.zig b/lib/std/os.zig index e12753ab3e..9c5e018fe1 100644 --- a/lib/std/os.zig +++ b/lib/std/os.zig @@ -683,11 +683,7 @@ fn getRandomBytesDevURandom(buf: []u8) !void { return error.NoDevice; } - const file = std.fs.File{ - .handle = fd, - .capable_io_mode = .blocking, - .intended_io_mode = .blocking, - }; + const file = std.fs.File{ .handle = fd }; const stream = file.reader(); stream.readNoEof(buf) catch return error.Unexpected; } @@ -856,7 +852,7 @@ pub const ReadError = error{ pub fn read(fd: fd_t, buf: []u8) ReadError!usize { if (buf.len == 0) return 0; if (builtin.os.tag == .windows) { - return windows.ReadFile(fd, buf, null, std.io.default_mode); + return windows.ReadFile(fd, buf, null); } if (builtin.os.tag == .wasi and !builtin.link_libc) { const iovs = [1]iovec{iovec{ @@ -995,7 +991,7 @@ pub const PReadError = ReadError || error{Unseekable}; pub fn pread(fd: fd_t, buf: []u8, offset: u64) PReadError!usize { if (buf.len == 0) return 0; if (builtin.os.tag == .windows) { - return windows.ReadFile(fd, buf, offset, std.io.default_mode); + return windows.ReadFile(fd, buf, offset); } if (builtin.os.tag == .wasi and !builtin.link_libc) { const iovs = [1]iovec{iovec{ @@ -1257,7 +1253,7 @@ pub const WriteError = error{ pub fn write(fd: fd_t, bytes: []const u8) WriteError!usize { if (bytes.len == 0) return 0; if (builtin.os.tag == .windows) { - return windows.WriteFile(fd, bytes, null, std.io.default_mode); + return windows.WriteFile(fd, bytes, null); } if (builtin.os.tag == .wasi and !builtin.link_libc) { @@ -1415,7 +1411,7 @@ pub const PWriteError = WriteError || error{Unseekable}; pub fn pwrite(fd: fd_t, bytes: []const u8, offset: u64) PWriteError!usize { if (bytes.len == 0) return 0; if (builtin.os.tag == .windows) { - return windows.WriteFile(fd, bytes, offset, std.io.default_mode); + return windows.WriteFile(fd, bytes, offset); } if (builtin.os.tag == .wasi and !builtin.link_libc) { const ciovs = [1]iovec_const{iovec_const{ @@ -1711,7 +1707,6 @@ fn openOptionsFromFlagsWindows(flags: u32) windows.OpenFileOptions { return .{ .access_mask = access_mask, - .io_mode = .blocking, .creation = creation, .filter = filter, .follow_symlinks = follow_symlinks, @@ -2797,7 +2792,6 @@ pub fn renameatW( .dir = old_dir_fd, .access_mask = windows.SYNCHRONIZE | windows.GENERIC_WRITE | windows.DELETE, .creation = windows.FILE_OPEN, - .io_mode = .blocking, .filter = .any, // This function is supposed to rename both files and directories. .follow_symlinks = false, }) catch |err| switch (err) { @@ -2962,7 +2956,6 @@ pub fn mkdiratW(dir_fd: fd_t, sub_path_w: []const u16, mode: u32) MakeDirError!v .dir = dir_fd, .access_mask = windows.GENERIC_READ | windows.SYNCHRONIZE, .creation = windows.FILE_CREATE, - .io_mode = .blocking, .filter = .dir_only, }) catch |err| switch (err) { error.IsDir => unreachable, @@ -3042,7 +3035,6 @@ pub fn mkdirW(dir_path_w: []const u16, mode: u32) MakeDirError!void { .dir = std.fs.cwd().fd, .access_mask = windows.GENERIC_READ | windows.SYNCHRONIZE, .creation = windows.FILE_CREATE, - .io_mode = .blocking, .filter = .dir_only, }) catch |err| switch (err) { error.IsDir => unreachable, @@ -5440,7 +5432,6 @@ pub fn realpathW(pathname: []const u16, out_buffer: *[MAX_PATH_BYTES]u8) RealPat .access_mask = access_mask, .share_access = share_access, .creation = creation, - .io_mode = .blocking, .filter = .any, }) catch |err| switch (err) { error.WouldBlock => unreachable, @@ -6404,12 +6395,7 @@ pub fn sendfile( // manually, the same as ENOSYS. break :sf; }, - .AGAIN => if (std.event.Loop.instance) |loop| { - loop.waitUntilFdWritable(out_fd); - continue; - } else { - return error.WouldBlock; - }, + .AGAIN => return error.WouldBlock, .IO => return error.InputOutput, .PIPE => return error.BrokenPipe, .NOMEM => return error.SystemResources, @@ -6476,18 +6462,12 @@ pub fn sendfile( .AGAIN => if (amt != 0) { return amt; - } else if (std.event.Loop.instance) |loop| { - loop.waitUntilFdWritable(out_fd); - continue; } else { return error.WouldBlock; }, .BUSY => if (amt != 0) { return amt; - } else if (std.event.Loop.instance) |loop| { - loop.waitUntilFdReadable(in_fd); - continue; } else { return error.WouldBlock; }, @@ -6550,9 +6530,6 @@ pub fn sendfile( .AGAIN => if (amt != 0) { return amt; - } else if (std.event.Loop.instance) |loop| { - loop.waitUntilFdWritable(out_fd); - continue; } else { return error.WouldBlock; }, diff --git a/lib/std/os/windows.zig b/lib/std/os/windows.zig index d48261a97a..2a19462a7c 100644 --- a/lib/std/os/windows.zig +++ b/lib/std/os/windows.zig @@ -49,7 +49,6 @@ pub const OpenFileOptions = struct { sa: ?*SECURITY_ATTRIBUTES = null, share_access: ULONG = FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_SHARE_DELETE, creation: ULONG, - io_mode: std.io.ModeOverride, /// If true, tries to open path as a directory. /// Defaults to false. filter: Filter = .file_only, @@ -95,7 +94,7 @@ pub fn OpenFile(sub_path_w: []const u16, options: OpenFileOptions) OpenError!HAN .SecurityQualityOfService = null, }; var io: IO_STATUS_BLOCK = undefined; - const blocking_flag: ULONG = if (options.io_mode == .blocking) FILE_SYNCHRONOUS_IO_NONALERT else 0; + const blocking_flag: ULONG = FILE_SYNCHRONOUS_IO_NONALERT; const file_or_dir_flag: ULONG = switch (options.filter) { .file_only => FILE_NON_DIRECTORY_FILE, .dir_only => FILE_DIRECTORY_FILE, @@ -119,12 +118,7 @@ pub fn OpenFile(sub_path_w: []const u16, options: OpenFileOptions) OpenError!HAN 0, ); switch (rc) { - .SUCCESS => { - if (std.io.is_async and options.io_mode == .evented) { - _ = CreateIoCompletionPort(result, std.event.Loop.instance.?.os_data.io_port, undefined, undefined) catch undefined; - } - return result; - }, + .SUCCESS => return result, .OBJECT_NAME_INVALID => unreachable, .OBJECT_NAME_NOT_FOUND => return error.FileNotFound, .OBJECT_PATH_NOT_FOUND => return error.FileNotFound, @@ -457,81 +451,36 @@ pub const ReadFileError = error{ /// If buffer's length exceeds what a Windows DWORD integer can hold, it will be broken into /// multiple non-atomic reads. -pub fn ReadFile(in_hFile: HANDLE, buffer: []u8, offset: ?u64, io_mode: std.io.ModeOverride) ReadFileError!usize { - if (io_mode != .blocking) { - const loop = std.event.Loop.instance.?; - // TODO make getting the file position non-blocking - const off = if (offset) |o| o else try SetFilePointerEx_CURRENT_get(in_hFile); - var resume_node = std.event.Loop.ResumeNode.Basic{ - .base = .{ - .id = .Basic, - .handle = @frame(), - .overlapped = OVERLAPPED{ - .Internal = 0, - .InternalHigh = 0, - .DUMMYUNIONNAME = .{ - .DUMMYSTRUCTNAME = .{ - .Offset = @as(u32, @truncate(off)), - .OffsetHigh = @as(u32, @truncate(off >> 32)), - }, +pub fn ReadFile(in_hFile: HANDLE, buffer: []u8, offset: ?u64) ReadFileError!usize { + while (true) { + const want_read_count: DWORD = @min(@as(DWORD, maxInt(DWORD)), buffer.len); + var amt_read: DWORD = undefined; + var overlapped_data: OVERLAPPED = undefined; + const overlapped: ?*OVERLAPPED = if (offset) |off| blk: { + overlapped_data = .{ + .Internal = 0, + .InternalHigh = 0, + .DUMMYUNIONNAME = .{ + .DUMMYSTRUCTNAME = .{ + .Offset = @as(u32, @truncate(off)), + .OffsetHigh = @as(u32, @truncate(off >> 32)), }, - .hEvent = null, }, - }, - }; - loop.beginOneEvent(); - suspend { - // TODO handle buffer bigger than DWORD can hold - _ = kernel32.ReadFile(in_hFile, buffer.ptr, @as(DWORD, @intCast(buffer.len)), null, &resume_node.base.overlapped); - } - var bytes_transferred: DWORD = undefined; - if (kernel32.GetOverlappedResult(in_hFile, &resume_node.base.overlapped, &bytes_transferred, FALSE) == 0) { + .hEvent = null, + }; + break :blk &overlapped_data; + } else null; + if (kernel32.ReadFile(in_hFile, buffer.ptr, want_read_count, &amt_read, overlapped) == 0) { switch (kernel32.GetLastError()) { .IO_PENDING => unreachable, - .OPERATION_ABORTED => return error.OperationAborted, - .BROKEN_PIPE => return error.BrokenPipe, + .OPERATION_ABORTED => continue, + .BROKEN_PIPE => return 0, + .HANDLE_EOF => return 0, .NETNAME_DELETED => return error.NetNameDeleted, - .HANDLE_EOF => return @as(usize, bytes_transferred), else => |err| return unexpectedError(err), } } - if (offset == null) { - // TODO make setting the file position non-blocking - const new_off = off + bytes_transferred; - try SetFilePointerEx_CURRENT(in_hFile, @as(i64, @bitCast(new_off))); - } - return @as(usize, bytes_transferred); - } else { - while (true) { - const want_read_count: DWORD = @min(@as(DWORD, maxInt(DWORD)), buffer.len); - var amt_read: DWORD = undefined; - var overlapped_data: OVERLAPPED = undefined; - const overlapped: ?*OVERLAPPED = if (offset) |off| blk: { - overlapped_data = .{ - .Internal = 0, - .InternalHigh = 0, - .DUMMYUNIONNAME = .{ - .DUMMYSTRUCTNAME = .{ - .Offset = @as(u32, @truncate(off)), - .OffsetHigh = @as(u32, @truncate(off >> 32)), - }, - }, - .hEvent = null, - }; - break :blk &overlapped_data; - } else null; - if (kernel32.ReadFile(in_hFile, buffer.ptr, want_read_count, &amt_read, overlapped) == 0) { - switch (kernel32.GetLastError()) { - .IO_PENDING => unreachable, - .OPERATION_ABORTED => continue, - .BROKEN_PIPE => return 0, - .HANDLE_EOF => return 0, - .NETNAME_DELETED => return error.NetNameDeleted, - else => |err| return unexpectedError(err), - } - } - return amt_read; - } + return amt_read; } } @@ -550,85 +499,38 @@ pub fn WriteFile( handle: HANDLE, bytes: []const u8, offset: ?u64, - io_mode: std.io.ModeOverride, ) WriteFileError!usize { - if (std.event.Loop.instance != null and io_mode != .blocking) { - const loop = std.event.Loop.instance.?; - // TODO make getting the file position non-blocking - const off = if (offset) |o| o else try SetFilePointerEx_CURRENT_get(handle); - var resume_node = std.event.Loop.ResumeNode.Basic{ - .base = .{ - .id = .Basic, - .handle = @frame(), - .overlapped = OVERLAPPED{ - .Internal = 0, - .InternalHigh = 0, - .DUMMYUNIONNAME = .{ - .DUMMYSTRUCTNAME = .{ - .Offset = @as(u32, @truncate(off)), - .OffsetHigh = @as(u32, @truncate(off >> 32)), - }, - }, - .hEvent = null, + var bytes_written: DWORD = undefined; + var overlapped_data: OVERLAPPED = undefined; + const overlapped: ?*OVERLAPPED = if (offset) |off| blk: { + overlapped_data = .{ + .Internal = 0, + .InternalHigh = 0, + .DUMMYUNIONNAME = .{ + .DUMMYSTRUCTNAME = .{ + .Offset = @as(u32, @truncate(off)), + .OffsetHigh = @as(u32, @truncate(off >> 32)), }, }, + .hEvent = null, }; - loop.beginOneEvent(); - suspend { - const adjusted_len = math.cast(DWORD, bytes.len) orelse maxInt(DWORD); - _ = kernel32.WriteFile(handle, bytes.ptr, adjusted_len, null, &resume_node.base.overlapped); + break :blk &overlapped_data; + } else null; + const adjusted_len = math.cast(u32, bytes.len) orelse maxInt(u32); + if (kernel32.WriteFile(handle, bytes.ptr, adjusted_len, &bytes_written, overlapped) == 0) { + switch (kernel32.GetLastError()) { + .INVALID_USER_BUFFER => return error.SystemResources, + .NOT_ENOUGH_MEMORY => return error.SystemResources, + .OPERATION_ABORTED => return error.OperationAborted, + .NOT_ENOUGH_QUOTA => return error.SystemResources, + .IO_PENDING => unreachable, + .BROKEN_PIPE => return error.BrokenPipe, + .INVALID_HANDLE => return error.NotOpenForWriting, + .LOCK_VIOLATION => return error.LockViolation, + else => |err| return unexpectedError(err), } - var bytes_transferred: DWORD = undefined; - if (kernel32.GetOverlappedResult(handle, &resume_node.base.overlapped, &bytes_transferred, FALSE) == 0) { - switch (kernel32.GetLastError()) { - .IO_PENDING => unreachable, - .INVALID_USER_BUFFER => return error.SystemResources, - .NOT_ENOUGH_MEMORY => return error.SystemResources, - .OPERATION_ABORTED => return error.OperationAborted, - .NOT_ENOUGH_QUOTA => return error.SystemResources, - .BROKEN_PIPE => return error.BrokenPipe, - else => |err| return unexpectedError(err), - } - } - if (offset == null) { - // TODO make setting the file position non-blocking - const new_off = off + bytes_transferred; - try SetFilePointerEx_CURRENT(handle, @as(i64, @bitCast(new_off))); - } - return bytes_transferred; - } else { - var bytes_written: DWORD = undefined; - var overlapped_data: OVERLAPPED = undefined; - const overlapped: ?*OVERLAPPED = if (offset) |off| blk: { - overlapped_data = .{ - .Internal = 0, - .InternalHigh = 0, - .DUMMYUNIONNAME = .{ - .DUMMYSTRUCTNAME = .{ - .Offset = @as(u32, @truncate(off)), - .OffsetHigh = @as(u32, @truncate(off >> 32)), - }, - }, - .hEvent = null, - }; - break :blk &overlapped_data; - } else null; - const adjusted_len = math.cast(u32, bytes.len) orelse maxInt(u32); - if (kernel32.WriteFile(handle, bytes.ptr, adjusted_len, &bytes_written, overlapped) == 0) { - switch (kernel32.GetLastError()) { - .INVALID_USER_BUFFER => return error.SystemResources, - .NOT_ENOUGH_MEMORY => return error.SystemResources, - .OPERATION_ABORTED => return error.OperationAborted, - .NOT_ENOUGH_QUOTA => return error.SystemResources, - .IO_PENDING => unreachable, - .BROKEN_PIPE => return error.BrokenPipe, - .INVALID_HANDLE => return error.NotOpenForWriting, - .LOCK_VIOLATION => return error.LockViolation, - else => |err| return unexpectedError(err), - } - } - return bytes_written; } + return bytes_written; } pub const SetCurrentDirectoryError = error{ @@ -732,7 +634,6 @@ pub fn CreateSymbolicLink( .access_mask = SYNCHRONIZE | GENERIC_READ | GENERIC_WRITE, .dir = dir, .creation = FILE_CREATE, - .io_mode = .blocking, .filter = if (is_directory) .dir_only else .file_only, }) catch |err| switch (err) { error.IsDir => return error.PathAlreadyExists, @@ -1256,7 +1157,6 @@ pub fn GetFinalPathNameByHandle( .access_mask = SYNCHRONIZE, .share_access = FILE_SHARE_READ | FILE_SHARE_WRITE, .creation = FILE_OPEN, - .io_mode = .blocking, }) catch |err| switch (err) { error.IsDir => unreachable, error.NotDir => unreachable, diff --git a/lib/std/pdb.zig b/lib/std/pdb.zig index d0623145a0..9640ec3569 100644 --- a/lib/std/pdb.zig +++ b/lib/std/pdb.zig @@ -513,7 +513,7 @@ pub const Pdb = struct { }; pub fn init(allocator: mem.Allocator, path: []const u8) !Pdb { - const file = try fs.cwd().openFile(path, .{ .intended_io_mode = .blocking }); + const file = try fs.cwd().openFile(path, .{}); errdefer file.close(); return Pdb{ diff --git a/lib/std/time.zig b/lib/std/time.zig index dad81385e9..012dc838f8 100644 --- a/lib/std/time.zig +++ b/lib/std/time.zig @@ -9,11 +9,6 @@ pub const epoch = @import("time/epoch.zig"); /// Spurious wakeups are possible and no precision of timing is guaranteed. pub fn sleep(nanoseconds: u64) void { - // TODO: opting out of async sleeping? - if (std.io.is_async) { - return std.event.Loop.instance.?.sleep(nanoseconds); - } - if (builtin.os.tag == .windows) { const big_ms_from_ns = nanoseconds / ns_per_ms; const ms = math.cast(os.windows.DWORD, big_ms_from_ns) orelse math.maxInt(os.windows.DWORD); diff --git a/lib/std/zig/Server.zig b/lib/std/zig/Server.zig index 7d5abaf6ea..915450c50a 100644 --- a/lib/std/zig/Server.zig +++ b/lib/std/zig/Server.zig @@ -38,8 +38,6 @@ pub const Message = struct { /// Trailing: /// * name: [tests_len]u32 /// - null-terminated string_bytes index - /// * async_frame_len: [tests_len]u32, - /// - 0 means not async /// * expected_panic_msg: [tests_len]u32, /// - null-terminated string_bytes index /// - 0 means does not expect pani @@ -210,7 +208,6 @@ pub fn serveErrorBundle(s: *Server, error_bundle: std.zig.ErrorBundle) !void { pub const TestMetadata = struct { names: []u32, - async_frame_sizes: []u32, expected_panic_msgs: []u32, string_bytes: []const u8, }; @@ -220,17 +217,16 @@ pub fn serveTestMetadata(s: *Server, test_metadata: TestMetadata) !void { .tests_len = bswap(@as(u32, @intCast(test_metadata.names.len))), .string_bytes_len = bswap(@as(u32, @intCast(test_metadata.string_bytes.len))), }; + const trailing = 2; const bytes_len = @sizeOf(OutMessage.TestMetadata) + - 3 * 4 * test_metadata.names.len + test_metadata.string_bytes.len; + trailing * @sizeOf(u32) * test_metadata.names.len + test_metadata.string_bytes.len; if (need_bswap) { bswap_u32_array(test_metadata.names); - bswap_u32_array(test_metadata.async_frame_sizes); bswap_u32_array(test_metadata.expected_panic_msgs); } defer if (need_bswap) { bswap_u32_array(test_metadata.names); - bswap_u32_array(test_metadata.async_frame_sizes); bswap_u32_array(test_metadata.expected_panic_msgs); }; @@ -241,7 +237,6 @@ pub fn serveTestMetadata(s: *Server, test_metadata: TestMetadata) !void { std.mem.asBytes(&header), // TODO: implement @ptrCast between slices changing the length std.mem.sliceAsBytes(test_metadata.names), - std.mem.sliceAsBytes(test_metadata.async_frame_sizes), std.mem.sliceAsBytes(test_metadata.expected_panic_msgs), test_metadata.string_bytes, }); diff --git a/lib/std/zig/system/linux.zig b/lib/std/zig/system/linux.zig index d2d31b4079..ad49f4d626 100644 --- a/lib/std/zig/system/linux.zig +++ b/lib/std/zig/system/linux.zig @@ -328,7 +328,7 @@ fn CpuinfoParser(comptime impl: anytype) type { } pub fn detectNativeCpuAndFeatures() ?Target.Cpu { - var f = fs.openFileAbsolute("/proc/cpuinfo", .{ .intended_io_mode = .blocking }) catch |err| switch (err) { + var f = fs.openFileAbsolute("/proc/cpuinfo", .{}) catch |err| switch (err) { else => return null, }; defer f.close(); diff --git a/lib/test_runner.zig b/lib/test_runner.zig index 8514632964..e11d187d2a 100644 --- a/lib/test_runner.zig +++ b/lib/test_runner.zig @@ -4,7 +4,6 @@ const io = std.io; const builtin = @import("builtin"); pub const std_options = .{ - .io_mode = builtin.test_io_mode, .logFn = log, }; @@ -65,24 +64,19 @@ fn mainServer() !void { const test_fns = builtin.test_functions; const names = try std.testing.allocator.alloc(u32, test_fns.len); defer std.testing.allocator.free(names); - const async_frame_sizes = try std.testing.allocator.alloc(u32, test_fns.len); - defer std.testing.allocator.free(async_frame_sizes); const expected_panic_msgs = try std.testing.allocator.alloc(u32, test_fns.len); defer std.testing.allocator.free(expected_panic_msgs); - for (test_fns, names, async_frame_sizes, expected_panic_msgs) |test_fn, *name, *async_frame_size, *expected_panic_msg| { + for (test_fns, names, expected_panic_msgs) |test_fn, *name, *expected_panic_msg| { name.* = @as(u32, @intCast(string_bytes.items.len)); try string_bytes.ensureUnusedCapacity(std.testing.allocator, test_fn.name.len + 1); string_bytes.appendSliceAssumeCapacity(test_fn.name); string_bytes.appendAssumeCapacity(0); - - async_frame_size.* = @as(u32, @intCast(test_fn.async_frame_size orelse 0)); expected_panic_msg.* = 0; } try server.serveTestMetadata(.{ .names = names, - .async_frame_sizes = async_frame_sizes, .expected_panic_msgs = expected_panic_msgs, .string_bytes = string_bytes.items, }); @@ -93,8 +87,6 @@ fn mainServer() !void { log_err_count = 0; const index = try server.receiveBody_u32(); const test_fn = builtin.test_functions[index]; - if (test_fn.async_frame_size != null) - @panic("TODO test runner implement async tests"); var fail = false; var skip = false; var leak = false; @@ -163,23 +155,7 @@ fn mainTerminal() void { if (!have_tty) { std.debug.print("{d}/{d} {s}... ", .{ i + 1, test_fn_list.len, test_fn.name }); } - const result = if (test_fn.async_frame_size) |size| switch (std.options.io_mode) { - .evented => blk: { - if (async_frame_buffer.len < size) { - std.heap.page_allocator.free(async_frame_buffer); - async_frame_buffer = std.heap.page_allocator.alignedAlloc(u8, std.Target.stack_align, size) catch @panic("out of memory"); - } - const casted_fn = @as(fn () callconv(.Async) anyerror!void, @ptrCast(test_fn.func)); - break :blk await @asyncCall(async_frame_buffer, {}, casted_fn, .{}); - }, - .blocking => { - skip_count += 1; - test_node.end(); - progress.log("SKIP (async test)\n", .{}); - continue; - }, - } else test_fn.func(); - if (result) |_| { + if (test_fn.func()) |_| { ok_count += 1; test_node.end(); if (!have_tty) std.debug.print("OK\n", .{}); diff --git a/src/Builtin.zig b/src/Builtin.zig index 3211dd3a69..fb0c1e9490 100644 --- a/src/Builtin.zig +++ b/src/Builtin.zig @@ -3,7 +3,6 @@ zig_backend: std.builtin.CompilerBackend, output_mode: std.builtin.OutputMode, link_mode: std.builtin.LinkMode, is_test: bool, -test_evented_io: bool, single_threaded: bool, link_libc: bool, link_libcpp: bool, @@ -222,17 +221,6 @@ pub fn append(opts: @This(), buffer: *std.ArrayList(u8)) Allocator.Error!void { \\pub var test_functions: []const std.builtin.TestFn = undefined; // overwritten later \\ ); - if (opts.test_evented_io) { - try buffer.appendSlice( - \\pub const test_io_mode = .evented; - \\ - ); - } else { - try buffer.appendSlice( - \\pub const test_io_mode = .blocking; - \\ - ); - } } } diff --git a/src/Compilation.zig b/src/Compilation.zig index 237f22df58..4074cc61a4 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -1607,7 +1607,6 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil hash.add(options.config.use_lib_llvm); hash.add(options.config.dll_export_fns); hash.add(options.config.is_test); - hash.add(options.config.test_evented_io); hash.addOptionalBytes(options.test_filter); hash.addOptionalBytes(options.test_name_prefix); hash.add(options.skip_linker_dependencies); @@ -2471,7 +2470,6 @@ fn addNonIncrementalStuffToCacheManifest( try addModuleTableToCacheHash(gpa, arena, &man.hash, mod.root_mod, mod.main_mod, .{ .files = man }); // Synchronize with other matching comments: ZigOnlyHashStuff - man.hash.add(comp.config.test_evented_io); man.hash.addOptionalBytes(comp.test_filter); man.hash.addOptionalBytes(comp.test_name_prefix); man.hash.add(comp.skip_linker_dependencies); diff --git a/src/Compilation/Config.zig b/src/Compilation/Config.zig index 78273f66e4..2f6422b28a 100644 --- a/src/Compilation/Config.zig +++ b/src/Compilation/Config.zig @@ -54,7 +54,6 @@ import_memory: bool, export_memory: bool, shared_memory: bool, is_test: bool, -test_evented_io: bool, debug_format: DebugFormat, root_strip: bool, root_error_tracing: bool, @@ -104,7 +103,6 @@ pub const Options = struct { import_memory: ?bool = null, export_memory: ?bool = null, shared_memory: ?bool = null, - test_evented_io: bool = false, debug_format: ?DebugFormat = null, dll_export_fns: ?bool = null, rdynamic: ?bool = null, @@ -477,7 +475,6 @@ pub fn resolve(options: Options) ResolveError!Config { .output_mode = options.output_mode, .have_zcu = options.have_zcu, .is_test = options.is_test, - .test_evented_io = options.test_evented_io, .link_mode = link_mode, .link_libc = link_libc, .link_libcpp = link_libcpp, diff --git a/src/Module.zig b/src/Module.zig index 221ea041b5..4f5b15bc1c 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -5237,10 +5237,6 @@ pub fn populateTestFunctions( } const decl = mod.declPtr(decl_index); const test_fn_ty = decl.ty.slicePtrFieldType(mod).childType(mod); - const null_usize = try mod.intern(.{ .opt = .{ - .ty = try mod.intern(.{ .opt_type = .usize_type }), - .val = .none, - } }); const array_decl_index = d: { // Add mod.test_functions to an array decl then make the test_functions @@ -5289,8 +5285,6 @@ pub fn populateTestFunctions( } }), .addr = .{ .decl = test_decl_index }, } }), - // async_frame_size - null_usize, }; test_fn_val.* = try mod.intern(.{ .aggregate = .{ .ty = test_fn_ty.toIntern(), diff --git a/src/Package/Module.zig b/src/Package/Module.zig index 66d5a21eab..6fadbf1dd5 100644 --- a/src/Package/Module.zig +++ b/src/Package/Module.zig @@ -349,7 +349,6 @@ pub fn create(arena: Allocator, options: CreateOptions) !*Package.Module { .output_mode = options.global.output_mode, .link_mode = options.global.link_mode, .is_test = options.global.is_test, - .test_evented_io = options.global.test_evented_io, .single_threaded = single_threaded, .link_libc = options.global.link_libc, .link_libcpp = options.global.link_libcpp, diff --git a/src/main.zig b/src/main.zig index c3d5a28ccf..81a8dc2a13 100644 --- a/src/main.zig +++ b/src/main.zig @@ -1322,8 +1322,6 @@ fn buildOutputType( create_module.each_lib_rpath = false; } else if (mem.eql(u8, arg, "--test-cmd-bin")) { try test_exec_args.append(null); - } else if (mem.eql(u8, arg, "--test-evented-io")) { - create_module.opts.test_evented_io = true; } else if (mem.eql(u8, arg, "--test-no-exec")) { test_no_exec = true; } else if (mem.eql(u8, arg, "-ftime-report")) {