| ... | @@ -8,7 +8,7 @@ const Allocator = std.mem.Allocator; | ... | @@ -8,7 +8,7 @@ const Allocator = std.mem.Allocator; |
| 8 | pub fn Group(comptime ReturnType: type) type { | 8 | pub fn Group(comptime ReturnType: type) type { |
| 9 | return struct { | 9 | return struct { |
| 10 | frame_stack: Stack, | 10 | frame_stack: Stack, |
| 11 | alloc_stack: Stack, | 11 | alloc_stack: AllocStack, |
| 12 | lock: Lock, | 12 | lock: Lock, |
| 13 | allocator: *Allocator, | 13 | allocator: *Allocator, |
| 14 | | 14 | |
| ... | @@ -19,11 +19,17 @@ pub fn Group(comptime ReturnType: type) type { | ... | @@ -19,11 +19,17 @@ pub fn Group(comptime ReturnType: type) type { |
| 19 | else => void, | 19 | else => void, |
| 20 | }; | 20 | }; |
| 21 | const Stack = std.atomic.Stack(anyframe->ReturnType); | 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 | pub fn init(allocator: *Allocator) Self { | 29 | pub fn init(allocator: *Allocator) Self { |
| 24 | return Self{ | 30 | return Self{ |
| 25 | .frame_stack = Stack.init(), | 31 | .frame_stack = Stack.init(), |
| 26 | .alloc_stack = Stack.init(), | 32 | .alloc_stack = AllocStack.init(), |
| 27 | .lock = Lock.init(), | 33 | .lock = Lock.init(), |
| 28 | .allocator = allocator, | 34 | .allocator = allocator, |
| 29 | }; | 35 | }; |
| ... | @@ -31,10 +37,12 @@ pub fn Group(comptime ReturnType: type) type { | ... | @@ -31,10 +37,12 @@ pub fn Group(comptime ReturnType: type) type { |
| 31 | | 37 | |
| 32 | /// Add a frame to the group. Thread-safe. | 38 | /// Add a frame to the group. Thread-safe. |
| 33 | pub fn add(self: *Self, handle: anyframe->ReturnType) (error{OutOfMemory}!void) { | 39 | pub fn add(self: *Self, handle: anyframe->ReturnType) (error{OutOfMemory}!void) { |
| 34 | const node = try self.allocator.create(Stack.Node); | 40 | const node = try self.allocator.create(AllocStack.Node); |
| 35 | node.* = Stack.Node{ | 41 | node.* = AllocStack.Node{ |
| 36 | .next = undefined, | 42 | .next = undefined, |
| 37 | .data = handle, | 43 | .data = Node{ |
| | 44 | .handle = handle, |
| | 45 | }, |
| 38 | }; | 46 | }; |
| 39 | self.alloc_stack.push(node); | 47 | self.alloc_stack.push(node); |
| 40 | } | 48 | } |
| ... | @@ -48,6 +56,24 @@ pub fn Group(comptime ReturnType: type) type { | ... | @@ -48,6 +56,24 @@ pub fn Group(comptime ReturnType: type) type { |
| 48 | self.frame_stack.push(node); | 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 | /// Wait for all the calls and promises of the group to complete. | 77 | /// Wait for all the calls and promises of the group to complete. |
| 52 | /// Thread-safe. | 78 | /// Thread-safe. |
| 53 | /// Safe to call any number of times. | 79 | /// Safe to call any number of times. |
| ... | @@ -67,8 +93,7 @@ pub fn Group(comptime ReturnType: type) type { | ... | @@ -67,8 +93,7 @@ pub fn Group(comptime ReturnType: type) type { |
| 67 | } | 93 | } |
| 68 | } | 94 | } |
| 69 | while (self.alloc_stack.pop()) |node| { | 95 | while (self.alloc_stack.pop()) |node| { |
| 70 | const handle = node.data; | 96 | const handle = node.data.handle; |
| 71 | self.allocator.destroy(node); | | |
| 72 | if (Error == void) { | 97 | if (Error == void) { |
| 73 | await handle; | 98 | await handle; |
| 74 | } else { | 99 | } else { |
| ... | @@ -76,6 +101,8 @@ pub fn Group(comptime ReturnType: type) type { | ... | @@ -76,6 +101,8 @@ pub fn Group(comptime ReturnType: type) type { |
| 76 | result = err; | 101 | result = err; |
| 77 | }; | 102 | }; |
| 78 | } | 103 | } |
| | 104 | self.allocator.free(node.data.bytes); |
| | 105 | self.allocator.destroy(node); |
| 79 | } | 106 | } |
| 80 | return result; | 107 | return result; |
| 81 | } | 108 | } |