authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-05-02 14:08:59-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-05-02 14:09:17-04:00
log5656f5090d8646e076db50da03cfc6ae686eb76b
tree89b400bd5cf8eadf57b92af194a44bc9530f9594
parent9dac8a5be9f5e439ea857b22867aaf2dc5b70c62

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.

2 files changed, 42 insertions(+), 11 deletions(-)

lib/std/fs/file.zig+40-9
...@@ -8,6 +8,7 @@ const assert = std.debug.assert;...@@ -8,6 +8,7 @@ const assert = std.debug.assert;
8const windows = os.windows;8const windows = os.windows;
9const Os = builtin.Os;9const Os = builtin.Os;
10const maxInt = std.math.maxInt;10const maxInt = std.math.maxInt;
11const is_windows = std.Target.current.os.tag == .windows;
1112
12pub const File = struct {13pub const File = struct {
13 /// The OS-specific file descriptor or file handle.14 /// The OS-specific file descriptor or file handle.
...@@ -119,7 +120,9 @@ pub const File = struct {...@@ -119,7 +120,9 @@ pub const File = struct {
119 /// Upon success, the stream is in an uninitialized state. To continue using it,120 /// Upon success, the stream is in an uninitialized state. To continue using it,
120 /// you must use the open() function.121 /// you must use the open() function.
121 pub fn close(self: File) void {122 pub fn close(self: File) void {
122 if (self.capable_io_mode != self.intended_io_mode) {123 if (is_windows) {
124 windows.CloseHandle(self.handle);
125 } else if (self.capable_io_mode != self.intended_io_mode) {
123 std.event.Loop.instance.?.close(self.handle);126 std.event.Loop.instance.?.close(self.handle);
124 } else {127 } else {
125 os.close(self.handle);128 os.close(self.handle);
...@@ -302,7 +305,9 @@ pub const File = struct {...@@ -302,7 +305,9 @@ pub const File = struct {
302 pub const PReadError = os.PReadError;305 pub const PReadError = os.PReadError;
303306
304 pub fn read(self: File, buffer: []u8) ReadError!usize {307 pub fn read(self: File, buffer: []u8) ReadError!usize {
305 if (self.capable_io_mode != self.intended_io_mode) {308 if (is_windows) {
309 return windows.ReadFile(self.handle, buffer, null, self.intended_io_mode);
310 } else if (self.capable_io_mode != self.intended_io_mode) {
306 return std.event.Loop.instance.?.read(self.handle, buffer);311 return std.event.Loop.instance.?.read(self.handle, buffer);
307 } else {312 } else {
308 return os.read(self.handle, buffer);313 return os.read(self.handle, buffer);
...@@ -322,7 +327,9 @@ pub const File = struct {...@@ -322,7 +327,9 @@ pub const File = struct {
322 }327 }
323328
324 pub fn pread(self: File, buffer: []u8, offset: u64) PReadError!usize {329 pub fn pread(self: File, buffer: []u8, offset: u64) PReadError!usize {
325 if (self.capable_io_mode != self.intended_io_mode) {330 if (is_windows) {
331 return windows.ReadFile(self.handle, buffer, offset, self.intended_io_mode);
332 } else if (self.capable_io_mode != self.intended_io_mode) {
326 return std.event.Loop.instance.?.pread(self.handle, buffer, offset);333 return std.event.Loop.instance.?.pread(self.handle, buffer, offset);
327 } else {334 } else {
328 return os.pread(self.handle, buffer, offset);335 return os.pread(self.handle, buffer, offset);
...@@ -342,7 +349,12 @@ pub const File = struct {...@@ -342,7 +349,12 @@ pub const File = struct {
342 }349 }
343350
344 pub fn readv(self: File, iovecs: []const os.iovec) ReadError!usize {351 pub fn readv(self: File, iovecs: []const os.iovec) ReadError!usize {
345 if (self.capable_io_mode != self.intended_io_mode) {352 if (is_windows) {
353 // TODO improve this to use ReadFileScatter
354 if (iovecs.len == 0) return @as(usize, 0);
355 const first = iovecs[0];
356 return windows.ReadFile(self.handle, first.iov_base[0..first.iov_len], null, self.intended_io_mode);
357 } else if (self.capable_io_mode != self.intended_io_mode) {
346 return std.event.Loop.instance.?.readv(self.handle, iovecs);358 return std.event.Loop.instance.?.readv(self.handle, iovecs);
347 } else {359 } else {
348 return os.readv(self.handle, iovecs);360 return os.readv(self.handle, iovecs);
...@@ -376,7 +388,12 @@ pub const File = struct {...@@ -376,7 +388,12 @@ pub const File = struct {
376 }388 }
377389
378 pub fn preadv(self: File, iovecs: []const os.iovec, offset: u64) PReadError!usize {390 pub fn preadv(self: File, iovecs: []const os.iovec, offset: u64) PReadError!usize {
379 if (self.capable_io_mode != self.intended_io_mode) {391 if (is_windows) {
392 // TODO improve this to use ReadFileScatter
393 if (iovecs.len == 0) return @as(usize, 0);
394 const first = iovecs[0];
395 return windows.ReadFile(self.handle, first.iov_base[0..first.iov_len], offset, self.intended_io_mode);
396 } else if (self.capable_io_mode != self.intended_io_mode) {
380 return std.event.Loop.instance.?.preadv(self.handle, iovecs, offset);397 return std.event.Loop.instance.?.preadv(self.handle, iovecs, offset);
381 } else {398 } else {
382 return os.preadv(self.handle, iovecs, offset);399 return os.preadv(self.handle, iovecs, offset);
...@@ -413,7 +430,9 @@ pub const File = struct {...@@ -413,7 +430,9 @@ pub const File = struct {
413 pub const PWriteError = os.PWriteError;430 pub const PWriteError = os.PWriteError;
414431
415 pub fn write(self: File, bytes: []const u8) WriteError!usize {432 pub fn write(self: File, bytes: []const u8) WriteError!usize {
416 if (self.capable_io_mode != self.intended_io_mode) {433 if (is_windows) {
434 return windows.WriteFile(self.handle, bytes, null, self.intended_io_mode);
435 } else if (self.capable_io_mode != self.intended_io_mode) {
417 return std.event.Loop.instance.?.write(self.handle, bytes);436 return std.event.Loop.instance.?.write(self.handle, bytes);
418 } else {437 } else {
419 return os.write(self.handle, bytes);438 return os.write(self.handle, bytes);
...@@ -428,7 +447,9 @@ pub const File = struct {...@@ -428,7 +447,9 @@ pub const File = struct {
428 }447 }
429448
430 pub fn pwrite(self: File, bytes: []const u8, offset: u64) PWriteError!usize {449 pub fn pwrite(self: File, bytes: []const u8, offset: u64) PWriteError!usize {
431 if (self.capable_io_mode != self.intended_io_mode) {450 if (is_windows) {
451 return windows.WriteFile(self.handle, bytes, offset, self.intended_io_mode);
452 } else if (self.capable_io_mode != self.intended_io_mode) {
432 return std.event.Loop.instance.?.pwrite(self.handle, bytes, offset);453 return std.event.Loop.instance.?.pwrite(self.handle, bytes, offset);
433 } else {454 } else {
434 return os.pwrite(self.handle, bytes, offset);455 return os.pwrite(self.handle, bytes, offset);
...@@ -443,7 +464,12 @@ pub const File = struct {...@@ -443,7 +464,12 @@ pub const File = struct {
443 }464 }
444465
445 pub fn writev(self: File, iovecs: []const os.iovec_const) WriteError!usize {466 pub fn writev(self: File, iovecs: []const os.iovec_const) WriteError!usize {
446 if (self.capable_io_mode != self.intended_io_mode) {467 if (is_windows) {
468 // TODO improve this to use WriteFileScatter
469 if (iovecs.len == 0) return @as(usize, 0);
470 const first = iovecs[0];
471 return windows.WriteFile(self.handle, first.iov_base[0..first.iov_len], null, self.intended_io_mode);
472 } else if (self.capable_io_mode != self.intended_io_mode) {
447 return std.event.Loop.instance.?.writev(self.handle, iovecs);473 return std.event.Loop.instance.?.writev(self.handle, iovecs);
448 } else {474 } else {
449 return os.writev(self.handle, iovecs);475 return os.writev(self.handle, iovecs);
...@@ -469,7 +495,12 @@ pub const File = struct {...@@ -469,7 +495,12 @@ pub const File = struct {
469 }495 }
470496
471 pub fn pwritev(self: File, iovecs: []os.iovec_const, offset: usize) PWriteError!usize {497 pub fn pwritev(self: File, iovecs: []os.iovec_const, offset: usize) PWriteError!usize {
472 if (self.capable_io_mode != self.intended_io_mode) {498 if (is_windows) {
499 // TODO improve this to use WriteFileScatter
500 if (iovecs.len == 0) return @as(usize, 0);
501 const first = iovecs[0];
502 return windows.WriteFile(self.handle, first.iov_base[0..first.iov_len], offset, self.intended_io_mode);
503 } else if (self.capable_io_mode != self.intended_io_mode) {
473 return std.event.Loop.instance.?.pwritev(self.handle, iovecs, offset);504 return std.event.Loop.instance.?.pwritev(self.handle, iovecs, offset);
474 } else {505 } else {
475 return os.pwritev(self.handle, iovecs, offset);506 return os.pwritev(self.handle, iovecs, offset);
lib/std/os.zig+2-2
...@@ -365,7 +365,7 @@ pub fn read(fd: fd_t, buf: []u8) ReadError!usize {...@@ -365,7 +365,7 @@ pub fn read(fd: fd_t, buf: []u8) ReadError!usize {
365/// On these systems, the read races with concurrent writes to the same file descriptor.365/// On these systems, the read races with concurrent writes to the same file descriptor.
366pub fn readv(fd: fd_t, iov: []const iovec) ReadError!usize {366pub fn readv(fd: fd_t, iov: []const iovec) ReadError!usize {
367 if (std.Target.current.os.tag == .windows) {367 if (std.Target.current.os.tag == .windows) {
368 // TODO does Windows have a way to read an io vector?368 // TODO improve this to use ReadFileScatter
369 if (iov.len == 0) return @as(usize, 0);369 if (iov.len == 0) return @as(usize, 0);
370 const first = iov[0];370 const first = iov[0];
371 return read(fd, first.iov_base[0..first.iov_len]);371 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 {...@@ -651,7 +651,7 @@ pub fn write(fd: fd_t, bytes: []const u8) WriteError!usize {
651/// If `iov.len` is larger than will fit in a `u31`, a partial write will occur.651/// If `iov.len` is larger than will fit in a `u31`, a partial write will occur.
652pub fn writev(fd: fd_t, iov: []const iovec_const) WriteError!usize {652pub fn writev(fd: fd_t, iov: []const iovec_const) WriteError!usize {
653 if (std.Target.current.os.tag == .windows) {653 if (std.Target.current.os.tag == .windows) {
654 // TODO does Windows have a way to write an io vector?654 // TODO improve this to use WriteFileScatter
655 if (iov.len == 0) return @as(usize, 0);655 if (iov.len == 0) return @as(usize, 0);
656 const first = iov[0];656 const first = iov[0];
657 return write(fd, first.iov_base[0..first.iov_len]);657 return write(fd, first.iov_base[0..first.iov_len]);