fs.File: improve handling async I/O on Windows

Before it was possible for .intended_io_mode = .blocking,
.capable_io_mode = .evented, and then the implementation would put a
request on the fs thread, which is the wrong behavior. Now it always
calls the appropriate WriteFile/ReadFile function, passing the intended
io mode directly as a parameter.

This makes the behavior tests pass on Windows with --test-evented-io.
master
Andrew Kelley 2020-05-02 14:08:59 -04:00
parent 9dac8a5be9
commit 5656f5090d
2 changed files with 42 additions and 11 deletions

View File

@ -8,6 +8,7 @@ const assert = std.debug.assert;
const windows = os.windows;
const Os = builtin.Os;
const maxInt = std.math.maxInt;
const is_windows = std.Target.current.os.tag == .windows;
pub const File = struct {
/// The OS-specific file descriptor or file handle.
@ -119,7 +120,9 @@ pub const File = struct {
/// Upon success, the stream is in an uninitialized state. To continue using it,
/// you must use the open() function.
pub fn close(self: File) void {
if (self.capable_io_mode != self.intended_io_mode) {
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 {
os.close(self.handle);
@ -302,7 +305,9 @@ pub const File = struct {
pub const PReadError = os.PReadError;
pub fn read(self: File, buffer: []u8) ReadError!usize {
if (self.capable_io_mode != self.intended_io_mode) {
if (is_windows) {
return windows.ReadFile(self.handle, buffer, null, self.intended_io_mode);
} else if (self.capable_io_mode != self.intended_io_mode) {
return std.event.Loop.instance.?.read(self.handle, buffer);
} else {
return os.read(self.handle, buffer);
@ -322,7 +327,9 @@ pub const File = struct {
}
pub fn pread(self: File, buffer: []u8, offset: u64) PReadError!usize {
if (self.capable_io_mode != self.intended_io_mode) {
if (is_windows) {
return windows.ReadFile(self.handle, buffer, offset, self.intended_io_mode);
} else if (self.capable_io_mode != self.intended_io_mode) {
return std.event.Loop.instance.?.pread(self.handle, buffer, offset);
} else {
return os.pread(self.handle, buffer, offset);
@ -342,7 +349,12 @@ pub const File = struct {
}
pub fn readv(self: File, iovecs: []const os.iovec) ReadError!usize {
if (self.capable_io_mode != self.intended_io_mode) {
if (is_windows) {
// 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);
} else if (self.capable_io_mode != self.intended_io_mode) {
return std.event.Loop.instance.?.readv(self.handle, iovecs);
} else {
return os.readv(self.handle, iovecs);
@ -376,7 +388,12 @@ pub const File = struct {
}
pub fn preadv(self: File, iovecs: []const os.iovec, offset: u64) PReadError!usize {
if (self.capable_io_mode != self.intended_io_mode) {
if (is_windows) {
// 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);
} else if (self.capable_io_mode != self.intended_io_mode) {
return std.event.Loop.instance.?.preadv(self.handle, iovecs, offset);
} else {
return os.preadv(self.handle, iovecs, offset);
@ -413,7 +430,9 @@ pub const File = struct {
pub const PWriteError = os.PWriteError;
pub fn write(self: File, bytes: []const u8) WriteError!usize {
if (self.capable_io_mode != self.intended_io_mode) {
if (is_windows) {
return windows.WriteFile(self.handle, bytes, null, self.intended_io_mode);
} else if (self.capable_io_mode != self.intended_io_mode) {
return std.event.Loop.instance.?.write(self.handle, bytes);
} else {
return os.write(self.handle, bytes);
@ -428,7 +447,9 @@ pub const File = struct {
}
pub fn pwrite(self: File, bytes: []const u8, offset: u64) PWriteError!usize {
if (self.capable_io_mode != self.intended_io_mode) {
if (is_windows) {
return windows.WriteFile(self.handle, bytes, offset, self.intended_io_mode);
} else if (self.capable_io_mode != self.intended_io_mode) {
return std.event.Loop.instance.?.pwrite(self.handle, bytes, offset);
} else {
return os.pwrite(self.handle, bytes, offset);
@ -443,7 +464,12 @@ pub const File = struct {
}
pub fn writev(self: File, iovecs: []const os.iovec_const) WriteError!usize {
if (self.capable_io_mode != self.intended_io_mode) {
if (is_windows) {
// 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);
} else if (self.capable_io_mode != self.intended_io_mode) {
return std.event.Loop.instance.?.writev(self.handle, iovecs);
} else {
return os.writev(self.handle, iovecs);
@ -469,7 +495,12 @@ pub const File = struct {
}
pub fn pwritev(self: File, iovecs: []os.iovec_const, offset: usize) PWriteError!usize {
if (self.capable_io_mode != self.intended_io_mode) {
if (is_windows) {
// 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);
} else if (self.capable_io_mode != self.intended_io_mode) {
return std.event.Loop.instance.?.pwritev(self.handle, iovecs, offset);
} else {
return os.pwritev(self.handle, iovecs, offset);

View File

@ -365,7 +365,7 @@ pub fn read(fd: fd_t, buf: []u8) ReadError!usize {
/// On these systems, the read races with concurrent writes to the same file descriptor.
pub fn readv(fd: fd_t, iov: []const iovec) ReadError!usize {
if (std.Target.current.os.tag == .windows) {
// TODO does Windows have a way to read an io vector?
// TODO improve this to use ReadFileScatter
if (iov.len == 0) return @as(usize, 0);
const first = iov[0];
return read(fd, first.iov_base[0..first.iov_len]);
@ -651,7 +651,7 @@ pub fn write(fd: fd_t, bytes: []const u8) WriteError!usize {
/// If `iov.len` is larger than will fit in a `u31`, a partial write will occur.
pub fn writev(fd: fd_t, iov: []const iovec_const) WriteError!usize {
if (std.Target.current.os.tag == .windows) {
// TODO does Windows have a way to write an io vector?
// TODO improve this to use WriteFileScatter
if (iov.len == 0) return @as(usize, 0);
const first = iov[0];
return write(fd, first.iov_base[0..first.iov_len]);