| ... | @@ -13,16 +13,18 @@ const assert = std.debug.assert; | ... | @@ -13,16 +13,18 @@ const assert = std.debug.assert; |
| 13 | const posix = std.posix; | 13 | const posix = std.posix; |
| 14 | const Writer = std.Io.Writer; | 14 | const Writer = std.Io.Writer; |
| 15 | | 15 | |
| 16 | /// `null` if the current node (and its children) should | 16 | /// Currently this API only supports this value being set to stderr, which |
| 17 | /// not print on update() | 17 | /// happens automatically inside `start`. |
| 18 | terminal: Io.File, | 18 | terminal: Io.File, |
| 19 | | 19 | |
| | 20 | io: Io, |
| | 21 | |
| 20 | terminal_mode: TerminalMode, | 22 | terminal_mode: TerminalMode, |
| 21 | | 23 | |
| 22 | update_thread: ?std.Thread, | 24 | update_worker: ?Io.Future(void), |
| 23 | | 25 | |
| 24 | /// Atomically set by SIGWINCH as well as the root done() function. | 26 | /// Atomically set by SIGWINCH as well as the root done() function. |
| 25 | redraw_event: std.Thread.ResetEvent, | 27 | redraw_event: Io.ResetEvent, |
| 26 | /// Indicates a request to shut down and reset global state. | 28 | /// Indicates a request to shut down and reset global state. |
| 27 | /// Accessed atomically. | 29 | /// Accessed atomically. |
| 28 | done: bool, | 30 | done: bool, |
| ... | @@ -95,9 +97,9 @@ pub const Options = struct { | ... | @@ -95,9 +97,9 @@ pub const Options = struct { |
| 95 | /// Must be at least 200 bytes. | 97 | /// Must be at least 200 bytes. |
| 96 | draw_buffer: []u8 = &default_draw_buffer, | 98 | draw_buffer: []u8 = &default_draw_buffer, |
| 97 | /// How many nanoseconds between writing updates to the terminal. | 99 | /// How many nanoseconds between writing updates to the terminal. |
| 98 | refresh_rate_ns: u64 = 80 * std.time.ns_per_ms, | 100 | refresh_rate_ns: Io.Duration = .fromMilliseconds(80), |
| 99 | /// How many nanoseconds to keep the output hidden | 101 | /// How many nanoseconds to keep the output hidden |
| 100 | initial_delay_ns: u64 = 200 * std.time.ns_per_ms, | 102 | initial_delay_ns: Io.Duration = .fromMilliseconds(200), |
| 101 | /// If provided, causes the progress item to have a denominator. | 103 | /// If provided, causes the progress item to have a denominator. |
| 102 | /// 0 means unknown. | 104 | /// 0 means unknown. |
| 103 | estimated_total_items: usize = 0, | 105 | estimated_total_items: usize = 0, |
| ... | @@ -330,7 +332,7 @@ pub const Node = struct { | ... | @@ -330,7 +332,7 @@ pub const Node = struct { |
| 330 | } else { | 332 | } else { |
| 331 | @atomicStore(bool, &global_progress.done, true, .monotonic); | 333 | @atomicStore(bool, &global_progress.done, true, .monotonic); |
| 332 | global_progress.redraw_event.set(); | 334 | global_progress.redraw_event.set(); |
| 333 | if (global_progress.update_thread) |thread| thread.join(); | 335 | if (global_progress.update_worker) |worker| worker.await(global_progress.io); |
| 334 | } | 336 | } |
| 335 | } | 337 | } |
| 336 | | 338 | |
| ... | @@ -391,9 +393,10 @@ pub const Node = struct { | ... | @@ -391,9 +393,10 @@ pub const Node = struct { |
| 391 | }; | 393 | }; |
| 392 | | 394 | |
| 393 | var global_progress: Progress = .{ | 395 | var global_progress: Progress = .{ |
| | 396 | .io = undefined, |
| 394 | .terminal = undefined, | 397 | .terminal = undefined, |
| 395 | .terminal_mode = .off, | 398 | .terminal_mode = .off, |
| 396 | .update_thread = null, | 399 | .update_worker = null, |
| 397 | .redraw_event = .unset, | 400 | .redraw_event = .unset, |
| 398 | .refresh_rate_ns = undefined, | 401 | .refresh_rate_ns = undefined, |
| 399 | .initial_delay_ns = undefined, | 402 | .initial_delay_ns = undefined, |
| ... | @@ -403,6 +406,7 @@ var global_progress: Progress = .{ | ... | @@ -403,6 +406,7 @@ var global_progress: Progress = .{ |
| 403 | .done = false, | 406 | .done = false, |
| 404 | .need_clear = false, | 407 | .need_clear = false, |
| 405 | .status = .working, | 408 | .status = .working, |
| | 409 | .start_failure = .unstarted, |
| 406 | | 410 | |
| 407 | .node_parents = &node_parents_buffer, | 411 | .node_parents = &node_parents_buffer, |
| 408 | .node_storage = &node_storage_buffer, | 412 | .node_storage = &node_storage_buffer, |
| ... | @@ -411,6 +415,13 @@ var global_progress: Progress = .{ | ... | @@ -411,6 +415,13 @@ var global_progress: Progress = .{ |
| 411 | .node_end_index = 0, | 415 | .node_end_index = 0, |
| 412 | }; | 416 | }; |
| 413 | | 417 | |
| | 418 | pub const StartFailure = union(enum) { |
| | 419 | unstarted, |
| | 420 | spawn_ipc_worker: error{ConcurrencyUnavailable}, |
| | 421 | spawn_update_worker: error{ConcurrencyUnavailable}, |
| | 422 | parse_env_var: error{}, |
| | 423 | }; |
| | 424 | |
| 414 | const node_storage_buffer_len = 83; | 425 | const node_storage_buffer_len = 83; |
| 415 | var node_parents_buffer: [node_storage_buffer_len]Node.Parent = undefined; | 426 | var node_parents_buffer: [node_storage_buffer_len]Node.Parent = undefined; |
| 416 | var node_storage_buffer: [node_storage_buffer_len]Node.Storage = undefined; | 427 | var node_storage_buffer: [node_storage_buffer_len]Node.Storage = undefined; |
| ... | @@ -437,7 +448,7 @@ const noop_impl = builtin.single_threaded or switch (builtin.os.tag) { | ... | @@ -437,7 +448,7 @@ const noop_impl = builtin.single_threaded or switch (builtin.os.tag) { |
| 437 | /// Asserts there is only one global Progress instance. | 448 | /// Asserts there is only one global Progress instance. |
| 438 | /// | 449 | /// |
| 439 | /// Call `Node.end` when done. | 450 | /// Call `Node.end` when done. |
| 440 | pub fn start(options: Options) Node { | 451 | pub fn start(options: Options, io: Io) Node { |
| 441 | // Ensure there is only 1 global Progress object. | 452 | // Ensure there is only 1 global Progress object. |
| 442 | if (global_progress.node_end_index != 0) { | 453 | if (global_progress.node_end_index != 0) { |
| 443 | debug_start_trace.dump(); | 454 | debug_start_trace.dump(); |
| ... | @@ -458,10 +469,10 @@ pub fn start(options: Options) Node { | ... | @@ -458,10 +469,10 @@ pub fn start(options: Options) Node { |
| 458 | if (noop_impl) | 469 | if (noop_impl) |
| 459 | return Node.none; | 470 | return Node.none; |
| 460 | | 471 | |
| 461 | const io = static_threaded_io.io(); | 472 | global_progress.io = io; |
| 462 | | 473 | |
| 463 | if (std.process.parseEnvVarInt("ZIG_PROGRESS", u31, 10)) |ipc_fd| { | 474 | if (std.process.parseEnvVarInt("ZIG_PROGRESS", u31, 10)) |ipc_fd| { |
| 464 | global_progress.update_thread = std.Thread.spawn(.{}, ipcThreadRun, .{ | 475 | global_progress.update_worker = io.concurrent(ipcThreadRun, .{ |
| 465 | io, | 476 | io, |
| 466 | @as(Io.File, .{ .handle = switch (@typeInfo(posix.fd_t)) { | 477 | @as(Io.File, .{ .handle = switch (@typeInfo(posix.fd_t)) { |
| 467 | .int => ipc_fd, | 478 | .int => ipc_fd, |
| ... | @@ -469,7 +480,7 @@ pub fn start(options: Options) Node { | ... | @@ -469,7 +480,7 @@ pub fn start(options: Options) Node { |
| 469 | else => @compileError("unsupported fd_t of " ++ @typeName(posix.fd_t)), | 480 | else => @compileError("unsupported fd_t of " ++ @typeName(posix.fd_t)), |
| 470 | } }), | 481 | } }), |
| 471 | }) catch |err| { | 482 | }) catch |err| { |
| 472 | std.log.warn("failed to spawn IPC thread for communicating progress to parent: {s}", .{@errorName(err)}); | 483 | global_progress.start_failure = .{ .spawn_ipc_worker = err }; |
| 473 | return Node.none; | 484 | return Node.none; |
| 474 | }; | 485 | }; |
| 475 | } else |env_err| switch (env_err) { | 486 | } else |env_err| switch (env_err) { |
| ... | @@ -502,17 +513,17 @@ pub fn start(options: Options) Node { | ... | @@ -502,17 +513,17 @@ pub fn start(options: Options) Node { |
| 502 | | 513 | |
| 503 | if (switch (global_progress.terminal_mode) { | 514 | if (switch (global_progress.terminal_mode) { |
| 504 | .off => unreachable, // handled a few lines above | 515 | .off => unreachable, // handled a few lines above |
| 505 | .ansi_escape_codes => std.Thread.spawn(.{}, updateThreadRun, .{io}), | 516 | .ansi_escape_codes => io.concurrent(updateThreadRun, .{io}), |
| 506 | .windows_api => if (is_windows) std.Thread.spawn(.{}, windowsApiUpdateThreadRun, .{io}) else unreachable, | 517 | .windows_api => if (is_windows) io.concurrent(windowsApiUpdateThreadRun, .{io}) else unreachable, |
| 507 | }) |thread| { | 518 | }) |future| { |
| 508 | global_progress.update_thread = thread; | 519 | global_progress.update_worker = future; |
| 509 | } else |err| { | 520 | } else |err| { |
| 510 | std.log.warn("unable to spawn thread for printing progress to terminal: {s}", .{@errorName(err)}); | 521 | global_progress.start_failure = .{ .spawn_update_worker = err }; |
| 511 | return Node.none; | 522 | return Node.none; |
| 512 | } | 523 | } |
| 513 | }, | 524 | }, |
| 514 | else => |e| { | 525 | else => |e| { |
| 515 | std.log.warn("invalid ZIG_PROGRESS file descriptor integer: {s}", .{@errorName(e)}); | 526 | global_progress.start_failure = .{ .parse_env_var = e }; |
| 516 | return Node.none; | 527 | return Node.none; |
| 517 | }, | 528 | }, |
| 518 | } | 529 | } |
| ... | @@ -545,10 +556,10 @@ fn updateThreadRun(io: Io) void { | ... | @@ -545,10 +556,10 @@ fn updateThreadRun(io: Io) void { |
| 545 | maybeUpdateSize(resize_flag); | 556 | maybeUpdateSize(resize_flag); |
| 546 | | 557 | |
| 547 | const buffer, _ = computeRedraw(&serialized_buffer); | 558 | const buffer, _ = computeRedraw(&serialized_buffer); |
| 548 | if (stderr_mutex.tryLock()) { | 559 | if (io.tryLockStderrWriter(&.{})) |w| { |
| 549 | defer stderr_mutex.unlock(); | 560 | defer io.unlockStderrWriter(); |
| 550 | write(io, buffer) catch return; | | |
| 551 | global_progress.need_clear = true; | 561 | global_progress.need_clear = true; |
| | 562 | w.writeAll(buffer) catch return; |
| 552 | } | 563 | } |
| 553 | } | 564 | } |
| 554 | | 565 | |
| ... | @@ -556,18 +567,18 @@ fn updateThreadRun(io: Io) void { | ... | @@ -556,18 +567,18 @@ fn updateThreadRun(io: Io) void { |
| 556 | const resize_flag = wait(global_progress.refresh_rate_ns); | 567 | const resize_flag = wait(global_progress.refresh_rate_ns); |
| 557 | | 568 | |
| 558 | if (@atomicLoad(bool, &global_progress.done, .monotonic)) { | 569 | if (@atomicLoad(bool, &global_progress.done, .monotonic)) { |
| 559 | stderr_mutex.lock(); | 570 | const w = io.lockStderrWriter(&.{}) catch return; |
| 560 | defer stderr_mutex.unlock(); | 571 | defer io.unlockStderrWriter(); |
| 561 | return clearWrittenWithEscapeCodes(io) catch {}; | 572 | return clearWrittenWithEscapeCodes(w) catch {}; |
| 562 | } | 573 | } |
| 563 | | 574 | |
| 564 | maybeUpdateSize(resize_flag); | 575 | maybeUpdateSize(resize_flag); |
| 565 | | 576 | |
| 566 | const buffer, _ = computeRedraw(&serialized_buffer); | 577 | const buffer, _ = computeRedraw(&serialized_buffer); |
| 567 | if (stderr_mutex.tryLock()) { | 578 | if (io.tryLockStderrWriter(&.{})) |w| { |
| 568 | defer stderr_mutex.unlock(); | 579 | defer io.unlockStderrWriter(); |
| 569 | write(io, buffer) catch return; | | |
| 570 | global_progress.need_clear = true; | 580 | global_progress.need_clear = true; |
| | 581 | w.writeAll(buffer) catch return; |
| 571 | } | 582 | } |
| 572 | } | 583 | } |
| 573 | } | 584 | } |
| ... | @@ -589,11 +600,11 @@ fn windowsApiUpdateThreadRun(io: Io) void { | ... | @@ -589,11 +600,11 @@ fn windowsApiUpdateThreadRun(io: Io) void { |
| 589 | maybeUpdateSize(resize_flag); | 600 | maybeUpdateSize(resize_flag); |
| 590 | | 601 | |
| 591 | const buffer, const nl_n = computeRedraw(&serialized_buffer); | 602 | const buffer, const nl_n = computeRedraw(&serialized_buffer); |
| 592 | if (stderr_mutex.tryLock()) { | 603 | if (io.tryLockStderrWriter()) |w| { |
| 593 | defer stderr_mutex.unlock(); | 604 | defer io.unlockStderrWriter(); |
| 594 | windowsApiWriteMarker(); | 605 | windowsApiWriteMarker(); |
| 595 | write(io, buffer) catch return; | | |
| 596 | global_progress.need_clear = true; | 606 | global_progress.need_clear = true; |
| | 607 | w.writeAll(buffer) catch return; |
| 597 | windowsApiMoveToMarker(nl_n) catch return; | 608 | windowsApiMoveToMarker(nl_n) catch return; |
| 598 | } | 609 | } |
| 599 | } | 610 | } |
| ... | @@ -602,74 +613,25 @@ fn windowsApiUpdateThreadRun(io: Io) void { | ... | @@ -602,74 +613,25 @@ fn windowsApiUpdateThreadRun(io: Io) void { |
| 602 | const resize_flag = wait(global_progress.refresh_rate_ns); | 613 | const resize_flag = wait(global_progress.refresh_rate_ns); |
| 603 | | 614 | |
| 604 | if (@atomicLoad(bool, &global_progress.done, .monotonic)) { | 615 | if (@atomicLoad(bool, &global_progress.done, .monotonic)) { |
| 605 | stderr_mutex.lock(); | 616 | _ = io.lockStderrWriter() catch return; |
| 606 | defer stderr_mutex.unlock(); | 617 | defer io.unlockStderrWriter(); |
| 607 | return clearWrittenWindowsApi() catch {}; | 618 | return clearWrittenWindowsApi() catch {}; |
| 608 | } | 619 | } |
| 609 | | 620 | |
| 610 | maybeUpdateSize(resize_flag); | 621 | maybeUpdateSize(resize_flag); |
| 611 | | 622 | |
| 612 | const buffer, const nl_n = computeRedraw(&serialized_buffer); | 623 | const buffer, const nl_n = computeRedraw(&serialized_buffer); |
| 613 | if (stderr_mutex.tryLock()) { | 624 | if (io.tryLockStderrWriter()) |w| { |
| 614 | defer stderr_mutex.unlock(); | 625 | defer io.unlockStderrWriter(); |
| 615 | clearWrittenWindowsApi() catch return; | 626 | clearWrittenWindowsApi() catch return; |
| 616 | windowsApiWriteMarker(); | 627 | windowsApiWriteMarker(); |
| 617 | write(io, buffer) catch return; | | |
| 618 | global_progress.need_clear = true; | 628 | global_progress.need_clear = true; |
| | 629 | w.writeAll(buffer) catch return; |
| 619 | windowsApiMoveToMarker(nl_n) catch return; | 630 | windowsApiMoveToMarker(nl_n) catch return; |
| 620 | } | 631 | } |
| 621 | } | 632 | } |
| 622 | } | 633 | } |
| 623 | | 634 | |
| 624 | /// Allows the caller to freely write to stderr until `unlockStdErr` is called. | | |
| 625 | /// | | |
| 626 | /// During the lock, any `std.Progress` information is cleared from the terminal. | | |
| 627 | /// | | |
| 628 | /// The lock is recursive; the same thread may hold the lock multiple times. | | |
| 629 | pub fn lockStdErr() void { | | |
| 630 | const io = stderr_file_writer.io; | | |
| 631 | stderr_mutex.lock(); | | |
| 632 | clearWrittenWithEscapeCodes(io) catch {}; | | |
| 633 | } | | |
| 634 | | | |
| 635 | pub fn unlockStdErr() void { | | |
| 636 | stderr_mutex.unlock(); | | |
| 637 | } | | |
| 638 | | | |
| 639 | /// Protected by `stderr_mutex`. | | |
| 640 | const stderr_writer: *Writer = &stderr_file_writer.interface; | | |
| 641 | /// Protected by `stderr_mutex`. | | |
| 642 | var stderr_file_writer: Io.File.Writer = .{ | | |
| 643 | .io = static_threaded_io.io(), | | |
| 644 | .interface = Io.File.Writer.initInterface(&.{}), | | |
| 645 | .file = if (is_windows) undefined else .stderr(), | | |
| 646 | .mode = .streaming, | | |
| 647 | }; | | |
| 648 | var static_threaded_io: Io.Threaded = .init_single_threaded; | | |
| 649 | | | |
| 650 | /// Allows the caller to freely write to the returned `Writer`, | | |
| 651 | /// initialized with `buffer`, until `unlockStderrWriter` is called. | | |
| 652 | /// | | |
| 653 | /// During the lock, any `std.Progress` information is cleared from the terminal. | | |
| 654 | /// | | |
| 655 | /// The lock is recursive; the same thread may hold the lock multiple times. | | |
| 656 | pub fn lockStderrWriter(buffer: []u8) *Io.Writer { | | |
| 657 | const io = stderr_file_writer.io; | | |
| 658 | stderr_mutex.lock(); | | |
| 659 | clearWrittenWithEscapeCodes(io) catch {}; | | |
| 660 | if (is_windows) stderr_file_writer.file = .stderr(); | | |
| 661 | stderr_writer.flush() catch {}; | | |
| 662 | stderr_writer.buffer = buffer; | | |
| 663 | return stderr_writer; | | |
| 664 | } | | |
| 665 | | | |
| 666 | pub fn unlockStderrWriter() void { | | |
| 667 | stderr_writer.flush() catch {}; | | |
| 668 | stderr_writer.end = 0; | | |
| 669 | stderr_writer.buffer = &.{}; | | |
| 670 | stderr_mutex.unlock(); | | |
| 671 | } | | |
| 672 | | | |
| 673 | fn ipcThreadRun(io: Io, file: Io.File) anyerror!void { | 635 | fn ipcThreadRun(io: Io, file: Io.File) anyerror!void { |
| 674 | // Store this data in the thread so that it does not need to be part of the | 636 | // Store this data in the thread so that it does not need to be part of the |
| 675 | // linker data of the main executable. | 637 | // linker data of the main executable. |
| ... | @@ -793,11 +755,11 @@ fn appendTreeSymbol(symbol: TreeSymbol, buf: []u8, start_i: usize) usize { | ... | @@ -793,11 +755,11 @@ fn appendTreeSymbol(symbol: TreeSymbol, buf: []u8, start_i: usize) usize { |
| 793 | } | 755 | } |
| 794 | } | 756 | } |
| 795 | | 757 | |
| 796 | fn clearWrittenWithEscapeCodes(io: Io) anyerror!void { | 758 | fn clearWrittenWithEscapeCodes(w: *Io.Writer) anyerror!void { |
| 797 | if (noop_impl or !global_progress.need_clear) return; | 759 | if (noop_impl or !global_progress.need_clear) return; |
| 798 | | 760 | |
| | 761 | try w.writeAll(clear ++ progress_remove); |
| 799 | global_progress.need_clear = false; | 762 | global_progress.need_clear = false; |
| 800 | try write(io, clear ++ progress_remove); | | |
| 801 | } | 763 | } |
| 802 | | 764 | |
| 803 | /// U+25BA or ► | 765 | /// U+25BA or ► |
| ... | @@ -997,7 +959,7 @@ fn serializeIpc(start_serialized_len: usize, serialized_buffer: *Serialized.Buff | ... | @@ -997,7 +959,7 @@ fn serializeIpc(start_serialized_len: usize, serialized_buffer: *Serialized.Buff |
| 997 | const n = posix.read(fd, pipe_buf[bytes_read..]) catch |err| switch (err) { | 959 | const n = posix.read(fd, pipe_buf[bytes_read..]) catch |err| switch (err) { |
| 998 | error.WouldBlock => break, | 960 | error.WouldBlock => break, |
| 999 | else => |e| { | 961 | else => |e| { |
| 1000 | std.log.debug("failed to read child progress data: {s}", .{@errorName(e)}); | 962 | std.log.debug("failed to read child progress data: {t}", .{e}); |
| 1001 | main_storage.completed_count = 0; | 963 | main_storage.completed_count = 0; |
| 1002 | main_storage.estimated_total_count = 0; | 964 | main_storage.estimated_total_count = 0; |
| 1003 | continue :main_loop; | 965 | continue :main_loop; |
| ... | @@ -1424,10 +1386,6 @@ fn withinRowLimit(p: *Progress, nl_n: usize) bool { | ... | @@ -1424,10 +1386,6 @@ fn withinRowLimit(p: *Progress, nl_n: usize) bool { |
| 1424 | return nl_n + 2 < p.rows; | 1386 | return nl_n + 2 < p.rows; |
| 1425 | } | 1387 | } |
| 1426 | | 1388 | |
| 1427 | fn write(io: Io, buf: []const u8) anyerror!void { | | |
| 1428 | try global_progress.terminal.writeStreamingAll(io, buf); | | |
| 1429 | } | | |
| 1430 | | | |
| 1431 | var remaining_write_trash_bytes: usize = 0; | 1389 | var remaining_write_trash_bytes: usize = 0; |
| 1432 | | 1390 | |
| 1433 | fn writeIpc(io: Io, file: Io.File, serialized: Serialized) error{BrokenPipe}!void { | 1391 | fn writeIpc(io: Io, file: Io.File, serialized: Serialized) error{BrokenPipe}!void { |
| ... | @@ -1459,7 +1417,7 @@ fn writeIpc(io: Io, file: Io.File, serialized: Serialized) error{BrokenPipe}!voi | ... | @@ -1459,7 +1417,7 @@ fn writeIpc(io: Io, file: Io.File, serialized: Serialized) error{BrokenPipe}!voi |
| 1459 | error.WouldBlock => return, | 1417 | error.WouldBlock => return, |
| 1460 | error.BrokenPipe => return error.BrokenPipe, | 1418 | error.BrokenPipe => return error.BrokenPipe, |
| 1461 | else => |e| { | 1419 | else => |e| { |
| 1462 | std.log.debug("failed to send progress to parent process: {s}", .{@errorName(e)}); | 1420 | std.log.debug("failed to send progress to parent process: {t}", .{e}); |
| 1463 | return error.BrokenPipe; | 1421 | return error.BrokenPipe; |
| 1464 | }, | 1422 | }, |
| 1465 | } | 1423 | } |
| ... | @@ -1476,7 +1434,7 @@ fn writeIpc(io: Io, file: Io.File, serialized: Serialized) error{BrokenPipe}!voi | ... | @@ -1476,7 +1434,7 @@ fn writeIpc(io: Io, file: Io.File, serialized: Serialized) error{BrokenPipe}!voi |
| 1476 | error.WouldBlock => {}, | 1434 | error.WouldBlock => {}, |
| 1477 | error.BrokenPipe => return error.BrokenPipe, | 1435 | error.BrokenPipe => return error.BrokenPipe, |
| 1478 | else => |e| { | 1436 | else => |e| { |
| 1479 | std.log.debug("failed to send progress to parent process: {s}", .{@errorName(e)}); | 1437 | std.log.debug("failed to send progress to parent process: {t}", .{e}); |
| 1480 | return error.BrokenPipe; | 1438 | return error.BrokenPipe; |
| 1481 | }, | 1439 | }, |
| 1482 | } | 1440 | } |
| ... | @@ -1568,11 +1526,6 @@ const have_sigwinch = switch (builtin.os.tag) { | ... | @@ -1568,11 +1526,6 @@ const have_sigwinch = switch (builtin.os.tag) { |
| 1568 | else => false, | 1526 | else => false, |
| 1569 | }; | 1527 | }; |
| 1570 | | 1528 | |
| 1571 | /// The primary motivation for recursive mutex here is so that a panic while | | |
| 1572 | /// stderr mutex is held still dumps the stack trace and other debug | | |
| 1573 | /// information. | | |
| 1574 | var stderr_mutex = std.Thread.Mutex.Recursive.init; | | |
| 1575 | | | |
| 1576 | fn copyAtomicStore(dest: []align(@alignOf(usize)) u8, src: []const u8) void { | 1529 | fn copyAtomicStore(dest: []align(@alignOf(usize)) u8, src: []const u8) void { |
| 1577 | assert(dest.len == src.len); | 1530 | assert(dest.len == src.len); |
| 1578 | const chunked_len = dest.len / @sizeOf(usize); | 1531 | const chunked_len = dest.len / @sizeOf(usize); |