authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-10-28 18:04:55-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-10-29 06:20:52-07:00
logc40204a3e521b82094fb44b2ce412f47d05964b2
treed7a5c1ac715631ba5f80048f81ab402fc8309050
parent03fd132b1ce82f767ffdb6cc886d1934b40c6071

std.Io: add unit tests for Group and concurrent


3 files changed, 97 insertions(+), 1 deletions(-)

lib/std/Io/Threaded.zig+4
...@@ -6114,3 +6114,7 @@ fn initializeWsa(t: *Threaded) error{NetworkDown}!void {...@@ -6114,3 +6114,7 @@ fn initializeWsa(t: *Threaded) error{NetworkDown}!void {
6114 }6114 }
6115 return error.NetworkDown;6115 return error.NetworkDown;
6116}6116}
6117
6118test {
6119 _ = @import("Threaded/test.zig");
6120}
lib/std/Io/Threaded/test.zig created+46
...@@ -0,0 +1,46 @@
1const std = @import("std");
2const Io = std.Io;
3const testing = std.testing;
4const assert = std.debug.assert;
5
6test "concurrent vs main prevents deadlock via oversubscription" {
7 var threaded: Io.Threaded = .init(std.testing.allocator);
8 defer threaded.deinit();
9 const io = threaded.io();
10
11 threaded.cpu_count = 1;
12
13 var queue: Io.Queue(u8) = .init(&.{});
14
15 var putter = try io.concurrent(put, .{ io, &queue });
16 defer putter.cancel(io);
17
18 try testing.expectEqual(42, queue.getOneUncancelable(io));
19}
20
21fn put(io: Io, queue: *Io.Queue(u8)) void {
22 queue.putOneUncancelable(io, 42);
23}
24
25fn get(io: Io, queue: *Io.Queue(u8)) void {
26 assert(queue.getOneUncancelable(io) == 42);
27}
28
29test "concurrent vs concurrent prevents deadlock via oversubscription" {
30 var threaded: Io.Threaded = .init(std.testing.allocator);
31 defer threaded.deinit();
32 const io = threaded.io();
33
34 threaded.cpu_count = 1;
35
36 var queue: Io.Queue(u8) = .init(&.{});
37
38 var putter = try io.concurrent(put, .{ io, &queue });
39 defer putter.cancel(io);
40
41 var getter = try io.concurrent(get, .{ io, &queue });
42 defer getter.cancel(io);
43
44 getter.await(io);
45 putter.await(io);
46}
lib/std/Io/test.zig+47-1
...@@ -1,4 +1,8 @@...@@ -1,4 +1,8 @@
1const builtin = @import("builtin");
2const native_endian = builtin.cpu.arch.endian();
3
1const std = @import("std");4const std = @import("std");
5const Io = std.Io;
2const DefaultPrng = std.Random.DefaultPrng;6const DefaultPrng = std.Random.DefaultPrng;
3const expect = std.testing.expect;7const expect = std.testing.expect;
4const expectEqual = std.testing.expectEqual;8const expectEqual = std.testing.expectEqual;
...@@ -6,7 +10,6 @@ const expectError = std.testing.expectError;...@@ -6,7 +10,6 @@ const expectError = std.testing.expectError;
6const mem = std.mem;10const mem = std.mem;
7const fs = std.fs;11const fs = std.fs;
8const File = std.fs.File;12const File = std.fs.File;
9const native_endian = @import("builtin").target.cpu.arch.endian();
1013
11const tmpDir = std.testing.tmpDir;14const tmpDir = std.testing.tmpDir;
1215
...@@ -123,3 +126,46 @@ test "updateTimes" {...@@ -123,3 +126,46 @@ test "updateTimes" {
123 try expect(stat_new.atime.nanoseconds < stat_old.atime.nanoseconds);126 try expect(stat_new.atime.nanoseconds < stat_old.atime.nanoseconds);
124 try expect(stat_new.mtime.nanoseconds < stat_old.mtime.nanoseconds);127 try expect(stat_new.mtime.nanoseconds < stat_old.mtime.nanoseconds);
125}128}
129
130test "Group" {
131 const io = std.testing.io;
132
133 var group: Io.Group = .init;
134 var results: [2]usize = undefined;
135
136 group.async(io, count, .{ 1, 10, &results[0] });
137 group.async(io, count, .{ 20, 30, &results[1] });
138
139 group.wait(io);
140
141 try std.testing.expectEqualSlices(usize, &.{ 45, 245 }, &results);
142}
143
144fn count(a: usize, b: usize, result: *usize) void {
145 var sum: usize = 0;
146 for (a..b) |i| {
147 sum += i;
148 }
149 result.* = sum;
150}
151
152test "Group cancellation" {
153 const io = std.testing.io;
154
155 var group: Io.Group = .init;
156 var results: [2]usize = undefined;
157
158 group.async(io, sleep, .{ io, &results[0] });
159 group.async(io, sleep, .{ io, &results[1] });
160
161 group.cancel(io);
162
163 try std.testing.expectEqualSlices(usize, &.{ 1, 1 }, &results);
164}
165
166fn sleep(io: Io, result: *usize) void {
167 // TODO when cancellation race bug is fixed, make this timeout much longer so that
168 // it causes the unit test to be failed if not cancelled.
169 io.sleep(.fromMilliseconds(1), .awake) catch {};
170 result.* = 1;
171}