authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-12-10 18:14:43-08:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-12-23 22:15:09-08:00
log95b0399d1bf7e12aefeba79652141d202f805fe4
tree5867007c138fc954a9102ed8c3f42e6d087528bc
parent3a6e15449b887481a0ed24fc948157c222f0072a

std: finish implementing futexWait with timer


3 files changed, 39 insertions(+), 35 deletions(-)

lib/std/Io/Threaded.zig-1
...@@ -1147,7 +1147,6 @@ const GroupClosure = struct {...@@ -1147,7 +1147,6 @@ const GroupClosure = struct {
1147 const group = gc.group;1147 const group = gc.group;
1148 const group_state: *std.atomic.Value(usize) = @ptrCast(&group.state);1148 const group_state: *std.atomic.Value(usize) = @ptrCast(&group.state);
1149 const event: *Io.Event = @ptrCast(&group.context);1149 const event: *Io.Event = @ptrCast(&group.context);
1150
1151 current_thread.current_closure = closure;1150 current_thread.current_closure = closure;
1152 current_thread.cancel_protection = .unblocked;1151 current_thread.cancel_protection = .unblocked;
11531152
lib/std/Progress.zig+33-28
...@@ -24,7 +24,7 @@ terminal_mode: TerminalMode,...@@ -24,7 +24,7 @@ terminal_mode: TerminalMode,
24update_worker: ?Io.Future(void),24update_worker: ?Io.Future(void),
2525
26/// Atomically set by SIGWINCH as well as the root done() function.26/// Atomically set by SIGWINCH as well as the root done() function.
27redraw_event: Io.ResetEvent,27redraw_event: Io.Event,
28/// Indicates a request to shut down and reset global state.28/// Indicates a request to shut down and reset global state.
29/// Accessed atomically.29/// Accessed atomically.
30done: bool,30done: bool,
...@@ -333,8 +333,9 @@ pub const Node = struct {...@@ -333,8 +333,9 @@ pub const Node = struct {
333 }333 }
334 } else {334 } else {
335 @atomicStore(bool, &global_progress.done, true, .monotonic);335 @atomicStore(bool, &global_progress.done, true, .monotonic);
336 global_progress.redraw_event.set();336 const io = global_progress.io;
337 if (global_progress.update_worker) |worker| worker.await(global_progress.io);337 global_progress.redraw_event.set(io);
338 if (global_progress.update_worker) |*worker| worker.await(io);
338 }339 }
339 }340 }
340341
...@@ -421,7 +422,7 @@ pub const StartFailure = union(enum) {...@@ -421,7 +422,7 @@ pub const StartFailure = union(enum) {
421 unstarted,422 unstarted,
422 spawn_ipc_worker: error{ConcurrencyUnavailable},423 spawn_ipc_worker: error{ConcurrencyUnavailable},
423 spawn_update_worker: error{ConcurrencyUnavailable},424 spawn_update_worker: error{ConcurrencyUnavailable},
424 parse_env_var: error{},425 parse_env_var: error{ InvalidCharacter, Overflow },
425};426};
426427
427const node_storage_buffer_len = 83;428const node_storage_buffer_len = 83;
...@@ -452,7 +453,7 @@ const noop_impl = builtin.single_threaded or switch (builtin.os.tag) {...@@ -452,7 +453,7 @@ const noop_impl = builtin.single_threaded or switch (builtin.os.tag) {
452/// Call `Node.end` when done.453/// Call `Node.end` when done.
453///454///
454/// If an error occurs, `start_failure` will be populated.455/// If an error occurs, `start_failure` will be populated.
455pub fn start(options: Options, io: Io) Node {456pub fn start(io: Io, options: Options) Node {
456 // Ensure there is only 1 global Progress object.457 // Ensure there is only 1 global Progress object.
457 if (global_progress.node_end_index != 0) {458 if (global_progress.node_end_index != 0) {
458 debug_start_trace.dump();459 debug_start_trace.dump();
...@@ -467,8 +468,8 @@ pub fn start(options: Options, io: Io) Node {...@@ -467,8 +468,8 @@ pub fn start(options: Options, io: Io) Node {
467468
468 assert(options.draw_buffer.len >= 200);469 assert(options.draw_buffer.len >= 200);
469 global_progress.draw_buffer = options.draw_buffer;470 global_progress.draw_buffer = options.draw_buffer;
470 global_progress.refresh_rate_ns = options.refresh_rate_ns;471 global_progress.refresh_rate_ns = @intCast(options.refresh_rate_ns.toNanoseconds());
471 global_progress.initial_delay_ns = options.initial_delay_ns;472 global_progress.initial_delay_ns = @intCast(options.initial_delay_ns.toNanoseconds());
472473
473 if (noop_impl)474 if (noop_impl)
474 return Node.none;475 return Node.none;
...@@ -541,9 +542,13 @@ pub fn setStatus(new_status: Status) void {...@@ -541,9 +542,13 @@ pub fn setStatus(new_status: Status) void {
541}542}
542543
543/// Returns whether a resize is needed to learn the terminal size.544/// Returns whether a resize is needed to learn the terminal size.
544fn wait(timeout_ns: u64) bool {545fn wait(io: Io, timeout_ns: u64) bool {
545 const resize_flag = if (global_progress.redraw_event.timedWait(timeout_ns)) |_| true else |err| switch (err) {546 const timeout: Io.Timeout = .{ .duration = .{
546 error.Timeout => false,547 .clock = .awake,
548 .raw = .fromNanoseconds(timeout_ns),
549 } };
550 const resize_flag = if (global_progress.redraw_event.waitTimeout(io, timeout)) |_| true else |err| switch (err) {
551 error.Timeout, error.Canceled => false,
547 };552 };
548 global_progress.redraw_event.reset();553 global_progress.redraw_event.reset();
549 return resize_flag or (global_progress.cols == 0);554 return resize_flag or (global_progress.cols == 0);
...@@ -555,34 +560,34 @@ fn updateThreadRun(io: Io) void {...@@ -555,34 +560,34 @@ fn updateThreadRun(io: Io) void {
555 var serialized_buffer: Serialized.Buffer = undefined;560 var serialized_buffer: Serialized.Buffer = undefined;
556561
557 {562 {
558 const resize_flag = wait(global_progress.initial_delay_ns);563 const resize_flag = wait(io, global_progress.initial_delay_ns);
559 if (@atomicLoad(bool, &global_progress.done, .monotonic)) return;564 if (@atomicLoad(bool, &global_progress.done, .monotonic)) return;
560 maybeUpdateSize(resize_flag);565 maybeUpdateSize(resize_flag);
561566
562 const buffer, _ = computeRedraw(&serialized_buffer);567 const buffer, _ = computeRedraw(&serialized_buffer);
563 if (io.tryLockStderrWriter(&.{})) |w| {568 if (io.tryLockStderrWriter(&.{})) |fw| {
564 defer io.unlockStderrWriter();569 defer io.unlockStderrWriter();
565 global_progress.need_clear = true;570 global_progress.need_clear = true;
566 w.writeAll(buffer) catch return;571 fw.writeAllUnescaped(buffer) catch return;
567 }572 }
568 }573 }
569574
570 while (true) {575 while (true) {
571 const resize_flag = wait(global_progress.refresh_rate_ns);576 const resize_flag = wait(io, global_progress.refresh_rate_ns);
572577
573 if (@atomicLoad(bool, &global_progress.done, .monotonic)) {578 if (@atomicLoad(bool, &global_progress.done, .monotonic)) {
574 const w = io.lockStderrWriter(&.{}) catch return;579 const fw = io.lockStderrWriter(&.{}) catch return;
575 defer io.unlockStderrWriter();580 defer io.unlockStderrWriter();
576 return clearWrittenWithEscapeCodes(w) catch {};581 return clearWrittenWithEscapeCodes(fw) catch {};
577 }582 }
578583
579 maybeUpdateSize(resize_flag);584 maybeUpdateSize(resize_flag);
580585
581 const buffer, _ = computeRedraw(&serialized_buffer);586 const buffer, _ = computeRedraw(&serialized_buffer);
582 if (io.tryLockStderrWriter(&.{})) |w| {587 if (io.tryLockStderrWriter(&.{})) |fw| {
583 defer io.unlockStderrWriter();588 defer io.unlockStderrWriter();
584 global_progress.need_clear = true;589 global_progress.need_clear = true;
585 w.writeAll(buffer) catch return;590 fw.writeAllUnescaped(buffer) catch return;
586 }591 }
587 }592 }
588}593}
...@@ -599,22 +604,22 @@ fn windowsApiUpdateThreadRun(io: Io) void {...@@ -599,22 +604,22 @@ fn windowsApiUpdateThreadRun(io: Io) void {
599 var serialized_buffer: Serialized.Buffer = undefined;604 var serialized_buffer: Serialized.Buffer = undefined;
600605
601 {606 {
602 const resize_flag = wait(global_progress.initial_delay_ns);607 const resize_flag = wait(io, global_progress.initial_delay_ns);
603 if (@atomicLoad(bool, &global_progress.done, .monotonic)) return;608 if (@atomicLoad(bool, &global_progress.done, .monotonic)) return;
604 maybeUpdateSize(resize_flag);609 maybeUpdateSize(resize_flag);
605610
606 const buffer, const nl_n = computeRedraw(&serialized_buffer);611 const buffer, const nl_n = computeRedraw(&serialized_buffer);
607 if (io.tryLockStderrWriter()) |w| {612 if (io.tryLockStderrWriter()) |fw| {
608 defer io.unlockStderrWriter();613 defer io.unlockStderrWriter();
609 windowsApiWriteMarker();614 windowsApiWriteMarker();
610 global_progress.need_clear = true;615 global_progress.need_clear = true;
611 w.writeAll(buffer) catch return;616 fw.writeAllUnescaped(buffer) catch return;
612 windowsApiMoveToMarker(nl_n) catch return;617 windowsApiMoveToMarker(nl_n) catch return;
613 }618 }
614 }619 }
615620
616 while (true) {621 while (true) {
617 const resize_flag = wait(global_progress.refresh_rate_ns);622 const resize_flag = wait(io, global_progress.refresh_rate_ns);
618623
619 if (@atomicLoad(bool, &global_progress.done, .monotonic)) {624 if (@atomicLoad(bool, &global_progress.done, .monotonic)) {
620 _ = io.lockStderrWriter() catch return;625 _ = io.lockStderrWriter() catch return;
...@@ -625,24 +630,24 @@ fn windowsApiUpdateThreadRun(io: Io) void {...@@ -625,24 +630,24 @@ fn windowsApiUpdateThreadRun(io: Io) void {
625 maybeUpdateSize(resize_flag);630 maybeUpdateSize(resize_flag);
626631
627 const buffer, const nl_n = computeRedraw(&serialized_buffer);632 const buffer, const nl_n = computeRedraw(&serialized_buffer);
628 if (io.tryLockStderrWriter()) |w| {633 if (io.tryLockStderrWriter()) |fw| {
629 defer io.unlockStderrWriter();634 defer io.unlockStderrWriter();
630 clearWrittenWindowsApi() catch return;635 clearWrittenWindowsApi() catch return;
631 windowsApiWriteMarker();636 windowsApiWriteMarker();
632 global_progress.need_clear = true;637 global_progress.need_clear = true;
633 w.writeAll(buffer) catch return;638 fw.writeAllUnescaped(buffer) catch return;
634 windowsApiMoveToMarker(nl_n) catch return;639 windowsApiMoveToMarker(nl_n) catch return;
635 }640 }
636 }641 }
637}642}
638643
639fn ipcThreadRun(io: Io, file: Io.File) anyerror!void {644fn ipcThreadRun(io: Io, file: Io.File) void {
640 // Store this data in the thread so that it does not need to be part of the645 // Store this data in the thread so that it does not need to be part of the
641 // linker data of the main executable.646 // linker data of the main executable.
642 var serialized_buffer: Serialized.Buffer = undefined;647 var serialized_buffer: Serialized.Buffer = undefined;
643648
644 {649 {
645 _ = wait(global_progress.initial_delay_ns);650 _ = wait(io, global_progress.initial_delay_ns);
646651
647 if (@atomicLoad(bool, &global_progress.done, .monotonic))652 if (@atomicLoad(bool, &global_progress.done, .monotonic))
648 return;653 return;
...@@ -654,7 +659,7 @@ fn ipcThreadRun(io: Io, file: Io.File) anyerror!void {...@@ -654,7 +659,7 @@ fn ipcThreadRun(io: Io, file: Io.File) anyerror!void {
654 }659 }
655660
656 while (true) {661 while (true) {
657 _ = wait(global_progress.refresh_rate_ns);662 _ = wait(io, global_progress.refresh_rate_ns);
658663
659 if (@atomicLoad(bool, &global_progress.done, .monotonic))664 if (@atomicLoad(bool, &global_progress.done, .monotonic))
660 return;665 return;
...@@ -1504,7 +1509,7 @@ fn handleSigWinch(sig: posix.SIG, info: *const posix.siginfo_t, ctx_ptr: ?*anyop...@@ -1504,7 +1509,7 @@ fn handleSigWinch(sig: posix.SIG, info: *const posix.siginfo_t, ctx_ptr: ?*anyop
1504 _ = info;1509 _ = info;
1505 _ = ctx_ptr;1510 _ = ctx_ptr;
1506 assert(sig == .WINCH);1511 assert(sig == .WINCH);
1507 global_progress.redraw_event.set();1512 global_progress.redraw_event.set(global_progress.io);
1508}1513}
15091514
1510const have_sigwinch = switch (builtin.os.tag) {1515const have_sigwinch = switch (builtin.os.tag) {
lib/std/debug.zig+6-6
...@@ -816,9 +816,9 @@ pub fn writeStackTrace(st: *const StackTrace, writer: *Writer, fwm: File.Writer....@@ -816,9 +816,9 @@ pub fn writeStackTrace(st: *const StackTrace, writer: *Writer, fwm: File.Writer.
816}816}
817/// A thin wrapper around `writeStackTrace` which writes to stderr and ignores write errors.817/// A thin wrapper around `writeStackTrace` which writes to stderr and ignores write errors.
818pub fn dumpStackTrace(st: *const StackTrace) void {818pub fn dumpStackTrace(st: *const StackTrace) void {
819 const stderr, const tty_config = lockStderrWriter(&.{});819 const stderr = lockStderrWriter(&.{});
820 defer unlockStderrWriter();820 defer unlockStderrWriter();
821 writeStackTrace(st, stderr, tty_config) catch |err| switch (err) {821 writeStackTrace(st, &stderr.interface, stderr.mode) catch |err| switch (err) {
822 error.WriteFailed => {},822 error.WriteFailed => {},
823 };823 };
824}824}
...@@ -1682,21 +1682,21 @@ pub fn ConfigurableTrace(comptime size: usize, comptime stack_frame_count: usize...@@ -1682,21 +1682,21 @@ pub fn ConfigurableTrace(comptime size: usize, comptime stack_frame_count: usize
1682 pub fn dump(t: @This()) void {1682 pub fn dump(t: @This()) void {
1683 if (!enabled) return;1683 if (!enabled) return;
16841684
1685 const stderr, const tty_config = lockStderrWriter(&.{});1685 const stderr = lockStderrWriter(&.{});
1686 defer unlockStderrWriter();1686 defer unlockStderrWriter();
1687 const end = @min(t.index, size);1687 const end = @min(t.index, size);
1688 for (t.addrs[0..end], 0..) |frames_array, i| {1688 for (t.addrs[0..end], 0..) |frames_array, i| {
1689 stderr.print("{s}:\n", .{t.notes[i]}) catch return;1689 stderr.interface.print("{s}:\n", .{t.notes[i]}) catch return;
1690 var frames_array_mutable = frames_array;1690 var frames_array_mutable = frames_array;
1691 const frames = mem.sliceTo(frames_array_mutable[0..], 0);1691 const frames = mem.sliceTo(frames_array_mutable[0..], 0);
1692 const stack_trace: StackTrace = .{1692 const stack_trace: StackTrace = .{
1693 .index = frames.len,1693 .index = frames.len,
1694 .instruction_addresses = frames,1694 .instruction_addresses = frames,
1695 };1695 };
1696 writeStackTrace(&stack_trace, stderr, tty_config) catch return;1696 writeStackTrace(&stack_trace, &stderr.interface, stderr.mode) catch return;
1697 }1697 }
1698 if (t.index > end) {1698 if (t.index > end) {
1699 stderr.print("{d} more traces not shown; consider increasing trace size\n", .{1699 stderr.interface.print("{d} more traces not shown; consider increasing trace size\n", .{
1700 t.index - end,1700 t.index - end,
1701 }) catch return;1701 }) catch return;
1702 }1702 }