| ... | @@ -24,7 +24,7 @@ terminal_mode: TerminalMode, | ... | @@ -24,7 +24,7 @@ terminal_mode: TerminalMode, |
| 24 | update_worker: ?Io.Future(void), | 24 | update_worker: ?Io.Future(void), |
| 25 | | 25 | |
| 26 | /// Atomically set by SIGWINCH as well as the root done() function. | 26 | /// Atomically set by SIGWINCH as well as the root done() function. |
| 27 | redraw_event: Io.ResetEvent, | 27 | redraw_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. |
| 30 | done: bool, | 30 | done: 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 | } |
| 340 | | 341 | |
| ... | @@ -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 | }; |
| 426 | | 427 | |
| 427 | const node_storage_buffer_len = 83; | 428 | const 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. |
| 455 | pub fn start(options: Options, io: Io) Node { | 456 | pub 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 { |
| 467 | | 468 | |
| 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()); |
| 472 | | 473 | |
| 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 | } |
| 542 | | 543 | |
| 543 | /// Returns whether a resize is needed to learn the terminal size. | 544 | /// Returns whether a resize is needed to learn the terminal size. |
| 544 | fn wait(timeout_ns: u64) bool { | 545 | fn 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; |
| 556 | | 561 | |
| 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); |
| 561 | | 566 | |
| 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 | } |
| 569 | | 574 | |
| 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); |
| 572 | | 577 | |
| 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 | } |
| 578 | | 583 | |
| 579 | maybeUpdateSize(resize_flag); | 584 | maybeUpdateSize(resize_flag); |
| 580 | | 585 | |
| 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; |
| 600 | | 605 | |
| 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); |
| 605 | | 610 | |
| 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 | } |
| 615 | | 620 | |
| 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); |
| 618 | | 623 | |
| 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); |
| 626 | | 631 | |
| 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 | } |
| 638 | | 643 | |
| 639 | fn ipcThreadRun(io: Io, file: Io.File) anyerror!void { | 644 | fn ipcThreadRun(io: Io, file: Io.File) void { |
| 640 | // Store this data in the thread so that it does not need to be part of the | 645 | // 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; |
| 643 | | 648 | |
| 644 | { | 649 | { |
| 645 | _ = wait(global_progress.initial_delay_ns); | 650 | _ = wait(io, global_progress.initial_delay_ns); |
| 646 | | 651 | |
| 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 | } |
| 655 | | 660 | |
| 656 | while (true) { | 661 | while (true) { |
| 657 | _ = wait(global_progress.refresh_rate_ns); | 662 | _ = wait(io, global_progress.refresh_rate_ns); |
| 658 | | 663 | |
| 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 | } |
| 1509 | | 1514 | |
| 1510 | const have_sigwinch = switch (builtin.os.tag) { | 1515 | const have_sigwinch = switch (builtin.os.tag) { |