| ... | ... | @@ -1183,10 +1183,12 @@ fn groupConcurrent( |
| 1183 | 1183 | t.cond.signal(); |
| 1184 | 1184 | } |
| 1185 | 1185 | |
| 1186 | | fn groupWait(userdata: ?*anyopaque, group: *Io.Group, token: *anyopaque) void { |
| 1186 | fn groupWait(userdata: ?*anyopaque, group: *Io.Group, initial_token: *anyopaque) void { |
| 1187 | 1187 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| 1188 | 1188 | const gpa = t.allocator; |
| 1189 | 1189 | |
| 1190 | _ = initial_token; // we need to load `token` *after* the group finishes |
| 1191 | |
| 1190 | 1192 | if (builtin.single_threaded) unreachable; // we never set `group.token` to non-`null` |
| 1191 | 1193 | |
| 1192 | 1194 | const group_state: *std.atomic.Value(usize) = @ptrCast(&group.state); |
| ... | ... | @@ -1195,42 +1197,40 @@ fn groupWait(userdata: ?*anyopaque, group: *Io.Group, token: *anyopaque) void { |
| 1195 | 1197 | assert(prev_state & GroupClosure.sync_is_waiting == 0); |
| 1196 | 1198 | if ((prev_state / GroupClosure.sync_one_pending) > 0) event.wait(ioBasic(t)) catch |err| switch (err) { |
| 1197 | 1199 | error.Canceled => { |
| 1198 | | var node: *std.SinglyLinkedList.Node = @ptrCast(@alignCast(token)); |
| 1199 | | while (true) { |
| 1200 | var it: ?*std.SinglyLinkedList.Node = @ptrCast(@alignCast(group.token.load(.monotonic))); |
| 1201 | while (it) |node| : (it = node.next) { |
| 1200 | 1202 | const gc: *GroupClosure = @fieldParentPtr("node", node); |
| 1201 | 1203 | gc.closure.requestCancel(t); |
| 1202 | | node = node.next orelse break; |
| 1203 | 1204 | } |
| 1204 | 1205 | event.waitUncancelable(ioBasic(t)); |
| 1205 | 1206 | }, |
| 1206 | 1207 | }; |
| 1207 | 1208 | |
| 1208 | | var node: *std.SinglyLinkedList.Node = @ptrCast(@alignCast(token)); |
| 1209 | | while (true) { |
| 1210 | | const gc: *GroupClosure = @fieldParentPtr("node", node); |
| 1211 | | const node_next = node.next; |
| 1212 | | gc.deinit(gpa); |
| 1213 | | node = node_next orelse break; |
| 1214 | | } |
| 1215 | | |
| 1216 | 1209 | // Since the group has now finished, it's illegal to add more tasks to it until we return. It's |
| 1217 | 1210 | // also illegal for us to race with another `await` or `cancel`. Therefore, we must be the only |
| 1218 | 1211 | // thread who can access `group` right now. |
| 1212 | var it: ?*std.SinglyLinkedList.Node = @ptrCast(@alignCast(group.token.raw)); |
| 1219 | 1213 | group.token.raw = null; |
| 1214 | while (it) |node| { |
| 1215 | it = node.next; // update `it` now, because `deinit` will invalidate `node` |
| 1216 | const gc: *GroupClosure = @fieldParentPtr("node", node); |
| 1217 | gc.deinit(gpa); |
| 1218 | } |
| 1220 | 1219 | } |
| 1221 | 1220 | |
| 1222 | | fn groupCancel(userdata: ?*anyopaque, group: *Io.Group, token: *anyopaque) void { |
| 1221 | fn groupCancel(userdata: ?*anyopaque, group: *Io.Group, initial_token: *anyopaque) void { |
| 1223 | 1222 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| 1224 | 1223 | const gpa = t.allocator; |
| 1225 | 1224 | |
| 1225 | _ = initial_token; // we need to load `token` *after* the group finishes |
| 1226 | |
| 1226 | 1227 | if (builtin.single_threaded) unreachable; // we never set `group.token` to non-`null` |
| 1227 | 1228 | |
| 1228 | 1229 | { |
| 1229 | | var node: *std.SinglyLinkedList.Node = @ptrCast(@alignCast(token)); |
| 1230 | | while (true) { |
| 1230 | var it: ?*std.SinglyLinkedList.Node = @ptrCast(@alignCast(group.token.load(.monotonic))); |
| 1231 | while (it) |node| : (it = node.next) { |
| 1231 | 1232 | const gc: *GroupClosure = @fieldParentPtr("node", node); |
| 1232 | 1233 | gc.closure.requestCancel(t); |
| 1233 | | node = node.next orelse break; |
| 1234 | 1234 | } |
| 1235 | 1235 | } |
| 1236 | 1236 | |
| ... | ... | @@ -1240,20 +1240,16 @@ fn groupCancel(userdata: ?*anyopaque, group: *Io.Group, token: *anyopaque) void |
| 1240 | 1240 | assert(prev_state & GroupClosure.sync_is_waiting == 0); |
| 1241 | 1241 | if ((prev_state / GroupClosure.sync_one_pending) > 0) event.waitUncancelable(ioBasic(t)); |
| 1242 | 1242 | |
| 1243 | | { |
| 1244 | | var node: *std.SinglyLinkedList.Node = @ptrCast(@alignCast(token)); |
| 1245 | | while (true) { |
| 1246 | | const gc: *GroupClosure = @fieldParentPtr("node", node); |
| 1247 | | const node_next = node.next; |
| 1248 | | gc.deinit(gpa); |
| 1249 | | node = node_next orelse break; |
| 1250 | | } |
| 1251 | | } |
| 1252 | | |
| 1253 | 1243 | // Since the group has now finished, it's illegal to add more tasks to it until we return. It's |
| 1254 | 1244 | // also illegal for us to race with another `await` or `cancel`. Therefore, we must be the only |
| 1255 | 1245 | // thread who can access `group` right now. |
| 1246 | var it: ?*std.SinglyLinkedList.Node = @ptrCast(@alignCast(group.token.raw)); |
| 1256 | 1247 | group.token.raw = null; |
| 1248 | while (it) |node| { |
| 1249 | it = node.next; // update `it` now, because `deinit` will invalidate `node` |
| 1250 | const gc: *GroupClosure = @fieldParentPtr("node", node); |
| 1251 | gc.deinit(gpa); |
| 1252 | } |
| 1257 | 1253 | } |
| 1258 | 1254 | |
| 1259 | 1255 | fn recancel(userdata: ?*anyopaque) void { |