authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-07-20 11:55:10+01:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-07-21 10:44:45+02:00
log37909d3170769ee361f4e62cb9558efe12630781
tree072b2464995b3b992c05586399f1db63497b3096
parent9485df42e938d5692c9066dee9152951a1aa1ad8

std.Progress: fix assertion failure when IPC slots are exhausted


1 files changed, 14 insertions(+), 2 deletions(-)

lib/std/Progress.zig+14-2
......@@ -442,7 +442,15 @@ pub const Node = struct {
442442 global_progress.ipc_files[slot] = file;
443443 storageByIndex(index).setIpcIndex(.{ .slot = slot, .generation = generation });
444444 break;
445 } else file.close(io);
445 } else {
446 // There was no IPC slot available, so we'll drop this node's IPC info and just close
447 // the fd. To avoid an old `estimated_total_items` or `completed_count` value still
448 // being rendered for the node, we'll zero that field out (and the user is not allowed
449 // to change it because they think we're doing IPC).
450 file.close(io);
451 @atomicStore(u32, &storageByIndex(index).completed_count, 0, .monotonic);
452 @atomicStore(u32, &storageByIndex(index).estimated_total_count, 0, .monotonic);
453 }
446454 }
447455
448456 pub fn setIpcIndex(node: Node, ipc_index: Ipc.Index) void {
......@@ -452,7 +460,11 @@ pub const Node = struct {
452460 /// Not thread-safe.
453461 pub fn takeIpcIndex(node: Node) ?Ipc.Index {
454462 const storage = storageByIndex(node.index.unwrap() orelse return null);
455 assert(storage.estimated_total_count == std.math.maxInt(u32));
463 switch (storage.estimated_total_count) {
464 std.math.maxInt(u32) => {}, // indicates that there is an IPC index in `completed_count`
465 0 => return null, // `setIpcFile` failed so we don't have an IPC index for this node
466 else => unreachable, // not an IPC node
467 }
456468 @atomicStore(u32, &storage.estimated_total_count, 0, .monotonic);
457469 return @bitCast(storage.completed_count);
458470 }