| ... | ... | @@ -1117,8 +1117,8 @@ fn groupAsync( |
| 1117 | 1117 | } |
| 1118 | 1118 | |
| 1119 | 1119 | // Append to the group linked list inside the mutex to make `Io.Group.async` thread-safe. |
| 1120 | | gc.node = .{ .next = @ptrCast(@alignCast(group.token)) }; |
| 1121 | | group.token = &gc.node; |
| 1120 | gc.node = .{ .next = @ptrCast(@alignCast(group.token.load(.monotonic))) }; |
| 1121 | group.token.store(&gc.node, .monotonic); |
| 1122 | 1122 | |
| 1123 | 1123 | t.run_queue.prepend(&gc.closure.node); |
| 1124 | 1124 | |
| ... | ... | @@ -1169,8 +1169,8 @@ fn groupConcurrent( |
| 1169 | 1169 | } |
| 1170 | 1170 | |
| 1171 | 1171 | // Append to the group linked list inside the mutex to make `Io.Group.concurrent` thread-safe. |
| 1172 | | gc.node = .{ .next = @ptrCast(@alignCast(group.token)) }; |
| 1173 | | group.token = &gc.node; |
| 1172 | gc.node = .{ .next = @ptrCast(@alignCast(group.token.load(.monotonic))) }; |
| 1173 | group.token.store(&gc.node, .monotonic); |
| 1174 | 1174 | |
| 1175 | 1175 | t.run_queue.prepend(&gc.closure.node); |
| 1176 | 1176 | |
| ... | ... | @@ -1187,7 +1187,7 @@ fn groupWait(userdata: ?*anyopaque, group: *Io.Group, token: *anyopaque) void { |
| 1187 | 1187 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| 1188 | 1188 | const gpa = t.allocator; |
| 1189 | 1189 | |
| 1190 | | if (builtin.single_threaded) return; |
| 1190 | if (builtin.single_threaded) unreachable; // we never set `group.token` to non-`null` |
| 1191 | 1191 | |
| 1192 | 1192 | const group_state: *std.atomic.Value(usize) = @ptrCast(&group.state); |
| 1193 | 1193 | const event: *Io.Event = @ptrCast(&group.context); |
| ... | ... | @@ -1212,13 +1212,18 @@ fn groupWait(userdata: ?*anyopaque, group: *Io.Group, token: *anyopaque) void { |
| 1212 | 1212 | gc.deinit(gpa); |
| 1213 | 1213 | node = node_next orelse break; |
| 1214 | 1214 | } |
| 1215 | |
| 1216 | // Since the group has now finished, it's illegal to add more tasks to it until we return. It's |
| 1217 | // also illegal for us to race with another `await` or `cancel`. Therefore, we must be the only |
| 1218 | // thread who can access `group` right now. |
| 1219 | group.token.raw = null; |
| 1215 | 1220 | } |
| 1216 | 1221 | |
| 1217 | 1222 | fn groupCancel(userdata: ?*anyopaque, group: *Io.Group, token: *anyopaque) void { |
| 1218 | 1223 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| 1219 | 1224 | const gpa = t.allocator; |
| 1220 | 1225 | |
| 1221 | | if (builtin.single_threaded) return; |
| 1226 | if (builtin.single_threaded) unreachable; // we never set `group.token` to non-`null` |
| 1222 | 1227 | |
| 1223 | 1228 | { |
| 1224 | 1229 | var node: *std.SinglyLinkedList.Node = @ptrCast(@alignCast(token)); |
| ... | ... | @@ -1244,6 +1249,11 @@ fn groupCancel(userdata: ?*anyopaque, group: *Io.Group, token: *anyopaque) void |
| 1244 | 1249 | node = node_next orelse break; |
| 1245 | 1250 | } |
| 1246 | 1251 | } |
| 1252 | |
| 1253 | // Since the group has now finished, it's illegal to add more tasks to it until we return. It's |
| 1254 | // also illegal for us to race with another `await` or `cancel`. Therefore, we must be the only |
| 1255 | // thread who can access `group` right now. |
| 1256 | group.token.raw = null; |
| 1247 | 1257 | } |
| 1248 | 1258 | |
| 1249 | 1259 | fn recancel(userdata: ?*anyopaque) void { |