commit cd963ba38d77622b2971e7ea0bdc916ec5685630 (tree)
parent 28b83e3b0274a52b1d02a4117edd9fc6636917de
Author: Matthew Lugg <mlugg@mlugg.co.uk>
Date: Wed, 7 Jan 2026 00:29:36 +0000
Io.Threaded: fix bad assertion
Resolves: https://codeberg.org/ziglang/zig/issues/30717
Diffstat:
1 file changed, 12 insertions(+), 9 deletions(-)
diff --git a/lib/std/Io/Threaded.zig b/lib/std/Io/Threaded.zig
@@ -2109,25 +2109,28 @@ fn await(
.tag = .pending_canceled,
.thread = .null,
}, .acq_rel); // acquire results if complete; release `future.awaiter`
- switch (pre_cancel_status.tag) {
+ const done_status = switch (pre_cancel_status.tag) {
.pending => unreachable, // invalid state: we already awaited
- .pending_awaited => {
+ .pending_awaited => done_status: {
const working_thread = pre_cancel_status.thread.unpack();
future.waitForCancelWithSignaling(t, &num_completed, @alignCast(working_thread));
+ break :done_status future.status.load(.monotonic);
},
.pending_canceled => unreachable, // `await` raced with `cancel`
- .done => {
+ .done => done_status: {
// The task just finished, but we still need to wait for the signal, because the
// task thread already figured out that they need to update `future.awaiter`.
future.waitForCancelWithSignaling(t, &num_completed, null);
+ // Also, we have clobbered `future.status.tag` to `.pending_canceled`, but that's
+ // not actually a problem for the logic below.
+ break :done_status pre_cancel_status;
},
- }
+ };
// If the future did not acknowledge the cancelation, we need to mark it outstanding
- // for us. Because `future.status.tag == .done`, the information about whether there
- // was an acknowledged cancelation is encoded in `future.status.thread`.
- const final_status = future.status.load(.monotonic);
- assert(final_status.tag == .done);
- switch (final_status.thread) {
+ // for us. Because `done_status.tag == .done`, the information about whether there
+ // was an acknowledged cancelation is encoded in `done_status.thread`.
+ assert(done_status.tag == .done);
+ switch (done_status.thread) {
.null => recancelInner(), // cancelation was not acknowledged, so it's ours
.all_ones => {}, // cancelation was acknowledged, so it was this task's job to propagate it
_ => unreachable,