master
  1const builtin = @import("builtin");
  2
  3const std = @import("std");
  4const Io = std.Io;
  5const testing = std.testing;
  6const assert = std.debug.assert;
  7
  8test "concurrent vs main prevents deadlock via oversubscription" {
  9    var threaded: Io.Threaded = .init(std.testing.allocator);
 10    defer threaded.deinit();
 11    const io = threaded.io();
 12
 13    threaded.async_limit = .nothing;
 14
 15    var queue: Io.Queue(u8) = .init(&.{});
 16
 17    var putter = io.concurrent(put, .{ io, &queue }) catch |err| switch (err) {
 18        error.ConcurrencyUnavailable => {
 19            try testing.expect(builtin.single_threaded);
 20            return;
 21        },
 22    };
 23    defer putter.cancel(io);
 24
 25    try testing.expectEqual(42, queue.getOneUncancelable(io));
 26}
 27
 28fn put(io: Io, queue: *Io.Queue(u8)) void {
 29    queue.putOneUncancelable(io, 42);
 30}
 31
 32fn get(io: Io, queue: *Io.Queue(u8)) void {
 33    assert(queue.getOneUncancelable(io) == 42);
 34}
 35
 36test "concurrent vs concurrent prevents deadlock via oversubscription" {
 37    var threaded: Io.Threaded = .init(std.testing.allocator);
 38    defer threaded.deinit();
 39    const io = threaded.io();
 40
 41    threaded.async_limit = .nothing;
 42
 43    var queue: Io.Queue(u8) = .init(&.{});
 44
 45    var putter = io.concurrent(put, .{ io, &queue }) catch |err| switch (err) {
 46        error.ConcurrencyUnavailable => {
 47            try testing.expect(builtin.single_threaded);
 48            return;
 49        },
 50    };
 51    defer putter.cancel(io);
 52
 53    var getter = try io.concurrent(get, .{ io, &queue });
 54    defer getter.cancel(io);
 55
 56    getter.await(io);
 57    putter.await(io);
 58}
 59
 60const ByteArray256 = struct { x: [32]u8 align(32) };
 61const ByteArray512 = struct { x: [64]u8 align(64) };
 62
 63fn concatByteArrays(a: ByteArray256, b: ByteArray256) ByteArray512 {
 64    return .{ .x = a.x ++ b.x };
 65}
 66
 67test "async/concurrent context and result alignment" {
 68    var buffer: [2048]u8 align(@alignOf(ByteArray512)) = undefined;
 69    var fba: std.heap.FixedBufferAllocator = .init(&buffer);
 70
 71    var threaded: std.Io.Threaded = .init(fba.allocator());
 72    defer threaded.deinit();
 73    const io = threaded.io();
 74
 75    const a: ByteArray256 = .{ .x = @splat(2) };
 76    const b: ByteArray256 = .{ .x = @splat(3) };
 77    const expected: ByteArray512 = .{ .x = @as([32]u8, @splat(2)) ++ @as([32]u8, @splat(3)) };
 78
 79    {
 80        var future = io.async(concatByteArrays, .{ a, b });
 81        const result = future.await(io);
 82        try std.testing.expectEqualSlices(u8, &expected.x, &result.x);
 83    }
 84    {
 85        var future = io.concurrent(concatByteArrays, .{ a, b }) catch |err| switch (err) {
 86            error.ConcurrencyUnavailable => {
 87                try testing.expect(builtin.single_threaded);
 88                return;
 89            },
 90        };
 91        const result = future.await(io);
 92        try std.testing.expectEqualSlices(u8, &expected.x, &result.x);
 93    }
 94}
 95
 96fn concatByteArraysResultPtr(a: ByteArray256, b: ByteArray256, result: *ByteArray512) void {
 97    result.* = .{ .x = a.x ++ b.x };
 98}
 99
100test "Group.async context alignment" {
101    var buffer: [2048]u8 align(@alignOf(ByteArray512)) = undefined;
102    var fba: std.heap.FixedBufferAllocator = .init(&buffer);
103
104    var threaded: std.Io.Threaded = .init(fba.allocator());
105    defer threaded.deinit();
106    const io = threaded.io();
107
108    const a: ByteArray256 = .{ .x = @splat(2) };
109    const b: ByteArray256 = .{ .x = @splat(3) };
110    const expected: ByteArray512 = .{ .x = @as([32]u8, @splat(2)) ++ @as([32]u8, @splat(3)) };
111
112    var group: std.Io.Group = .init;
113    var result: ByteArray512 = undefined;
114    group.async(io, concatByteArraysResultPtr, .{ a, b, &result });
115    group.wait(io);
116    try std.testing.expectEqualSlices(u8, &expected.x, &result.x);
117}
118
119fn returnArray() [32]u8 {
120    return @splat(5);
121}
122
123test "async with array return type" {
124    var threaded: std.Io.Threaded = .init(std.testing.allocator);
125    defer threaded.deinit();
126    const io = threaded.io();
127
128    var future = io.async(returnArray, .{});
129    const result = future.await(io);
130    try std.testing.expectEqualSlices(u8, &@as([32]u8, @splat(5)), &result);
131}