authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-01-14 20:41:40-08:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-01-15 14:18:20-08:00
loge70def70ece846433b7a2140291ed416a6c34f43
tree0e6fd3d5111a6258128fca65093d286a82465f06
parentc917f619f041f5494e1c2d13c28ce1b04cec11f7

std.Io.Threaded: passing memory mapping tests on wasm32-wasi


1 files changed, 169 insertions(+), 94 deletions(-)

lib/std/Io/Threaded.zig+169-94
......@@ -7963,7 +7963,7 @@ fn fileReadStreamingPosix(userdata: ?*anyopaque, file: File, data: []const []u8)
79637963 switch (e) {
79647964 .INVAL => |err| return errnoBug(err),
79657965 .FAULT => |err| return errnoBug(err),
7966 .BADF => return error.NotOpenForReading, // File operation on directory.
7966 .BADF => return error.IsDir, // File operation on directory.
79677967 .IO => return error.InputOutput,
79687968 .ISDIR => return error.IsDir,
79697969 .NOBUFS => return error.SystemResources,
......@@ -8793,7 +8793,7 @@ fn fileWritePositional(
87938793 .INVAL => |err| return errnoBug(err),
87948794 .FAULT => |err| return errnoBug(err),
87958795 .AGAIN => |err| return errnoBug(err),
8796 .BADF => return error.NotOpenForWriting, // can be a race condition.
8796 .BADF => |err| return errnoBug(err), // use after free
87978797 .DESTADDRREQ => |err| return errnoBug(err), // `connect` was never called.
87988798 .DQUOT => return error.DiskQuota,
87998799 .FBIG => return error.FileTooBig,
......@@ -16176,6 +16176,7 @@ fn fileMemoryMapCreate(
1617616176 return result;
1617716177 } else |err| switch (err) {
1617816178 error.Unseekable, error.Canceled, error.AccessDenied => |e| return e,
16179 error.OperationUnsupported => {},
1617916180 else => {
1618016181 if (builtin.mode == .Debug)
1618116182 std.log.warn("memory mapping failed with {t}, falling back to file operations", .{err});
......@@ -16478,104 +16479,178 @@ fn fileMemoryMapWrite(userdata: ?*anyopaque, mm: *File.MemoryMap) File.WritePosi
1647816479}
1647916480
1648016481fn mmSyncRead(file: File, memory: []u8, offset: u64) File.ReadPositionalError!void {
16481 switch (native_os) {
16482 .windows => @panic("TODO"),
16483 .wasi => @panic("TODO"),
16484 else => {
16485 var i: usize = 0;
16486 const syscall: Syscall = try .start();
16487 while (true) {
16488 const buf = memory[i..];
16489 if (buf.len == 0) {
16490 syscall.finish();
16491 break;
16492 }
16493 const rc = pread_sym(file.handle, buf.ptr, buf.len, @intCast(offset + i));
16494 switch (posix.errno(rc)) {
16495 .SUCCESS => {
16496 const n: usize = @intCast(rc);
16497 if (n == 0) {
16498 syscall.finish();
16499 @memset(memory[i..], 0);
16500 break;
16501 }
16502 i += n;
16503 try syscall.checkCancel();
16504 continue;
16505 },
16506 .INTR, .TIMEDOUT => {
16507 try syscall.checkCancel();
16508 continue;
16509 },
16510 .NXIO => return syscall.fail(error.Unseekable),
16511 .SPIPE => return syscall.fail(error.Unseekable),
16512 .OVERFLOW => return syscall.fail(error.Unseekable),
16513 .NOBUFS => return syscall.fail(error.SystemResources),
16514 .NOMEM => return syscall.fail(error.SystemResources),
16515 .AGAIN => return syscall.fail(error.WouldBlock),
16516 .IO => return syscall.fail(error.InputOutput),
16517 .ISDIR => return syscall.fail(error.IsDir),
16518 .NOTCONN => |err| return syscall.errnoBug(err), // not a socket
16519 .CONNRESET => |err| return syscall.errnoBug(err), // not a socket
16520 .INVAL => |err| return syscall.errnoBug(err),
16521 .FAULT => |err| return syscall.errnoBug(err),
16522 .BADF => |err| {
16482 if (is_windows) {
16483 @panic("TODO");
16484 } else if (native_os == .wasi and !builtin.link_libc) {
16485 var i: usize = 0;
16486 const syscall: Syscall = try .start();
16487 while (true) {
16488 const buf = memory[i..];
16489 if (buf.len == 0) {
16490 syscall.finish();
16491 break;
16492 }
16493 var n: usize = undefined;
16494 const vec: std.os.wasi.iovec_t = .{ .base = buf.ptr, .len = buf.len };
16495 switch (std.os.wasi.fd_pread(file.handle, (&vec)[0..1], 1, offset + i, &n)) {
16496 .SUCCESS => {
16497 if (n == 0) {
1652316498 syscall.finish();
16524 if (native_os == .wasi) return error.IsDir; // File operation on directory.
16525 return errnoBug(err); // File descriptor used after closed.
16526 },
16527 else => |err| return syscall.unexpectedErrno(err),
16528 }
16499 @memset(memory[i..], 0);
16500 break;
16501 }
16502 i += n;
16503 try syscall.checkCancel();
16504 continue;
16505 },
16506 .INTR, .TIMEDOUT => {
16507 try syscall.checkCancel();
16508 continue;
16509 },
16510 .NOTCONN => |err| return syscall.errnoBug(err), // not a socket
16511 .CONNRESET => |err| return syscall.errnoBug(err), // not a socket
16512 .BADF => |err| return syscall.errnoBug(err), // use after free
16513 .INVAL => |err| return syscall.errnoBug(err),
16514 .FAULT => |err| return syscall.errnoBug(err), // segmentation fault
16515 .AGAIN => |err| return syscall.errnoBug(err),
16516 .IO => return syscall.fail(error.InputOutput),
16517 .ISDIR => return syscall.fail(error.IsDir),
16518 .NOBUFS => return syscall.fail(error.SystemResources),
16519 .NOMEM => return syscall.fail(error.SystemResources),
16520 .NXIO => return syscall.fail(error.Unseekable),
16521 .SPIPE => return syscall.fail(error.Unseekable),
16522 .OVERFLOW => return syscall.fail(error.Unseekable),
16523 .NOTCAPABLE => return syscall.fail(error.AccessDenied),
16524 else => |err| return syscall.unexpectedErrno(err),
1652916525 }
16530 },
16526 }
16527 } else {
16528 var i: usize = 0;
16529 const syscall: Syscall = try .start();
16530 while (true) {
16531 const buf = memory[i..];
16532 if (buf.len == 0) {
16533 syscall.finish();
16534 break;
16535 }
16536 const rc = pread_sym(file.handle, buf.ptr, buf.len, @intCast(offset + i));
16537 switch (posix.errno(rc)) {
16538 .SUCCESS => {
16539 const n: usize = @intCast(rc);
16540 if (n == 0) {
16541 syscall.finish();
16542 @memset(memory[i..], 0);
16543 break;
16544 }
16545 i += n;
16546 try syscall.checkCancel();
16547 continue;
16548 },
16549 .INTR, .TIMEDOUT => {
16550 try syscall.checkCancel();
16551 continue;
16552 },
16553 .NXIO => return syscall.fail(error.Unseekable),
16554 .SPIPE => return syscall.fail(error.Unseekable),
16555 .OVERFLOW => return syscall.fail(error.Unseekable),
16556 .NOBUFS => return syscall.fail(error.SystemResources),
16557 .NOMEM => return syscall.fail(error.SystemResources),
16558 .AGAIN => return syscall.fail(error.WouldBlock),
16559 .IO => return syscall.fail(error.InputOutput),
16560 .ISDIR => return syscall.fail(error.IsDir),
16561 .NOTCONN => |err| return syscall.errnoBug(err), // not a socket
16562 .CONNRESET => |err| return syscall.errnoBug(err), // not a socket
16563 .INVAL => |err| return syscall.errnoBug(err),
16564 .FAULT => |err| return syscall.errnoBug(err),
16565 .BADF => |err| return syscall.errnoBug(err), // use after free
16566 else => |err| return syscall.unexpectedErrno(err),
16567 }
16568 }
1653116569 }
1653216570}
1653316571
1653416572fn mmSyncWrite(file: File, memory: []u8, offset: u64) File.WritePositionalError!void {
16535 switch (native_os) {
16536 .windows => @panic("TODO"),
16537 .wasi => @panic("TODO"),
16538 else => {
16539 var i: usize = 0;
16540 const syscall: Syscall = try .start();
16541 while (true) {
16542 const buf = memory[i..];
16543 if (buf.len == 0) {
16544 syscall.finish();
16545 break;
16546 }
16547 const rc = pwrite_sym(file.handle, buf.ptr, buf.len, @intCast(offset));
16548 switch (posix.errno(rc)) {
16549 .SUCCESS => {
16550 const n: usize = @bitCast(rc);
16551 i += n;
16552 try syscall.checkCancel();
16553 continue;
16554 },
16555 .INTR => {
16556 try syscall.checkCancel();
16557 continue;
16558 },
16559 .INVAL => |err| return syscall.errnoBug(err),
16560 .FAULT => |err| return syscall.errnoBug(err),
16561 .DESTADDRREQ => |err| return syscall.errnoBug(err), // not a socket
16562 .CONNRESET => |err| return syscall.errnoBug(err), // not a socket
16563 .BADF => |err| return syscall.errnoBug(err), // use after free
16564 .AGAIN => return syscall.fail(error.WouldBlock),
16565 .DQUOT => return syscall.fail(error.DiskQuota),
16566 .FBIG => return syscall.fail(error.FileTooBig),
16567 .IO => return syscall.fail(error.InputOutput),
16568 .NOSPC => return syscall.fail(error.NoSpaceLeft),
16569 .PERM => return syscall.fail(error.PermissionDenied),
16570 .PIPE => return syscall.fail(error.BrokenPipe),
16571 .BUSY => return syscall.fail(error.DeviceBusy),
16572 .TXTBSY => return syscall.fail(error.FileBusy),
16573 .NXIO => return syscall.fail(error.Unseekable),
16574 .SPIPE => return syscall.fail(error.Unseekable),
16575 .OVERFLOW => return syscall.fail(error.Unseekable),
16576 else => |err| return syscall.unexpectedErrno(err),
16577 }
16573 if (is_windows) {
16574 @panic("TODO");
16575 } else if (native_os == .wasi and !builtin.link_libc) {
16576 var i: usize = 0;
16577 var n: usize = undefined;
16578 const syscall: Syscall = try .start();
16579 while (true) {
16580 const buf = memory[i..];
16581 if (buf.len == 0) {
16582 syscall.finish();
16583 break;
1657816584 }
16579 },
16585 const iovec: std.os.wasi.ciovec_t = .{ .base = buf.ptr, .len = buf.len };
16586 switch (std.os.wasi.fd_pwrite(file.handle, (&iovec)[0..1], 1, offset + i, &n)) {
16587 .SUCCESS => {
16588 i += n;
16589 try syscall.checkCancel();
16590 continue;
16591 },
16592 .INTR => {
16593 try syscall.checkCancel();
16594 continue;
16595 },
16596 .DQUOT => return syscall.fail(error.DiskQuota),
16597 .FBIG => return syscall.fail(error.FileTooBig),
16598 .IO => return syscall.fail(error.InputOutput),
16599 .NOSPC => return syscall.fail(error.NoSpaceLeft),
16600 .PERM => return syscall.fail(error.PermissionDenied),
16601 .PIPE => return syscall.fail(error.BrokenPipe),
16602 .NOTCAPABLE => return syscall.fail(error.AccessDenied),
16603 .NXIO => return syscall.fail(error.Unseekable),
16604 .SPIPE => return syscall.fail(error.Unseekable),
16605 .OVERFLOW => return syscall.fail(error.Unseekable),
16606 .INVAL => |err| return syscall.errnoBug(err),
16607 .FAULT => |err| return syscall.errnoBug(err),
16608 .AGAIN => |err| return syscall.errnoBug(err),
16609 .BADF => |err| return syscall.errnoBug(err), // use after free
16610 .DESTADDRREQ => |err| return syscall.errnoBug(err), // not a socket
16611 else => |err| return syscall.unexpectedErrno(err),
16612 }
16613 }
16614 } else {
16615 var i: usize = 0;
16616 const syscall: Syscall = try .start();
16617 while (true) {
16618 const buf = memory[i..];
16619 if (buf.len == 0) {
16620 syscall.finish();
16621 break;
16622 }
16623 const rc = pwrite_sym(file.handle, buf.ptr, buf.len, @intCast(offset + i));
16624 switch (posix.errno(rc)) {
16625 .SUCCESS => {
16626 const n: usize = @bitCast(rc);
16627 i += n;
16628 try syscall.checkCancel();
16629 continue;
16630 },
16631 .INTR => {
16632 try syscall.checkCancel();
16633 continue;
16634 },
16635 .INVAL => |err| return syscall.errnoBug(err),
16636 .FAULT => |err| return syscall.errnoBug(err),
16637 .DESTADDRREQ => |err| return syscall.errnoBug(err), // not a socket
16638 .CONNRESET => |err| return syscall.errnoBug(err), // not a socket
16639 .BADF => |err| return syscall.errnoBug(err), // use after free
16640 .AGAIN => return syscall.fail(error.WouldBlock),
16641 .DQUOT => return syscall.fail(error.DiskQuota),
16642 .FBIG => return syscall.fail(error.FileTooBig),
16643 .IO => return syscall.fail(error.InputOutput),
16644 .NOSPC => return syscall.fail(error.NoSpaceLeft),
16645 .PERM => return syscall.fail(error.PermissionDenied),
16646 .PIPE => return syscall.fail(error.BrokenPipe),
16647 .BUSY => return syscall.fail(error.DeviceBusy),
16648 .TXTBSY => return syscall.fail(error.FileBusy),
16649 .NXIO => return syscall.fail(error.Unseekable),
16650 .SPIPE => return syscall.fail(error.Unseekable),
16651 .OVERFLOW => return syscall.fail(error.Unseekable),
16652 else => |err| return syscall.unexpectedErrno(err),
16653 }
16654 }
1658016655 }
1658116656}