authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-07-15 20:52:56-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-07-15 20:52:56-07:00
loge9cb8a777b88b124ddc093a09d2ae7a62b8cda81
tree6a20ea5c755347e0df0e48cc7f038dc8a6647b99
parent87be80f6e9d1aa95cb55a8d7ef95808ca4aba44b
parent9a69aede0e250c136de5f1e1b33f072d4d744ffc

Merge remote-tracking branch 'origin/master' into wrangle-writer-buffering


8 files changed, 121 insertions(+), 26 deletions(-)

.github/workflows/ci.yaml-18
...@@ -50,24 +50,6 @@ jobs:...@@ -50,24 +50,6 @@ jobs:
50 uses: actions/checkout@v450 uses: actions/checkout@v4
51 - name: Build and Test51 - name: Build and Test
52 run: sh ci/aarch64-linux-release.sh52 run: sh ci/aarch64-linux-release.sh
53 riscv64-linux-debug:
54 if: ${{ github.event_name == 'push' }}
55 timeout-minutes: 1020
56 runs-on: [self-hosted, Linux, riscv64]
57 steps:
58 - name: Checkout
59 uses: actions/checkout@v4
60 - name: Build and Test
61 run: sh ci/riscv64-linux-debug.sh
62 riscv64-linux-release:
63 if: ${{ github.event_name == 'push' }}
64 timeout-minutes: 900
65 runs-on: [self-hosted, Linux, riscv64]
66 steps:
67 - name: Checkout
68 uses: actions/checkout@v4
69 - name: Build and Test
70 run: sh ci/riscv64-linux-release.sh
71 x86_64-macos-release:53 x86_64-macos-release:
72 runs-on: "macos-13"54 runs-on: "macos-13"
73 env:55 env:
.github/workflows/riscv.yaml created+22
...@@ -0,0 +1,22 @@
1name: riscv
2on:
3 workflow_dispatch:
4permissions:
5 contents: read
6jobs:
7 riscv64-linux-debug:
8 timeout-minutes: 1020
9 runs-on: [self-hosted, Linux, riscv64]
10 steps:
11 - name: Checkout
12 uses: actions/checkout@v4
13 - name: Build and Test
14 run: sh ci/riscv64-linux-debug.sh
15 riscv64-linux-release:
16 timeout-minutes: 900
17 runs-on: [self-hosted, Linux, riscv64]
18 steps:
19 - name: Checkout
20 uses: actions/checkout@v4
21 - name: Build and Test
22 run: sh ci/riscv64-linux-release.sh
lib/std/Io/Reader.zig+14
...@@ -1303,6 +1303,13 @@ fn takeMultipleOf7Leb128(r: *Reader, comptime Result: type) TakeLeb128Error!Resu...@@ -1303,6 +1303,13 @@ fn takeMultipleOf7Leb128(r: *Reader, comptime Result: type) TakeLeb128Error!Resu
1303}1303}
13041304
1305/// Left-aligns data such that `r.seek` becomes zero.1305/// Left-aligns data such that `r.seek` becomes zero.
1306///
1307/// If `r.seek` is not already zero then `buffer` is mutated, making it illegal
1308/// to call this function with a const-casted `buffer`, such as in the case of
1309/// `fixed`. This issue can be avoided:
1310/// * in implementations, by attempting a read before a rebase, in which
1311/// case the read will return `error.EndOfStream`, preventing the rebase.
1312/// * in usage, by copying into a mutable buffer before initializing `fixed`.
1306pub fn rebase(r: *Reader) void {1313pub fn rebase(r: *Reader) void {
1307 if (r.seek == 0) return;1314 if (r.seek == 0) return;
1308 const data = r.buffer[r.seek..r.end];1315 const data = r.buffer[r.seek..r.end];
...@@ -1315,6 +1322,13 @@ pub fn rebase(r: *Reader) void {...@@ -1315,6 +1322,13 @@ pub fn rebase(r: *Reader) void {
1315/// if necessary.1322/// if necessary.
1316///1323///
1317/// Asserts `capacity` is within the buffer capacity.1324/// Asserts `capacity` is within the buffer capacity.
1325///
1326/// If the rebase occurs then `buffer` is mutated, making it illegal to call
1327/// this function with a const-casted `buffer`, such as in the case of `fixed`.
1328/// This issue can be avoided:
1329/// * in implementations, by attempting a read before a rebase, in which
1330/// case the read will return `error.EndOfStream`, preventing the rebase.
1331/// * in usage, by copying into a mutable buffer before initializing `fixed`.
1318pub fn rebaseCapacity(r: *Reader, capacity: usize) void {1332pub fn rebaseCapacity(r: *Reader, capacity: usize) void {
1319 if (r.end > r.buffer.len - capacity) rebase(r);1333 if (r.end > r.buffer.len - capacity) rebase(r);
1320}1334}
lib/std/Io/Writer.zig+45-4
...@@ -2194,8 +2194,10 @@ pub const Discarding = struct {...@@ -2194,8 +2194,10 @@ pub const Discarding = struct {
2194 const d: *Discarding = @alignCast(@fieldParentPtr("writer", w));2194 const d: *Discarding = @alignCast(@fieldParentPtr("writer", w));
2195 d.count += w.end;2195 d.count += w.end;
2196 w.end = 0;2196 w.end = 0;
2197 if (limit == .nothing) return 0;
2197 if (file_reader.getSize()) |size| {2198 if (file_reader.getSize()) |size| {
2198 const n = limit.minInt64(size - file_reader.pos);2199 const n = limit.minInt64(size - file_reader.pos);
2200 if (n == 0) return error.EndOfStream;
2199 file_reader.seekBy(@intCast(n)) catch return error.Unimplemented;2201 file_reader.seekBy(@intCast(n)) catch return error.Unimplemented;
2200 w.end = 0;2202 w.end = 0;
2201 d.count += n;2203 d.count += n;
...@@ -2489,18 +2491,17 @@ pub const Allocating = struct {...@@ -2489,18 +2491,17 @@ pub const Allocating = struct {
24892491
2490 fn sendFile(w: *Writer, file_reader: *File.Reader, limit: std.io.Limit) FileError!usize {2492 fn sendFile(w: *Writer, file_reader: *File.Reader, limit: std.io.Limit) FileError!usize {
2491 if (File.Handle == void) return error.Unimplemented;2493 if (File.Handle == void) return error.Unimplemented;
2494 if (limit == .nothing) return 0;
2492 const a: *Allocating = @fieldParentPtr("writer", w);2495 const a: *Allocating = @fieldParentPtr("writer", w);
2493 const gpa = a.allocator;2496 const gpa = a.allocator;
2494 var list = a.toArrayList();2497 var list = a.toArrayList();
2495 defer setArrayList(a, list);2498 defer setArrayList(a, list);
2496 const pos = file_reader.pos;2499 const pos = file_reader.pos;
2497 const additional = if (file_reader.getSize()) |size| size - pos else |_| std.atomic.cache_line;2500 const additional = if (file_reader.getSize()) |size| size - pos else |_| std.atomic.cache_line;
2501 if (additional == 0) return error.EndOfStream;
2498 list.ensureUnusedCapacity(gpa, limit.minInt64(additional)) catch return error.WriteFailed;2502 list.ensureUnusedCapacity(gpa, limit.minInt64(additional)) catch return error.WriteFailed;
2499 const dest = limit.slice(list.unusedCapacitySlice());2503 const dest = limit.slice(list.unusedCapacitySlice());
2500 const n = file_reader.read(dest) catch |err| switch (err) {2504 const n = try file_reader.read(dest);
2501 error.ReadFailed => return error.ReadFailed,
2502 error.EndOfStream => 0,
2503 };
2504 list.items.len += n;2505 list.items.len += n;
2505 return n;2506 return n;
2506 }2507 }
...@@ -2522,3 +2523,43 @@ pub const Allocating = struct {...@@ -2522,3 +2523,43 @@ pub const Allocating = struct {
2522 try testing.expectEqualSlices(u8, "x: 42\ny: 1234\n", a.getWritten());2523 try testing.expectEqualSlices(u8, "x: 42\ny: 1234\n", a.getWritten());
2523 }2524 }
2524};2525};
2526
2527test "discarding sendFile" {
2528 var tmp_dir = testing.tmpDir(.{});
2529 defer tmp_dir.cleanup();
2530
2531 const file = try tmp_dir.dir.createFile("input.txt", .{ .read = true });
2532 defer file.close();
2533 var r_buffer: [256]u8 = undefined;
2534 var file_writer: std.fs.File.Writer = .init(file, &r_buffer);
2535 try file_writer.interface.writeByte('h');
2536 try file_writer.interface.flush();
2537
2538 var file_reader = file_writer.moveToReader();
2539 try file_reader.seekTo(0);
2540
2541 var w_buffer: [256]u8 = undefined;
2542 var discarding: std.io.Writer.Discarding = .init(&w_buffer);
2543
2544 _ = try file_reader.interface.streamRemaining(&discarding.writer);
2545}
2546
2547test "allocating sendFile" {
2548 var tmp_dir = testing.tmpDir(.{});
2549 defer tmp_dir.cleanup();
2550
2551 const file = try tmp_dir.dir.createFile("input.txt", .{ .read = true });
2552 defer file.close();
2553 var r_buffer: [256]u8 = undefined;
2554 var file_writer: std.fs.File.Writer = .init(file, &r_buffer);
2555 try file_writer.interface.writeByte('h');
2556 try file_writer.interface.flush();
2557
2558 var file_reader = file_writer.moveToReader();
2559 try file_reader.seekTo(0);
2560
2561 var allocating: std.io.Writer.Allocating = .init(std.testing.allocator);
2562 defer allocating.deinit();
2563
2564 _ = try file_reader.interface.streamRemaining(&allocating.writer);
2565}
lib/std/os/windows.zig+34
...@@ -1690,6 +1690,40 @@ pub fn getpeername(s: ws2_32.SOCKET, name: *ws2_32.sockaddr, namelen: *ws2_32.so...@@ -1690,6 +1690,40 @@ pub fn getpeername(s: ws2_32.SOCKET, name: *ws2_32.sockaddr, namelen: *ws2_32.so
1690 return ws2_32.getpeername(s, name, @as(*i32, @ptrCast(namelen)));1690 return ws2_32.getpeername(s, name, @as(*i32, @ptrCast(namelen)));
1691}1691}
16921692
1693pub fn sendmsg(
1694 s: ws2_32.SOCKET,
1695 msg: *ws2_32.WSAMSG_const,
1696 flags: u32,
1697) i32 {
1698 var bytes_send: DWORD = undefined;
1699 if (ws2_32.WSASendMsg(s, msg, flags, &bytes_send, null, null) == ws2_32.SOCKET_ERROR) {
1700 return ws2_32.SOCKET_ERROR;
1701 } else {
1702 return @as(i32, @as(u31, @intCast(bytes_send)));
1703 }
1704}
1705
1706pub fn sendto(s: ws2_32.SOCKET, buf: [*]const u8, len: usize, flags: u32, to: ?*const ws2_32.sockaddr, to_len: ws2_32.socklen_t) i32 {
1707 var buffer = ws2_32.WSABUF{ .len = @as(u31, @truncate(len)), .buf = @constCast(buf) };
1708 var bytes_send: DWORD = undefined;
1709 if (ws2_32.WSASendTo(s, @as([*]ws2_32.WSABUF, @ptrCast(&buffer)), 1, &bytes_send, flags, to, @as(i32, @intCast(to_len)), null, null) == ws2_32.SOCKET_ERROR) {
1710 return ws2_32.SOCKET_ERROR;
1711 } else {
1712 return @as(i32, @as(u31, @intCast(bytes_send)));
1713 }
1714}
1715
1716pub fn recvfrom(s: ws2_32.SOCKET, buf: [*]u8, len: usize, flags: u32, from: ?*ws2_32.sockaddr, from_len: ?*ws2_32.socklen_t) i32 {
1717 var buffer = ws2_32.WSABUF{ .len = @as(u31, @truncate(len)), .buf = buf };
1718 var bytes_received: DWORD = undefined;
1719 var flags_inout = flags;
1720 if (ws2_32.WSARecvFrom(s, @as([*]ws2_32.WSABUF, @ptrCast(&buffer)), 1, &bytes_received, &flags_inout, from, @as(?*i32, @ptrCast(from_len)), null, null) == ws2_32.SOCKET_ERROR) {
1721 return ws2_32.SOCKET_ERROR;
1722 } else {
1723 return @as(i32, @as(u31, @intCast(bytes_received)));
1724 }
1725}
1726
1693pub fn poll(fds: [*]ws2_32.pollfd, n: c_ulong, timeout: i32) i32 {1727pub fn poll(fds: [*]ws2_32.pollfd, n: c_ulong, timeout: i32) i32 {
1694 return ws2_32.WSAPoll(fds, n, timeout);1728 return ws2_32.WSAPoll(fds, n, timeout);
1695}1729}
test/standalone/build.zig+1
...@@ -31,6 +31,7 @@ pub fn build(b: *std.Build) void {...@@ -31,6 +31,7 @@ pub fn build(b: *std.Build) void {
31 const tools_target = b.resolveTargetQuery(.{});31 const tools_target = b.resolveTargetQuery(.{});
32 for ([_][]const u8{32 for ([_][]const u8{
33 // Alphabetically sorted. No need to build `tools/spirv/grammar.zig`.33 // Alphabetically sorted. No need to build `tools/spirv/grammar.zig`.
34 "../../tools/dump-cov.zig",
34 "../../tools/fetch_them_macos_headers.zig",35 "../../tools/fetch_them_macos_headers.zig",
35 "../../tools/gen_macos_headers_c.zig",36 "../../tools/gen_macos_headers_c.zig",
36 "../../tools/gen_outline_atomics.zig",37 "../../tools/gen_outline_atomics.zig",
test/standalone/build.zig.zon+2-1
...@@ -1,5 +1,6 @@...@@ -1,5 +1,6 @@
1.{1.{
2 .name = "standalone_test_cases",2 .name = .standalone_test_cases,
3 .fingerprint = 0xc0dbdf9c818957be,
3 .version = "0.0.0",4 .version = "0.0.0",
4 .dependencies = .{5 .dependencies = .{
5 .simple = .{6 .simple = .{
tools/dump-cov.zig+3-3
...@@ -33,7 +33,7 @@ pub fn main() !void {...@@ -33,7 +33,7 @@ pub fn main() !void {
33 defer coverage.deinit(gpa);33 defer coverage.deinit(gpa);
3434
35 var debug_info = std.debug.Info.load(gpa, exe_path, &coverage) catch |err| {35 var debug_info = std.debug.Info.load(gpa, exe_path, &coverage) catch |err| {
36 fatal("failed to load debug info for {}: {s}", .{ exe_path, @errorName(err) });36 fatal("failed to load debug info for {f}: {s}", .{ exe_path, @errorName(err) });
37 };37 };
38 defer debug_info.deinit(gpa);38 defer debug_info.deinit(gpa);
3939
...@@ -42,10 +42,10 @@ pub fn main() !void {...@@ -42,10 +42,10 @@ pub fn main() !void {
42 cov_path.sub_path,42 cov_path.sub_path,
43 1 << 30,43 1 << 30,
44 null,44 null,
45 @alignOf(SeenPcsHeader),45 .of(SeenPcsHeader),
46 null,46 null,
47 ) catch |err| {47 ) catch |err| {
48 fatal("failed to load coverage file {}: {s}", .{ cov_path, @errorName(err) });48 fatal("failed to load coverage file {f}: {s}", .{ cov_path, @errorName(err) });
49 };49 };
5050
51 var stdout_buffer: [4000]u8 = undefined;51 var stdout_buffer: [4000]u8 = undefined;