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)...@@ -7963,7 +7963,7 @@ fn fileReadStreamingPosix(userdata: ?*anyopaque, file: File, data: []const []u8)
7963 switch (e) {7963 switch (e) {
7964 .INVAL => |err| return errnoBug(err),7964 .INVAL => |err| return errnoBug(err),
7965 .FAULT => |err| return errnoBug(err),7965 .FAULT => |err| return errnoBug(err),
7966 .BADF => return error.NotOpenForReading, // File operation on directory.7966 .BADF => return error.IsDir, // File operation on directory.
7967 .IO => return error.InputOutput,7967 .IO => return error.InputOutput,
7968 .ISDIR => return error.IsDir,7968 .ISDIR => return error.IsDir,
7969 .NOBUFS => return error.SystemResources,7969 .NOBUFS => return error.SystemResources,
...@@ -8793,7 +8793,7 @@ fn fileWritePositional(...@@ -8793,7 +8793,7 @@ fn fileWritePositional(
8793 .INVAL => |err| return errnoBug(err),8793 .INVAL => |err| return errnoBug(err),
8794 .FAULT => |err| return errnoBug(err),8794 .FAULT => |err| return errnoBug(err),
8795 .AGAIN => |err| return errnoBug(err),8795 .AGAIN => |err| return errnoBug(err),
8796 .BADF => return error.NotOpenForWriting, // can be a race condition.8796 .BADF => |err| return errnoBug(err), // use after free
8797 .DESTADDRREQ => |err| return errnoBug(err), // `connect` was never called.8797 .DESTADDRREQ => |err| return errnoBug(err), // `connect` was never called.
8798 .DQUOT => return error.DiskQuota,8798 .DQUOT => return error.DiskQuota,
8799 .FBIG => return error.FileTooBig,8799 .FBIG => return error.FileTooBig,
...@@ -16176,6 +16176,7 @@ fn fileMemoryMapCreate(...@@ -16176,6 +16176,7 @@ fn fileMemoryMapCreate(
16176 return result;16176 return result;
16177 } else |err| switch (err) {16177 } else |err| switch (err) {
16178 error.Unseekable, error.Canceled, error.AccessDenied => |e| return e,16178 error.Unseekable, error.Canceled, error.AccessDenied => |e| return e,
16179 error.OperationUnsupported => {},
16179 else => {16180 else => {
16180 if (builtin.mode == .Debug)16181 if (builtin.mode == .Debug)
16181 std.log.warn("memory mapping failed with {t}, falling back to file operations", .{err});16182 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...@@ -16478,104 +16479,178 @@ fn fileMemoryMapWrite(userdata: ?*anyopaque, mm: *File.MemoryMap) File.WritePosi
16478}16479}
1647916480
16480fn mmSyncRead(file: File, memory: []u8, offset: u64) File.ReadPositionalError!void {16481fn mmSyncRead(file: File, memory: []u8, offset: u64) File.ReadPositionalError!void {
16481 switch (native_os) {16482 if (is_windows) {
16482 .windows => @panic("TODO"),16483 @panic("TODO");
16483 .wasi => @panic("TODO"),16484 } else if (native_os == .wasi and !builtin.link_libc) {
16484 else => {16485 var i: usize = 0;
16485 var i: usize = 0;16486 const syscall: Syscall = try .start();
16486 const syscall: Syscall = try .start();16487 while (true) {
16487 while (true) {16488 const buf = memory[i..];
16488 const buf = memory[i..];16489 if (buf.len == 0) {
16489 if (buf.len == 0) {16490 syscall.finish();
16490 syscall.finish();16491 break;
16491 break;16492 }
16492 }16493 var n: usize = undefined;
16493 const rc = pread_sym(file.handle, buf.ptr, buf.len, @intCast(offset + i));16494 const vec: std.os.wasi.iovec_t = .{ .base = buf.ptr, .len = buf.len };
16494 switch (posix.errno(rc)) {16495 switch (std.os.wasi.fd_pread(file.handle, (&vec)[0..1], 1, offset + i, &n)) {
16495 .SUCCESS => {16496 .SUCCESS => {
16496 const n: usize = @intCast(rc);16497 if (n == 0) {
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| {
16523 syscall.finish();16498 syscall.finish();
16524 if (native_os == .wasi) return error.IsDir; // File operation on directory.16499 @memset(memory[i..], 0);
16525 return errnoBug(err); // File descriptor used after closed.16500 break;
16526 },16501 }
16527 else => |err| return syscall.unexpectedErrno(err),16502 i += n;
16528 }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),
16529 }16525 }
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 }
16531 }16569 }
16532}16570}
1653316571
16534fn mmSyncWrite(file: File, memory: []u8, offset: u64) File.WritePositionalError!void {16572fn mmSyncWrite(file: File, memory: []u8, offset: u64) File.WritePositionalError!void {
16535 switch (native_os) {16573 if (is_windows) {
16536 .windows => @panic("TODO"),16574 @panic("TODO");
16537 .wasi => @panic("TODO"),16575 } else if (native_os == .wasi and !builtin.link_libc) {
16538 else => {16576 var i: usize = 0;
16539 var i: usize = 0;16577 var n: usize = undefined;
16540 const syscall: Syscall = try .start();16578 const syscall: Syscall = try .start();
16541 while (true) {16579 while (true) {
16542 const buf = memory[i..];16580 const buf = memory[i..];
16543 if (buf.len == 0) {16581 if (buf.len == 0) {
16544 syscall.finish();16582 syscall.finish();
16545 break;16583 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 }
16578 }16584 }
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 }
16580 }16655 }
16581}16656}