-
-
Notifications
You must be signed in to change notification settings - Fork 2.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
std.io: add GenericStream and AnyStream #19376
Conversation
c5298e3
to
adb70aa
Compare
adb70aa
to
5b1356d
Compare
- replace Reader `fn read(ctx, buffer: []u8)` with `readv(ctx, iovecs: []std.posix.iovec)` - replace Writer `fn write(ctx, buffer: []const u8)` with `writev(ctx, iovecs: []std.posix.iovec_const)`
d55bc15
to
e180295
Compare
Looks like the status quo HTTP client with TLS already crashes for https://www.google.com without the Since it's fixed in #19308 I'm tempted to leave this strange fix in unless someone else can figure out the issue. I spent 3 hours to get this far. I really thought it had to do with Here's the stack trace~/src/zig-test(master)$ zig build run-client
fetching https://www.google.com/
General protection exception (no address available)
/home/thesm/.local/share/zvm/local/lib/std/crypto/tls/Client.zig:741:31: 0x831b0e6 in prepareCiphertextRecord (client.zig)
P.AEAD.encrypt(ciphertext, auth_tag, cleartext, ad, nonce, p.client_key);
^
Unwind error at address `exe:0x831b0e6` (error.AddressOutOfRange), trace may be incomplete
/home/thesm/.local/share/zvm/local/lib/std/crypto/tls/Client.zig:646:43: 0x8232962 in writeEnd (client.zig)
var prepared = prepareCiphertextRecord(c, &iovecs_buf, &ciphertext_buf, bytes, .application_data);
^
/home/thesm/.local/share/zvm/local/lib/std/crypto/tls/Client.zig:671:26: 0x8233118 in writev (client.zig)
return try c.writeEnd(bytes, false);
^
/home/thesm/.local/share/zvm/local/lib/std/io.zig:374:28: 0x81aa955 in typeErasedWritevFn (client.zig)
return writevFn(ptr.*, iov);
^
/home/thesm/.local/share/zvm/local/lib/std/io/Writer.zig:13:25: 0x81ab929 in writev (client.zig)
return self.writevFn(self.context, iov);
^
/home/thesm/.local/share/zvm/local/lib/std/io/Writer.zig:21:34: 0x801d4f5 in writevAll (client.zig)
var amt = try self.writev(iovecs[i..]);
^
/home/thesm/.local/share/zvm/local/lib/std/io/Writer.zig:39:26: 0x80081fd in writeAll (client.zig)
return self.writevAll(&iov);
^
/home/thesm/.local/share/zvm/local/lib/std/http/Client.zig:357:41: 0x801bd8a in flush (client.zig)
try conn.any().writer().writeAll(conn.write_buf[0..conn.write_end]);
^
/home/thesm/.local/share/zvm/local/lib/std/http/Client.zig:888:29: 0x8007286 in send (client.zig)
try connection.flush();
^
/home/thesm/.local/share/zvm/local/lib/std/http/Client.zig:1740:17: 0x8000490 in fetch (client.zig)
try req.send(.{ .raw_uri = options.raw_uri });
^
/home/thesm/src/zig-test/src/client.zig:25:33: 0x800150e in fetch_old (client.zig)
const req = try client.fetch(.{ |
Introducing The |
I'm already a bit tired from splitting this PR out from #19308. I know the changeset is large, but I think changing
That's a good point.
It does apply. I'll update the OP. |
I've thought more about the lack of If the only goal is to save syscalls, I think integrating cross-platform io event loops like libxev into Readers/Writers/Sockets is a better path to pursue. If the goal is convenience when parsing/serializing I believe developers ought to think more carefully about buffering (which also improves cache coherency) than lean on platform-dependent I don't think Reader/Writer types should support more than a simple read and write: pub fn read(fd: fd_t, buf: []u8) ReadError!usize {}
pub fn write(fd: fd_t, bytes: []const u8) WriteError!usize {} So after adding them everywhere in this PR, I've swung in favor of removing Most usages are in http/tls code for parsing and serializing that can be refactored to use a buffered reader or writer in #19308 without having to heap allocate (I'm looking at Also, I think the |
std.posix.iovec
andstd.posix.iovec_const
members fromiov_base
andiov_len
toptr
andlen
(matches slice).std.io.ReadBuffers = std.posix.iovec;
andstd.io.WriteBuffers = std.posix.iovec_const;
.std.io.[GenericReader|AnyReader]
'sfn read(ctx, buffer: []u8)
withreadv(ctx, iovecs: []std.io.ReadBuffers)
.std.io.[GenericWriter|AnyWriter]
'sfn write(ctx, buffer: []const u8)
withwritev(ctx, iovecs: []std.io.WriteBuffers)
.GenericStream
andAnyStream
that hasreadv
,writev
, and a newclose(ctx): void
parameter. Use it instd.net
,std.http
, andstd.crypto.tls
to abstract over TLS/plain socket streams and removeStreamInterface
.This change is intended to promote generic reader syscall efficiency with
readv
andwritev
(for supported platforms) and provide a type erased stream type to reduce future code bloat from instantiating many generic stream types in #19308.Existing Readers/Writers have been changed to read/write all buffers where possible. When significant logic would have to change, I've opted to simply extract a buffer from the first entry in
std.io.ReadBuffers
orstd.io.WriteBuffers
and leave the function alone.I chose to not make the slices const so that implementers like
writevAll
can cleverly mutate the vector fields without having to copy them. This seems to outweigh the cost of forcing callers to duplicatestd.io.ReadBuffers
orstd.io.WriteBuffers
when sending to multiple readers/writers. A stack cloneablestd.io.ReadBuffers
andstd.io.WriteBuffers
type may remove this limitation in the future.