| ... | ... | @@ -8,7 +8,7 @@ const Allocator = std.mem.Allocator; |
| 8 | 8 | pub fn Group(comptime ReturnType: type) type { |
| 9 | 9 | return struct { |
| 10 | 10 | frame_stack: Stack, |
| 11 | | alloc_stack: Stack, |
| 11 | alloc_stack: AllocStack, |
| 12 | 12 | lock: Lock, |
| 13 | 13 | allocator: *Allocator, |
| 14 | 14 | |
| ... | ... | @@ -19,11 +19,17 @@ pub fn Group(comptime ReturnType: type) type { |
| 19 | 19 | else => void, |
| 20 | 20 | }; |
| 21 | 21 | const Stack = std.atomic.Stack(anyframe->ReturnType); |
| 22 | const AllocStack = std.atomic.Stack(Node); |
| 23 | |
| 24 | pub const Node = struct { |
| 25 | bytes: []const u8 = [0]u8{}, |
| 26 | handle: anyframe->ReturnType, |
| 27 | }; |
| 22 | 28 | |
| 23 | 29 | pub fn init(allocator: *Allocator) Self { |
| 24 | 30 | return Self{ |
| 25 | 31 | .frame_stack = Stack.init(), |
| 26 | | .alloc_stack = Stack.init(), |
| 32 | .alloc_stack = AllocStack.init(), |
| 27 | 33 | .lock = Lock.init(), |
| 28 | 34 | .allocator = allocator, |
| 29 | 35 | }; |
| ... | ... | @@ -31,10 +37,12 @@ pub fn Group(comptime ReturnType: type) type { |
| 31 | 37 | |
| 32 | 38 | /// Add a frame to the group. Thread-safe. |
| 33 | 39 | pub fn add(self: *Self, handle: anyframe->ReturnType) (error{OutOfMemory}!void) { |
| 34 | | const node = try self.allocator.create(Stack.Node); |
| 35 | | node.* = Stack.Node{ |
| 40 | const node = try self.allocator.create(AllocStack.Node); |
| 41 | node.* = AllocStack.Node{ |
| 36 | 42 | .next = undefined, |
| 37 | | .data = handle, |
| 43 | .data = Node{ |
| 44 | .handle = handle, |
| 45 | }, |
| 38 | 46 | }; |
| 39 | 47 | self.alloc_stack.push(node); |
| 40 | 48 | } |
| ... | ... | @@ -48,6 +56,24 @@ pub fn Group(comptime ReturnType: type) type { |
| 48 | 56 | self.frame_stack.push(node); |
| 49 | 57 | } |
| 50 | 58 | |
| 59 | /// This is equivalent to adding a frame to the group but the memory of its frame is |
| 60 | /// allocated by the group and freed by `wait`. |
| 61 | /// `func` must be async and have return type `ReturnType`. |
| 62 | /// Thread-safe. |
| 63 | pub fn call(self: *Self, comptime func: var, args: ...) error{OutOfMemory}!void { |
| 64 | var frame = try self.allocator.create(@Frame(func)); |
| 65 | const node = try self.allocator.create(AllocStack.Node); |
| 66 | node.* = AllocStack.Node{ |
| 67 | .next = undefined, |
| 68 | .data = Node{ |
| 69 | .handle = frame, |
| 70 | .bytes = @sliceToBytes((*[1]@Frame(func))(frame)[0..]), |
| 71 | }, |
| 72 | }; |
| 73 | frame.* = async func(args); |
| 74 | self.alloc_stack.push(node); |
| 75 | } |
| 76 | |
| 51 | 77 | /// Wait for all the calls and promises of the group to complete. |
| 52 | 78 | /// Thread-safe. |
| 53 | 79 | /// Safe to call any number of times. |
| ... | ... | @@ -67,8 +93,7 @@ pub fn Group(comptime ReturnType: type) type { |
| 67 | 93 | } |
| 68 | 94 | } |
| 69 | 95 | while (self.alloc_stack.pop()) |node| { |
| 70 | | const handle = node.data; |
| 71 | | self.allocator.destroy(node); |
| 96 | const handle = node.data.handle; |
| 72 | 97 | if (Error == void) { |
| 73 | 98 | await handle; |
| 74 | 99 | } else { |
| ... | ... | @@ -76,6 +101,8 @@ pub fn Group(comptime ReturnType: type) type { |
| 76 | 101 | result = err; |
| 77 | 102 | }; |
| 78 | 103 | } |
| 104 | self.allocator.free(node.data.bytes); |
| 105 | self.allocator.destroy(node); |
| 79 | 106 | } |
| 80 | 107 | return result; |
| 81 | 108 | } |