authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-01-07 13:54:02-08:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-01-07 17:33:06-08:00
log2f372b3dc00c60a625e1cc3518fa1bda3429de59
tree37d690e0383cb461308a010cc36c4a2cbfb493dd
parent520397b48fac7fd0c107257c57f2cca4f0a40a98

goodbye posix.write

see #6600

3 files changed, 10 insertions(+), 102 deletions(-)

lib/std/Thread.zig+1-1
...@@ -175,7 +175,7 @@ pub const SetNameError = error{...@@ -175,7 +175,7 @@ pub const SetNameError = error{
175 Unsupported,175 Unsupported,
176 Unexpected,176 Unexpected,
177 InvalidWtf8,177 InvalidWtf8,
178} || posix.PrctlError || posix.WriteError || Io.File.OpenError || std.fmt.BufPrintError;178} || posix.PrctlError || Io.File.Writer.Error || Io.File.OpenError || std.fmt.BufPrintError;
179179
180pub fn setName(self: Thread, io: Io, name: []const u8) SetNameError!void {180pub fn setName(self: Thread, io: Io, name: []const u8) SetNameError!void {
181 if (name.len > max_name_len) return error.NameTooLong;181 if (name.len > max_name_len) return error.NameTooLong;
lib/std/posix.zig-97
...@@ -446,103 +446,6 @@ pub fn read(fd: fd_t, buf: []u8) ReadError!usize {...@@ -446,103 +446,6 @@ pub fn read(fd: fd_t, buf: []u8) ReadError!usize {
446 }446 }
447}447}
448448
449pub const WriteError = error{
450 DiskQuota,
451 FileTooBig,
452 InputOutput,
453 NoSpaceLeft,
454 DeviceBusy,
455 InvalidArgument,
456
457 /// File descriptor does not hold the required rights to write to it.
458 AccessDenied,
459 PermissionDenied,
460 BrokenPipe,
461 SystemResources,
462 Canceled,
463 NotOpenForWriting,
464
465 /// The process cannot access the file because another process has locked
466 /// a portion of the file. Windows-only.
467 LockViolation,
468
469 /// This error occurs when no global event loop is configured,
470 /// and reading from the file descriptor would block.
471 WouldBlock,
472
473 /// Connection reset by peer.
474 ConnectionResetByPeer,
475
476 /// This error occurs in Linux if the process being written to
477 /// no longer exists.
478 ProcessNotFound,
479 /// This error occurs when a device gets disconnected before or mid-flush
480 /// while it's being written to - errno(6): No such device or address.
481 NoDevice,
482
483 /// The socket type requires that message be sent atomically, and the size of the message
484 /// to be sent made this impossible. The message is not transmitted.
485 MessageOversize,
486} || UnexpectedError;
487
488/// Write to a file descriptor.
489/// Retries when interrupted by a signal.
490/// Returns the number of bytes written. If nonzero bytes were supplied, this will be nonzero.
491///
492/// Note that a successful write() may transfer fewer than count bytes. Such partial writes can
493/// occur for various reasons; for example, because there was insufficient space on the disk
494/// device to write all of the requested bytes, or because a blocked write() to a socket, pipe, or
495/// similar was interrupted by a signal handler after it had transferred some, but before it had
496/// transferred all of the requested bytes. In the event of a partial write, the caller can make
497/// another write() call to transfer the remaining bytes. The subsequent call will either
498/// transfer further bytes or may result in an error (e.g., if the disk is now full).
499///
500/// For POSIX systems, if `fd` is opened in non blocking mode, the function will
501/// return error.WouldBlock when EAGAIN is received.
502/// On Windows, if the application has a global event loop enabled, I/O Completion Ports are
503/// used to perform the I/O. `error.WouldBlock` is not possible on Windows.
504///
505/// Linux has a limit on how many bytes may be transferred in one `write` call, which is `0x7ffff000`
506/// on both 64-bit and 32-bit systems. This is due to using a signed C int as the return value, as
507/// well as stuffing the errno codes into the last `4096` values. This is noted on the `write` man page.
508/// The limit on Darwin is `0x7fffffff`, trying to read more than that returns EINVAL.
509/// The corresponding POSIX limit is `maxInt(isize)`.
510pub fn write(fd: fd_t, bytes: []const u8) WriteError!usize {
511 if (bytes.len == 0) return 0;
512 if (native_os == .windows) @compileError("unsupported OS");
513 if (native_os == .wasi) @compileError("unsupported OS");
514
515 const max_count = switch (native_os) {
516 .linux => 0x7ffff000,
517 .driverkit, .ios, .maccatalyst, .macos, .tvos, .visionos, .watchos => maxInt(i32),
518 else => maxInt(isize),
519 };
520 while (true) {
521 const rc = system.write(fd, bytes.ptr, @min(bytes.len, max_count));
522 switch (errno(rc)) {
523 .SUCCESS => return @intCast(rc),
524 .INTR => continue,
525 .INVAL => return error.InvalidArgument,
526 .FAULT => unreachable,
527 .AGAIN => return error.WouldBlock,
528 .BADF => return error.NotOpenForWriting, // can be a race condition.
529 .DESTADDRREQ => unreachable, // `connect` was never called.
530 .DQUOT => return error.DiskQuota,
531 .FBIG => return error.FileTooBig,
532 .IO => return error.InputOutput,
533 .NOSPC => return error.NoSpaceLeft,
534 .ACCES => return error.AccessDenied,
535 .PERM => return error.PermissionDenied,
536 .PIPE => return error.BrokenPipe,
537 .CONNRESET => return error.ConnectionResetByPeer,
538 .BUSY => return error.DeviceBusy,
539 .NXIO => return error.NoDevice,
540 .MSGSIZE => return error.MessageOversize,
541 else => |err| return unexpectedErrno(err),
542 }
543 }
544}
545
546pub const OpenError = std.Io.File.OpenError || error{WouldBlock};449pub const OpenError = std.Io.File.OpenError || error{WouldBlock};
547450
548/// Open and possibly create a file. Keeps trying if it gets interrupted.451/// Open and possibly create a file. Keeps trying if it gets interrupted.
lib/std/posix/test.zig+9-4
...@@ -121,13 +121,18 @@ test "pipe" {...@@ -121,13 +121,18 @@ test "pipe" {
121 if (native_os == .windows or native_os == .wasi)121 if (native_os == .windows or native_os == .wasi)
122 return error.SkipZigTest;122 return error.SkipZigTest;
123123
124 const io = testing.io;
125
124 const fds = try std.Io.Threaded.pipe2(.{});126 const fds = try std.Io.Threaded.pipe2(.{});
125 try expect((try posix.write(fds[1], "hello")) == 5);127 const out: Io.File = .{ .handle = fds[0] };
128 const in: Io.File = .{ .handle = fds[1] };
129 try in.writeStreamingAll(io, "hello");
126 var buf: [16]u8 = undefined;130 var buf: [16]u8 = undefined;
127 try expect((try posix.read(fds[0], buf[0..])) == 5);131 try expect((try out.readStreaming(io, &.{&buf})) == 5);
132
128 try expectEqualSlices(u8, buf[0..5], "hello");133 try expectEqualSlices(u8, buf[0..5], "hello");
129 posix.close(fds[1]);134 out.close(io);
130 posix.close(fds[0]);135 in.close(io);
131}136}
132137
133test "memfd_create" {138test "memfd_create" {