authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-01-07 00:29:36+00:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-01-07 11:27:21+01:00
logcd963ba38d77622b2971e7ea0bdc916ec5685630
tree51e53bc8affaf52ac024cc65bd0891fe340e30cf
parent28b83e3b0274a52b1d02a4117edd9fc6636917de

Io.Threaded: fix bad assertion

Resolves: https://codeberg.org/ziglang/zig/issues/30717

1 files changed, 12 insertions(+), 9 deletions(-)

lib/std/Io/Threaded.zig+12-9
...@@ -2109,25 +2109,28 @@ fn await(...@@ -2109,25 +2109,28 @@ fn await(
2109 .tag = .pending_canceled,2109 .tag = .pending_canceled,
2110 .thread = .null,2110 .thread = .null,
2111 }, .acq_rel); // acquire results if complete; release `future.awaiter`2111 }, .acq_rel); // acquire results if complete; release `future.awaiter`
2112 switch (pre_cancel_status.tag) {2112 const done_status = switch (pre_cancel_status.tag) {
2113 .pending => unreachable, // invalid state: we already awaited2113 .pending => unreachable, // invalid state: we already awaited
2114 .pending_awaited => {2114 .pending_awaited => done_status: {
2115 const working_thread = pre_cancel_status.thread.unpack();2115 const working_thread = pre_cancel_status.thread.unpack();
2116 future.waitForCancelWithSignaling(t, &num_completed, @alignCast(working_thread));2116 future.waitForCancelWithSignaling(t, &num_completed, @alignCast(working_thread));
2117 break :done_status future.status.load(.monotonic);
2117 },2118 },
2118 .pending_canceled => unreachable, // `await` raced with `cancel`2119 .pending_canceled => unreachable, // `await` raced with `cancel`
2119 .done => {2120 .done => done_status: {
2120 // The task just finished, but we still need to wait for the signal, because the2121 // The task just finished, but we still need to wait for the signal, because the
2121 // task thread already figured out that they need to update `future.awaiter`.2122 // task thread already figured out that they need to update `future.awaiter`.
2122 future.waitForCancelWithSignaling(t, &num_completed, null);2123 future.waitForCancelWithSignaling(t, &num_completed, null);
2124 // Also, we have clobbered `future.status.tag` to `.pending_canceled`, but that's
2125 // not actually a problem for the logic below.
2126 break :done_status pre_cancel_status;
2123 },2127 },
2124 }2128 };
2125 // If the future did not acknowledge the cancelation, we need to mark it outstanding2129 // If the future did not acknowledge the cancelation, we need to mark it outstanding
2126 // for us. Because `future.status.tag == .done`, the information about whether there2130 // for us. Because `done_status.tag == .done`, the information about whether there
2127 // was an acknowledged cancelation is encoded in `future.status.thread`.2131 // was an acknowledged cancelation is encoded in `done_status.thread`.
2128 const final_status = future.status.load(.monotonic);2132 assert(done_status.tag == .done);
2129 assert(final_status.tag == .done);2133 switch (done_status.thread) {
2130 switch (final_status.thread) {
2131 .null => recancelInner(), // cancelation was not acknowledged, so it's ours2134 .null => recancelInner(), // cancelation was not acknowledged, so it's ours
2132 .all_ones => {}, // cancelation was acknowledged, so it was this task's job to propagate it2135 .all_ones => {}, // cancelation was acknowledged, so it was this task's job to propagate it
2133 _ => unreachable,2136 _ => unreachable,