| author | |
| committer | |
| log | 963ffe9d572e6da4ef22672af9b7c54150f66b27 |
| tree | 950c39722d71cdd6f2af75c255ee92a318cda516 |
| parent | 759c2211c2eba44cccf0608267bf1a05934ad8a1 |
| parent | 3a3d2187f986066859cfb793fb7ee1cae4dfea08 |
| signature |
rework std.Progress62 files changed, 1758 insertions(+), 819 deletions(-)
lib/compiler/aro/aro/Diagnostics.zig+2-2| ... | @@ -528,7 +528,7 @@ const MsgWriter = struct { | ... | @@ -528,7 +528,7 @@ const MsgWriter = struct { |
| 528 | config: std.io.tty.Config, | 528 | config: std.io.tty.Config, |
| 529 | 529 | ||
| 530 | fn init(config: std.io.tty.Config) MsgWriter { | 530 | fn init(config: std.io.tty.Config) MsgWriter { |
| 531 | std.debug.getStderrMutex().lock(); | 531 | std.debug.lockStdErr(); |
| 532 | return .{ | 532 | return .{ |
| 533 | .w = std.io.bufferedWriter(std.io.getStdErr().writer()), | 533 | .w = std.io.bufferedWriter(std.io.getStdErr().writer()), |
| 534 | .config = config, | 534 | .config = config, |
| ... | @@ -537,7 +537,7 @@ const MsgWriter = struct { | ... | @@ -537,7 +537,7 @@ const MsgWriter = struct { |
| 537 | 537 | ||
| 538 | pub fn deinit(m: *MsgWriter) void { | 538 | pub fn deinit(m: *MsgWriter) void { |
| 539 | m.w.flush() catch {}; | 539 | m.w.flush() catch {}; |
| 540 | std.debug.getStderrMutex().unlock(); | 540 | std.debug.unlockStdErr(); |
| 541 | } | 541 | } |
| 542 | 542 | ||
| 543 | pub fn print(m: *MsgWriter, comptime fmt: []const u8, args: anytype) void { | 543 | pub fn print(m: *MsgWriter, comptime fmt: []const u8, args: anytype) void { |
lib/compiler/build_runner.zig+13-13| ... | @@ -289,13 +289,14 @@ pub fn main() !void { | ... | @@ -289,13 +289,14 @@ pub fn main() !void { |
| 289 | .windows_api => {}, | 289 | .windows_api => {}, |
| 290 | } | 290 | } |
| 291 | 291 | ||
| 292 | var progress: std.Progress = .{ .dont_print_on_dumb = true }; | 292 | const main_progress_node = std.Progress.start(.{ |
| 293 | const main_progress_node = progress.start("", 0); | 293 | .disable_printing = (color == .off), |
| 294 | }); | ||
| 294 | 295 | ||
| 295 | builder.debug_log_scopes = debug_log_scopes.items; | 296 | builder.debug_log_scopes = debug_log_scopes.items; |
| 296 | builder.resolveInstallPrefix(install_prefix, dir_list); | 297 | builder.resolveInstallPrefix(install_prefix, dir_list); |
| 297 | { | 298 | { |
| 298 | var prog_node = main_progress_node.start("user build.zig logic", 0); | 299 | var prog_node = main_progress_node.start("Configure", 0); |
| 299 | defer prog_node.end(); | 300 | defer prog_node.end(); |
| 300 | try builder.runBuild(root); | 301 | try builder.runBuild(root); |
| 301 | } | 302 | } |
| ... | @@ -385,7 +386,7 @@ fn runStepNames( | ... | @@ -385,7 +386,7 @@ fn runStepNames( |
| 385 | arena: std.mem.Allocator, | 386 | arena: std.mem.Allocator, |
| 386 | b: *std.Build, | 387 | b: *std.Build, |
| 387 | step_names: []const []const u8, | 388 | step_names: []const []const u8, |
| 388 | parent_prog_node: *std.Progress.Node, | 389 | parent_prog_node: std.Progress.Node, |
| 389 | thread_pool_options: std.Thread.Pool.Options, | 390 | thread_pool_options: std.Thread.Pool.Options, |
| 390 | run: *Run, | 391 | run: *Run, |
| 391 | seed: u32, | 392 | seed: u32, |
| ... | @@ -452,7 +453,7 @@ fn runStepNames( | ... | @@ -452,7 +453,7 @@ fn runStepNames( |
| 452 | { | 453 | { |
| 453 | defer parent_prog_node.end(); | 454 | defer parent_prog_node.end(); |
| 454 | 455 | ||
| 455 | var step_prog = parent_prog_node.start("steps", step_stack.count()); | 456 | const step_prog = parent_prog_node.start("steps", step_stack.count()); |
| 456 | defer step_prog.end(); | 457 | defer step_prog.end(); |
| 457 | 458 | ||
| 458 | var wait_group: std.Thread.WaitGroup = .{}; | 459 | var wait_group: std.Thread.WaitGroup = .{}; |
| ... | @@ -467,7 +468,7 @@ fn runStepNames( | ... | @@ -467,7 +468,7 @@ fn runStepNames( |
| 467 | if (step.state == .skipped_oom) continue; | 468 | if (step.state == .skipped_oom) continue; |
| 468 | 469 | ||
| 469 | thread_pool.spawnWg(&wait_group, workerMakeOneStep, .{ | 470 | thread_pool.spawnWg(&wait_group, workerMakeOneStep, .{ |
| 470 | &wait_group, &thread_pool, b, step, &step_prog, run, | 471 | &wait_group, &thread_pool, b, step, step_prog, run, |
| 471 | }); | 472 | }); |
| 472 | } | 473 | } |
| 473 | } | 474 | } |
| ... | @@ -891,7 +892,7 @@ fn workerMakeOneStep( | ... | @@ -891,7 +892,7 @@ fn workerMakeOneStep( |
| 891 | thread_pool: *std.Thread.Pool, | 892 | thread_pool: *std.Thread.Pool, |
| 892 | b: *std.Build, | 893 | b: *std.Build, |
| 893 | s: *Step, | 894 | s: *Step, |
| 894 | prog_node: *std.Progress.Node, | 895 | prog_node: std.Progress.Node, |
| 895 | run: *Run, | 896 | run: *Run, |
| 896 | ) void { | 897 | ) void { |
| 897 | // First, check the conditions for running this step. If they are not met, | 898 | // First, check the conditions for running this step. If they are not met, |
| ... | @@ -941,11 +942,10 @@ fn workerMakeOneStep( | ... | @@ -941,11 +942,10 @@ fn workerMakeOneStep( |
| 941 | } | 942 | } |
| 942 | } | 943 | } |
| 943 | 944 | ||
| 944 | var sub_prog_node = prog_node.start(s.name, 0); | 945 | const sub_prog_node = prog_node.start(s.name, 0); |
| 945 | sub_prog_node.activate(); | ||
| 946 | defer sub_prog_node.end(); | 946 | defer sub_prog_node.end(); |
| 947 | 947 | ||
| 948 | const make_result = s.make(&sub_prog_node); | 948 | const make_result = s.make(sub_prog_node); |
| 949 | 949 | ||
| 950 | // No matter the result, we want to display error/warning messages. | 950 | // No matter the result, we want to display error/warning messages. |
| 951 | const show_compile_errors = !run.prominent_compile_errors and | 951 | const show_compile_errors = !run.prominent_compile_errors and |
| ... | @@ -954,8 +954,8 @@ fn workerMakeOneStep( | ... | @@ -954,8 +954,8 @@ fn workerMakeOneStep( |
| 954 | const show_stderr = s.result_stderr.len > 0; | 954 | const show_stderr = s.result_stderr.len > 0; |
| 955 | 955 | ||
| 956 | if (show_error_msgs or show_compile_errors or show_stderr) { | 956 | if (show_error_msgs or show_compile_errors or show_stderr) { |
| 957 | sub_prog_node.context.lock_stderr(); | 957 | std.debug.lockStdErr(); |
| 958 | defer sub_prog_node.context.unlock_stderr(); | 958 | defer std.debug.unlockStdErr(); |
| 959 | 959 | ||
| 960 | printErrorMessages(b, s, run) catch {}; | 960 | printErrorMessages(b, s, run) catch {}; |
| 961 | } | 961 | } |
| ... | @@ -1225,7 +1225,7 @@ fn cleanExit() void { | ... | @@ -1225,7 +1225,7 @@ fn cleanExit() void { |
| 1225 | process.exit(0); | 1225 | process.exit(0); |
| 1226 | } | 1226 | } |
| 1227 | 1227 | ||
| 1228 | const Color = enum { auto, off, on }; | 1228 | const Color = std.zig.Color; |
| 1229 | const Summary = enum { all, new, failures, none }; | 1229 | const Summary = enum { all, new, failures, none }; |
| 1230 | 1230 | ||
| 1231 | fn get_tty_conf(color: Color, stderr: File) std.io.tty.Config { | 1231 | fn get_tty_conf(color: Color, stderr: File) std.io.tty.Config { |
lib/compiler/resinator/cli.zig+2-2| ... | @@ -108,8 +108,8 @@ pub const Diagnostics = struct { | ... | @@ -108,8 +108,8 @@ pub const Diagnostics = struct { |
| 108 | } | 108 | } |
| 109 | 109 | ||
| 110 | pub fn renderToStdErr(self: *Diagnostics, args: []const []const u8, config: std.io.tty.Config) void { | 110 | pub fn renderToStdErr(self: *Diagnostics, args: []const []const u8, config: std.io.tty.Config) void { |
| 111 | std.debug.getStderrMutex().lock(); | 111 | std.debug.lockStdErr(); |
| 112 | defer std.debug.getStderrMutex().unlock(); | 112 | defer std.debug.unlockStdErr(); |
| 113 | const stderr = std.io.getStdErr().writer(); | 113 | const stderr = std.io.getStdErr().writer(); |
| 114 | self.renderToWriter(args, stderr, config) catch return; | 114 | self.renderToWriter(args, stderr, config) catch return; |
| 115 | } | 115 | } |
lib/compiler/resinator/errors.zig+2-2| ... | @@ -60,8 +60,8 @@ pub const Diagnostics = struct { | ... | @@ -60,8 +60,8 @@ pub const Diagnostics = struct { |
| 60 | } | 60 | } |
| 61 | 61 | ||
| 62 | pub fn renderToStdErr(self: *Diagnostics, cwd: std.fs.Dir, source: []const u8, tty_config: std.io.tty.Config, source_mappings: ?SourceMappings) void { | 62 | pub fn renderToStdErr(self: *Diagnostics, cwd: std.fs.Dir, source: []const u8, tty_config: std.io.tty.Config, source_mappings: ?SourceMappings) void { |
| 63 | std.debug.getStderrMutex().lock(); | 63 | std.debug.lockStdErr(); |
| 64 | defer std.debug.getStderrMutex().unlock(); | 64 | defer std.debug.unlockStdErr(); |
| 65 | const stderr = std.io.getStdErr().writer(); | 65 | const stderr = std.io.getStdErr().writer(); |
| 66 | for (self.errors.items) |err_details| { | 66 | for (self.errors.items) |err_details| { |
| 67 | renderErrorMessage(self.allocator, stderr, tty_config, cwd, err_details, source, self.strings.items, source_mappings) catch return; | 67 | renderErrorMessage(self.allocator, stderr, tty_config, cwd, err_details, source, self.strings.items, source_mappings) catch return; |
lib/compiler/resinator/main.zig-6| ... | @@ -50,12 +50,6 @@ pub fn main() !void { | ... | @@ -50,12 +50,6 @@ pub fn main() !void { |
| 50 | }, | 50 | }, |
| 51 | }; | 51 | }; |
| 52 | 52 | ||
| 53 | if (zig_integration) { | ||
| 54 | // Send progress with a special string to indicate that the building of the | ||
| 55 | // resinator binary is finished and we've moved on to actually compiling the .rc file | ||
| 56 | try error_handler.server.serveStringMessage(.progress, "<resinator>"); | ||
| 57 | } | ||
| 58 | |||
| 59 | var options = options: { | 53 | var options = options: { |
| 60 | var cli_diagnostics = cli.Diagnostics.init(allocator); | 54 | var cli_diagnostics = cli.Diagnostics.init(allocator); |
| 61 | defer cli_diagnostics.deinit(); | 55 | defer cli_diagnostics.deinit(); |
lib/compiler/test_runner.zig+19-12| ... | @@ -129,12 +129,11 @@ fn mainTerminal() void { | ... | @@ -129,12 +129,11 @@ fn mainTerminal() void { |
| 129 | var ok_count: usize = 0; | 129 | var ok_count: usize = 0; |
| 130 | var skip_count: usize = 0; | 130 | var skip_count: usize = 0; |
| 131 | var fail_count: usize = 0; | 131 | var fail_count: usize = 0; |
| 132 | var progress = std.Progress{ | 132 | const root_node = std.Progress.start(.{ |
| 133 | .dont_print_on_dumb = true, | 133 | .root_name = "Test", |
| 134 | }; | 134 | .estimated_total_items = test_fn_list.len, |
| 135 | const root_node = progress.start("Test", test_fn_list.len); | 135 | }); |
| 136 | const have_tty = progress.terminal != null and | 136 | const have_tty = std.io.getStdErr().isTty(); |
| 137 | (progress.supports_ansi_escape_codes or progress.is_windows_terminal); | ||
| 138 | 137 | ||
| 139 | var async_frame_buffer: []align(builtin.target.stackAlignment()) u8 = undefined; | 138 | var async_frame_buffer: []align(builtin.target.stackAlignment()) u8 = undefined; |
| 140 | // TODO this is on the next line (using `undefined` above) because otherwise zig incorrectly | 139 | // TODO this is on the next line (using `undefined` above) because otherwise zig incorrectly |
| ... | @@ -151,11 +150,9 @@ fn mainTerminal() void { | ... | @@ -151,11 +150,9 @@ fn mainTerminal() void { |
| 151 | } | 150 | } |
| 152 | std.testing.log_level = .warn; | 151 | std.testing.log_level = .warn; |
| 153 | 152 | ||
| 154 | var test_node = root_node.start(test_fn.name, 0); | 153 | const test_node = root_node.start(test_fn.name, 0); |
| 155 | test_node.activate(); | ||
| 156 | progress.refresh(); | ||
| 157 | if (!have_tty) { | 154 | if (!have_tty) { |
| 158 | std.debug.print("{d}/{d} {s}... ", .{ i + 1, test_fn_list.len, test_fn.name }); | 155 | std.debug.print("{d}/{d} {s}...", .{ i + 1, test_fn_list.len, test_fn.name }); |
| 159 | } | 156 | } |
| 160 | if (test_fn.func()) |_| { | 157 | if (test_fn.func()) |_| { |
| 161 | ok_count += 1; | 158 | ok_count += 1; |
| ... | @@ -164,12 +161,22 @@ fn mainTerminal() void { | ... | @@ -164,12 +161,22 @@ fn mainTerminal() void { |
| 164 | } else |err| switch (err) { | 161 | } else |err| switch (err) { |
| 165 | error.SkipZigTest => { | 162 | error.SkipZigTest => { |
| 166 | skip_count += 1; | 163 | skip_count += 1; |
| 167 | progress.log("SKIP\n", .{}); | 164 | if (have_tty) { |
| 165 | std.debug.print("{d}/{d} {s}...SKIP\n", .{ i + 1, test_fn_list.len, test_fn.name }); | ||
| 166 | } else { | ||
| 167 | std.debug.print("SKIP\n", .{}); | ||
| 168 | } | ||
| 168 | test_node.end(); | 169 | test_node.end(); |
| 169 | }, | 170 | }, |
| 170 | else => { | 171 | else => { |
| 171 | fail_count += 1; | 172 | fail_count += 1; |
| 172 | progress.log("FAIL ({s})\n", .{@errorName(err)}); | 173 | if (have_tty) { |
| 174 | std.debug.print("{d}/{d} {s}...FAIL ({s})\n", .{ | ||
| 175 | i + 1, test_fn_list.len, test_fn.name, @errorName(err), | ||
| 176 | }); | ||
| 177 | } else { | ||
| 178 | std.debug.print("FAIL ({s})\n", .{@errorName(err)}); | ||
| 179 | } | ||
| 173 | if (@errorReturnTrace()) |trace| { | 180 | if (@errorReturnTrace()) |trace| { |
| 174 | std.debug.dumpStackTrace(trace.*); | 181 | std.debug.dumpStackTrace(trace.*); |
| 175 | } | 182 | } |
lib/std/Build.zig+5-5| ... | @@ -1059,7 +1059,7 @@ pub fn getUninstallStep(b: *Build) *Step { | ... | @@ -1059,7 +1059,7 @@ pub fn getUninstallStep(b: *Build) *Step { |
| 1059 | return &b.uninstall_tls.step; | 1059 | return &b.uninstall_tls.step; |
| 1060 | } | 1060 | } |
| 1061 | 1061 | ||
| 1062 | fn makeUninstall(uninstall_step: *Step, prog_node: *std.Progress.Node) anyerror!void { | 1062 | fn makeUninstall(uninstall_step: *Step, prog_node: std.Progress.Node) anyerror!void { |
| 1063 | _ = prog_node; | 1063 | _ = prog_node; |
| 1064 | const uninstall_tls: *TopLevelStep = @fieldParentPtr("step", uninstall_step); | 1064 | const uninstall_tls: *TopLevelStep = @fieldParentPtr("step", uninstall_step); |
| 1065 | const b: *Build = @fieldParentPtr("uninstall_tls", uninstall_tls); | 1065 | const b: *Build = @fieldParentPtr("uninstall_tls", uninstall_tls); |
| ... | @@ -2281,10 +2281,10 @@ pub const LazyPath = union(enum) { | ... | @@ -2281,10 +2281,10 @@ pub const LazyPath = union(enum) { |
| 2281 | .cwd_relative => |p| return src_builder.pathFromCwd(p), | 2281 | .cwd_relative => |p| return src_builder.pathFromCwd(p), |
| 2282 | .generated => |gen| { | 2282 | .generated => |gen| { |
| 2283 | var file_path: []const u8 = gen.file.step.owner.pathFromRoot(gen.file.path orelse { | 2283 | var file_path: []const u8 = gen.file.step.owner.pathFromRoot(gen.file.path orelse { |
| 2284 | std.debug.getStderrMutex().lock(); | 2284 | std.debug.lockStdErr(); |
| 2285 | const stderr = std.io.getStdErr(); | 2285 | const stderr = std.io.getStdErr(); |
| 2286 | dumpBadGetPathHelp(gen.file.step, stderr, src_builder, asking_step) catch {}; | 2286 | dumpBadGetPathHelp(gen.file.step, stderr, src_builder, asking_step) catch {}; |
| 2287 | std.debug.getStderrMutex().unlock(); | 2287 | std.debug.unlockStdErr(); |
| 2288 | @panic("misconfigured build script"); | 2288 | @panic("misconfigured build script"); |
| 2289 | }); | 2289 | }); |
| 2290 | 2290 | ||
| ... | @@ -2351,8 +2351,8 @@ fn dumpBadDirnameHelp( | ... | @@ -2351,8 +2351,8 @@ fn dumpBadDirnameHelp( |
| 2351 | comptime msg: []const u8, | 2351 | comptime msg: []const u8, |
| 2352 | args: anytype, | 2352 | args: anytype, |
| 2353 | ) anyerror!void { | 2353 | ) anyerror!void { |
| 2354 | debug.getStderrMutex().lock(); | 2354 | debug.lockStdErr(); |
| 2355 | defer debug.getStderrMutex().unlock(); | 2355 | defer debug.unlockStdErr(); |
| 2356 | 2356 | ||
| 2357 | const stderr = io.getStdErr(); | 2357 | const stderr = io.getStdErr(); |
| 2358 | const w = stderr.writer(); | 2358 | const w = stderr.writer(); |
lib/std/Build/Step.zig+5-14| ... | @@ -58,7 +58,7 @@ pub const TestResults = struct { | ... | @@ -58,7 +58,7 @@ pub const TestResults = struct { |
| 58 | } | 58 | } |
| 59 | }; | 59 | }; |
| 60 | 60 | ||
| 61 | pub const MakeFn = *const fn (step: *Step, prog_node: *std.Progress.Node) anyerror!void; | 61 | pub const MakeFn = *const fn (step: *Step, prog_node: std.Progress.Node) anyerror!void; |
| 62 | 62 | ||
| 63 | pub const State = enum { | 63 | pub const State = enum { |
| 64 | precheck_unstarted, | 64 | precheck_unstarted, |
| ... | @@ -176,7 +176,7 @@ pub fn init(options: StepOptions) Step { | ... | @@ -176,7 +176,7 @@ pub fn init(options: StepOptions) Step { |
| 176 | /// If the Step's `make` function reports `error.MakeFailed`, it indicates they | 176 | /// If the Step's `make` function reports `error.MakeFailed`, it indicates they |
| 177 | /// have already reported the error. Otherwise, we add a simple error report | 177 | /// have already reported the error. Otherwise, we add a simple error report |
| 178 | /// here. | 178 | /// here. |
| 179 | pub fn make(s: *Step, prog_node: *std.Progress.Node) error{ MakeFailed, MakeSkipped }!void { | 179 | pub fn make(s: *Step, prog_node: std.Progress.Node) error{ MakeFailed, MakeSkipped }!void { |
| 180 | const arena = s.owner.allocator; | 180 | const arena = s.owner.allocator; |
| 181 | 181 | ||
| 182 | s.makeFn(s, prog_node) catch |err| switch (err) { | 182 | s.makeFn(s, prog_node) catch |err| switch (err) { |
| ... | @@ -217,7 +217,7 @@ pub fn getStackTrace(s: *Step) ?std.builtin.StackTrace { | ... | @@ -217,7 +217,7 @@ pub fn getStackTrace(s: *Step) ?std.builtin.StackTrace { |
| 217 | }; | 217 | }; |
| 218 | } | 218 | } |
| 219 | 219 | ||
| 220 | fn makeNoOp(step: *Step, prog_node: *std.Progress.Node) anyerror!void { | 220 | fn makeNoOp(step: *Step, prog_node: std.Progress.Node) anyerror!void { |
| 221 | _ = prog_node; | 221 | _ = prog_node; |
| 222 | 222 | ||
| 223 | var all_cached = true; | 223 | var all_cached = true; |
| ... | @@ -303,7 +303,7 @@ pub fn addError(step: *Step, comptime fmt: []const u8, args: anytype) error{OutO | ... | @@ -303,7 +303,7 @@ pub fn addError(step: *Step, comptime fmt: []const u8, args: anytype) error{OutO |
| 303 | pub fn evalZigProcess( | 303 | pub fn evalZigProcess( |
| 304 | s: *Step, | 304 | s: *Step, |
| 305 | argv: []const []const u8, | 305 | argv: []const []const u8, |
| 306 | prog_node: *std.Progress.Node, | 306 | prog_node: std.Progress.Node, |
| 307 | ) !?[]const u8 { | 307 | ) !?[]const u8 { |
| 308 | assert(argv.len != 0); | 308 | assert(argv.len != 0); |
| 309 | const b = s.owner; | 309 | const b = s.owner; |
| ... | @@ -319,6 +319,7 @@ pub fn evalZigProcess( | ... | @@ -319,6 +319,7 @@ pub fn evalZigProcess( |
| 319 | child.stdout_behavior = .Pipe; | 319 | child.stdout_behavior = .Pipe; |
| 320 | child.stderr_behavior = .Pipe; | 320 | child.stderr_behavior = .Pipe; |
| 321 | child.request_resource_usage_statistics = true; | 321 | child.request_resource_usage_statistics = true; |
| 322 | child.progress_node = prog_node; | ||
| 322 | 323 | ||
| 323 | child.spawn() catch |err| return s.fail("unable to spawn {s}: {s}", .{ | 324 | child.spawn() catch |err| return s.fail("unable to spawn {s}: {s}", .{ |
| 324 | argv[0], @errorName(err), | 325 | argv[0], @errorName(err), |
| ... | @@ -337,11 +338,6 @@ pub fn evalZigProcess( | ... | @@ -337,11 +338,6 @@ pub fn evalZigProcess( |
| 337 | const Header = std.zig.Server.Message.Header; | 338 | const Header = std.zig.Server.Message.Header; |
| 338 | var result: ?[]const u8 = null; | 339 | var result: ?[]const u8 = null; |
| 339 | 340 | ||
| 340 | var node_name: std.ArrayListUnmanaged(u8) = .{}; | ||
| 341 | defer node_name.deinit(gpa); | ||
| 342 | var sub_prog_node = prog_node.start("", 0); | ||
| 343 | defer sub_prog_node.end(); | ||
| 344 | |||
| 345 | const stdout = poller.fifo(.stdout); | 341 | const stdout = poller.fifo(.stdout); |
| 346 | 342 | ||
| 347 | poll: while (true) { | 343 | poll: while (true) { |
| ... | @@ -379,11 +375,6 @@ pub fn evalZigProcess( | ... | @@ -379,11 +375,6 @@ pub fn evalZigProcess( |
| 379 | .extra = extra_array, | 375 | .extra = extra_array, |
| 380 | }; | 376 | }; |
| 381 | }, | 377 | }, |
| 382 | .progress => { | ||
| 383 | node_name.clearRetainingCapacity(); | ||
| 384 | try node_name.appendSlice(gpa, body); | ||
| 385 | sub_prog_node.setName(node_name.items); | ||
| 386 | }, | ||
| 387 | .emit_bin_path => { | 378 | .emit_bin_path => { |
| 388 | const EbpHdr = std.zig.Server.Message.EmitBinPath; | 379 | const EbpHdr = std.zig.Server.Message.EmitBinPath; |
| 389 | const ebp_hdr = @as(*align(1) const EbpHdr, @ptrCast(body)); | 380 | const ebp_hdr = @as(*align(1) const EbpHdr, @ptrCast(body)); |
lib/std/Build/Step/CheckFile.zig+1-1| ... | @@ -46,7 +46,7 @@ pub fn setName(check_file: *CheckFile, name: []const u8) void { | ... | @@ -46,7 +46,7 @@ pub fn setName(check_file: *CheckFile, name: []const u8) void { |
| 46 | check_file.step.name = name; | 46 | check_file.step.name = name; |
| 47 | } | 47 | } |
| 48 | 48 | ||
| 49 | fn make(step: *Step, prog_node: *std.Progress.Node) !void { | 49 | fn make(step: *Step, prog_node: std.Progress.Node) !void { |
| 50 | _ = prog_node; | 50 | _ = prog_node; |
| 51 | const b = step.owner; | 51 | const b = step.owner; |
| 52 | const check_file: *CheckFile = @fieldParentPtr("step", step); | 52 | const check_file: *CheckFile = @fieldParentPtr("step", step); |
lib/std/Build/Step/CheckObject.zig+1-1| ... | @@ -550,7 +550,7 @@ pub fn checkComputeCompare( | ... | @@ -550,7 +550,7 @@ pub fn checkComputeCompare( |
| 550 | check_object.checks.append(check) catch @panic("OOM"); | 550 | check_object.checks.append(check) catch @panic("OOM"); |
| 551 | } | 551 | } |
| 552 | 552 | ||
| 553 | fn make(step: *Step, prog_node: *std.Progress.Node) !void { | 553 | fn make(step: *Step, prog_node: std.Progress.Node) !void { |
| 554 | _ = prog_node; | 554 | _ = prog_node; |
| 555 | const b = step.owner; | 555 | const b = step.owner; |
| 556 | const gpa = b.allocator; | 556 | const gpa = b.allocator; |
lib/std/Build/Step/Compile.zig+3-3| ... | @@ -967,7 +967,7 @@ fn getGeneratedFilePath(compile: *Compile, comptime tag_name: []const u8, asking | ... | @@ -967,7 +967,7 @@ fn getGeneratedFilePath(compile: *Compile, comptime tag_name: []const u8, asking |
| 967 | const maybe_path: ?*GeneratedFile = @field(compile, tag_name); | 967 | const maybe_path: ?*GeneratedFile = @field(compile, tag_name); |
| 968 | 968 | ||
| 969 | const generated_file = maybe_path orelse { | 969 | const generated_file = maybe_path orelse { |
| 970 | std.debug.getStderrMutex().lock(); | 970 | std.debug.lockStdErr(); |
| 971 | const stderr = std.io.getStdErr(); | 971 | const stderr = std.io.getStdErr(); |
| 972 | 972 | ||
| 973 | std.Build.dumpBadGetPathHelp(&compile.step, stderr, compile.step.owner, asking_step) catch {}; | 973 | std.Build.dumpBadGetPathHelp(&compile.step, stderr, compile.step.owner, asking_step) catch {}; |
| ... | @@ -976,7 +976,7 @@ fn getGeneratedFilePath(compile: *Compile, comptime tag_name: []const u8, asking | ... | @@ -976,7 +976,7 @@ fn getGeneratedFilePath(compile: *Compile, comptime tag_name: []const u8, asking |
| 976 | }; | 976 | }; |
| 977 | 977 | ||
| 978 | const path = generated_file.path orelse { | 978 | const path = generated_file.path orelse { |
| 979 | std.debug.getStderrMutex().lock(); | 979 | std.debug.lockStdErr(); |
| 980 | const stderr = std.io.getStdErr(); | 980 | const stderr = std.io.getStdErr(); |
| 981 | 981 | ||
| 982 | std.Build.dumpBadGetPathHelp(&compile.step, stderr, compile.step.owner, asking_step) catch {}; | 982 | std.Build.dumpBadGetPathHelp(&compile.step, stderr, compile.step.owner, asking_step) catch {}; |
| ... | @@ -987,7 +987,7 @@ fn getGeneratedFilePath(compile: *Compile, comptime tag_name: []const u8, asking | ... | @@ -987,7 +987,7 @@ fn getGeneratedFilePath(compile: *Compile, comptime tag_name: []const u8, asking |
| 987 | return path; | 987 | return path; |
| 988 | } | 988 | } |
| 989 | 989 | ||
| 990 | fn make(step: *Step, prog_node: *std.Progress.Node) !void { | 990 | fn make(step: *Step, prog_node: std.Progress.Node) !void { |
| 991 | const b = step.owner; | 991 | const b = step.owner; |
| 992 | const arena = b.allocator; | 992 | const arena = b.allocator; |
| 993 | const compile: *Compile = @fieldParentPtr("step", step); | 993 | const compile: *Compile = @fieldParentPtr("step", step); |
lib/std/Build/Step/ConfigHeader.zig+1-1| ... | @@ -164,7 +164,7 @@ fn putValue(config_header: *ConfigHeader, field_name: []const u8, comptime T: ty | ... | @@ -164,7 +164,7 @@ fn putValue(config_header: *ConfigHeader, field_name: []const u8, comptime T: ty |
| 164 | } | 164 | } |
| 165 | } | 165 | } |
| 166 | 166 | ||
| 167 | fn make(step: *Step, prog_node: *std.Progress.Node) !void { | 167 | fn make(step: *Step, prog_node: std.Progress.Node) !void { |
| 168 | _ = prog_node; | 168 | _ = prog_node; |
| 169 | const b = step.owner; | 169 | const b = step.owner; |
| 170 | const config_header: *ConfigHeader = @fieldParentPtr("step", step); | 170 | const config_header: *ConfigHeader = @fieldParentPtr("step", step); |
lib/std/Build/Step/Fmt.zig+1-1| ... | @@ -36,7 +36,7 @@ pub fn create(owner: *std.Build, options: Options) *Fmt { | ... | @@ -36,7 +36,7 @@ pub fn create(owner: *std.Build, options: Options) *Fmt { |
| 36 | return fmt; | 36 | return fmt; |
| 37 | } | 37 | } |
| 38 | 38 | ||
| 39 | fn make(step: *Step, prog_node: *std.Progress.Node) !void { | 39 | fn make(step: *Step, prog_node: std.Progress.Node) !void { |
| 40 | // zig fmt is fast enough that no progress is needed. | 40 | // zig fmt is fast enough that no progress is needed. |
| 41 | _ = prog_node; | 41 | _ = prog_node; |
| 42 | 42 |
lib/std/Build/Step/InstallArtifact.zig+1-1| ... | @@ -115,7 +115,7 @@ pub fn create(owner: *std.Build, artifact: *Step.Compile, options: Options) *Ins | ... | @@ -115,7 +115,7 @@ pub fn create(owner: *std.Build, artifact: *Step.Compile, options: Options) *Ins |
| 115 | return install_artifact; | 115 | return install_artifact; |
| 116 | } | 116 | } |
| 117 | 117 | ||
| 118 | fn make(step: *Step, prog_node: *std.Progress.Node) !void { | 118 | fn make(step: *Step, prog_node: std.Progress.Node) !void { |
| 119 | _ = prog_node; | 119 | _ = prog_node; |
| 120 | const install_artifact: *InstallArtifact = @fieldParentPtr("step", step); | 120 | const install_artifact: *InstallArtifact = @fieldParentPtr("step", step); |
| 121 | const b = step.owner; | 121 | const b = step.owner; |
lib/std/Build/Step/InstallDir.zig+1-1| ... | @@ -56,7 +56,7 @@ pub fn create(owner: *std.Build, options: Options) *InstallDir { | ... | @@ -56,7 +56,7 @@ pub fn create(owner: *std.Build, options: Options) *InstallDir { |
| 56 | return install_dir; | 56 | return install_dir; |
| 57 | } | 57 | } |
| 58 | 58 | ||
| 59 | fn make(step: *Step, prog_node: *std.Progress.Node) !void { | 59 | fn make(step: *Step, prog_node: std.Progress.Node) !void { |
| 60 | _ = prog_node; | 60 | _ = prog_node; |
| 61 | const b = step.owner; | 61 | const b = step.owner; |
| 62 | const install_dir: *InstallDir = @fieldParentPtr("step", step); | 62 | const install_dir: *InstallDir = @fieldParentPtr("step", step); |
lib/std/Build/Step/InstallFile.zig+1-1| ... | @@ -36,7 +36,7 @@ pub fn create( | ... | @@ -36,7 +36,7 @@ pub fn create( |
| 36 | return install_file; | 36 | return install_file; |
| 37 | } | 37 | } |
| 38 | 38 | ||
| 39 | fn make(step: *Step, prog_node: *std.Progress.Node) !void { | 39 | fn make(step: *Step, prog_node: std.Progress.Node) !void { |
| 40 | _ = prog_node; | 40 | _ = prog_node; |
| 41 | const b = step.owner; | 41 | const b = step.owner; |
| 42 | const install_file: *InstallFile = @fieldParentPtr("step", step); | 42 | const install_file: *InstallFile = @fieldParentPtr("step", step); |
lib/std/Build/Step/ObjCopy.zig+1-1| ... | @@ -90,7 +90,7 @@ pub fn getOutputSeparatedDebug(objcopy: *const ObjCopy) ?std.Build.LazyPath { | ... | @@ -90,7 +90,7 @@ pub fn getOutputSeparatedDebug(objcopy: *const ObjCopy) ?std.Build.LazyPath { |
| 90 | return if (objcopy.output_file_debug) |*file| .{ .generated = .{ .file = file } } else null; | 90 | return if (objcopy.output_file_debug) |*file| .{ .generated = .{ .file = file } } else null; |
| 91 | } | 91 | } |
| 92 | 92 | ||
| 93 | fn make(step: *Step, prog_node: *std.Progress.Node) !void { | 93 | fn make(step: *Step, prog_node: std.Progress.Node) !void { |
| 94 | const b = step.owner; | 94 | const b = step.owner; |
| 95 | const objcopy: *ObjCopy = @fieldParentPtr("step", step); | 95 | const objcopy: *ObjCopy = @fieldParentPtr("step", step); |
| 96 | 96 |
lib/std/Build/Step/Options.zig+1-1| ... | @@ -410,7 +410,7 @@ pub fn getOutput(options: *Options) LazyPath { | ... | @@ -410,7 +410,7 @@ pub fn getOutput(options: *Options) LazyPath { |
| 410 | return .{ .generated = .{ .file = &options.generated_file } }; | 410 | return .{ .generated = .{ .file = &options.generated_file } }; |
| 411 | } | 411 | } |
| 412 | 412 | ||
| 413 | fn make(step: *Step, prog_node: *std.Progress.Node) !void { | 413 | fn make(step: *Step, prog_node: std.Progress.Node) !void { |
| 414 | // This step completes so quickly that no progress is necessary. | 414 | // This step completes so quickly that no progress is necessary. |
| 415 | _ = prog_node; | 415 | _ = prog_node; |
| 416 | 416 |
lib/std/Build/Step/RemoveDir.zig+1-1| ... | @@ -22,7 +22,7 @@ pub fn create(owner: *std.Build, dir_path: []const u8) *RemoveDir { | ... | @@ -22,7 +22,7 @@ pub fn create(owner: *std.Build, dir_path: []const u8) *RemoveDir { |
| 22 | return remove_dir; | 22 | return remove_dir; |
| 23 | } | 23 | } |
| 24 | 24 | ||
| 25 | fn make(step: *Step, prog_node: *std.Progress.Node) !void { | 25 | fn make(step: *Step, prog_node: std.Progress.Node) !void { |
| 26 | // TODO update progress node while walking file system. | 26 | // TODO update progress node while walking file system. |
| 27 | // Should the standard library support this use case?? | 27 | // Should the standard library support this use case?? |
| 28 | _ = prog_node; | 28 | _ = prog_node; |
lib/std/Build/Step/Run.zig+17-7| ... | @@ -23,6 +23,11 @@ cwd: ?Build.LazyPath, | ... | @@ -23,6 +23,11 @@ cwd: ?Build.LazyPath, |
| 23 | /// Override this field to modify the environment, or use setEnvironmentVariable | 23 | /// Override this field to modify the environment, or use setEnvironmentVariable |
| 24 | env_map: ?*EnvMap, | 24 | env_map: ?*EnvMap, |
| 25 | 25 | ||
| 26 | /// When `true` prevents `ZIG_PROGRESS` environment variable from being passed | ||
| 27 | /// to the child process, which otherwise would be used for the child to send | ||
| 28 | /// progress updates to the parent. | ||
| 29 | disable_zig_progress: bool, | ||
| 30 | |||
| 26 | /// Configures whether the Run step is considered to have side-effects, and also | 31 | /// Configures whether the Run step is considered to have side-effects, and also |
| 27 | /// whether the Run step will inherit stdio streams, forwarding them to the | 32 | /// whether the Run step will inherit stdio streams, forwarding them to the |
| 28 | /// parent process, in which case will require a global lock to prevent other | 33 | /// parent process, in which case will require a global lock to prevent other |
| ... | @@ -152,6 +157,7 @@ pub fn create(owner: *std.Build, name: []const u8) *Run { | ... | @@ -152,6 +157,7 @@ pub fn create(owner: *std.Build, name: []const u8) *Run { |
| 152 | .argv = .{}, | 157 | .argv = .{}, |
| 153 | .cwd = null, | 158 | .cwd = null, |
| 154 | .env_map = null, | 159 | .env_map = null, |
| 160 | .disable_zig_progress = false, | ||
| 155 | .stdio = .infer_from_args, | 161 | .stdio = .infer_from_args, |
| 156 | .stdin = .none, | 162 | .stdin = .none, |
| 157 | .extra_file_dependencies = &.{}, | 163 | .extra_file_dependencies = &.{}, |
| ... | @@ -574,7 +580,7 @@ const IndexedOutput = struct { | ... | @@ -574,7 +580,7 @@ const IndexedOutput = struct { |
| 574 | tag: @typeInfo(Arg).Union.tag_type.?, | 580 | tag: @typeInfo(Arg).Union.tag_type.?, |
| 575 | output: *Output, | 581 | output: *Output, |
| 576 | }; | 582 | }; |
| 577 | fn make(step: *Step, prog_node: *std.Progress.Node) !void { | 583 | fn make(step: *Step, prog_node: std.Progress.Node) !void { |
| 578 | const b = step.owner; | 584 | const b = step.owner; |
| 579 | const arena = b.allocator; | 585 | const arena = b.allocator; |
| 580 | const run: *Run = @fieldParentPtr("step", step); | 586 | const run: *Run = @fieldParentPtr("step", step); |
| ... | @@ -878,7 +884,7 @@ fn runCommand( | ... | @@ -878,7 +884,7 @@ fn runCommand( |
| 878 | argv: []const []const u8, | 884 | argv: []const []const u8, |
| 879 | has_side_effects: bool, | 885 | has_side_effects: bool, |
| 880 | output_dir_path: []const u8, | 886 | output_dir_path: []const u8, |
| 881 | prog_node: *std.Progress.Node, | 887 | prog_node: std.Progress.Node, |
| 882 | ) !void { | 888 | ) !void { |
| 883 | const step = &run.step; | 889 | const step = &run.step; |
| 884 | const b = step.owner; | 890 | const b = step.owner; |
| ... | @@ -1195,7 +1201,7 @@ fn spawnChildAndCollect( | ... | @@ -1195,7 +1201,7 @@ fn spawnChildAndCollect( |
| 1195 | run: *Run, | 1201 | run: *Run, |
| 1196 | argv: []const []const u8, | 1202 | argv: []const []const u8, |
| 1197 | has_side_effects: bool, | 1203 | has_side_effects: bool, |
| 1198 | prog_node: *std.Progress.Node, | 1204 | prog_node: std.Progress.Node, |
| 1199 | ) !ChildProcResult { | 1205 | ) !ChildProcResult { |
| 1200 | const b = run.step.owner; | 1206 | const b = run.step.owner; |
| 1201 | const arena = b.allocator; | 1207 | const arena = b.allocator; |
| ... | @@ -1235,6 +1241,10 @@ fn spawnChildAndCollect( | ... | @@ -1235,6 +1241,10 @@ fn spawnChildAndCollect( |
| 1235 | child.stdin_behavior = .Pipe; | 1241 | child.stdin_behavior = .Pipe; |
| 1236 | } | 1242 | } |
| 1237 | 1243 | ||
| 1244 | if (run.stdio != .zig_test and !run.disable_zig_progress) { | ||
| 1245 | child.progress_node = prog_node; | ||
| 1246 | } | ||
| 1247 | |||
| 1238 | try child.spawn(); | 1248 | try child.spawn(); |
| 1239 | var timer = try std.time.Timer.start(); | 1249 | var timer = try std.time.Timer.start(); |
| 1240 | 1250 | ||
| ... | @@ -1264,7 +1274,7 @@ const StdIoResult = struct { | ... | @@ -1264,7 +1274,7 @@ const StdIoResult = struct { |
| 1264 | fn evalZigTest( | 1274 | fn evalZigTest( |
| 1265 | run: *Run, | 1275 | run: *Run, |
| 1266 | child: *std.process.Child, | 1276 | child: *std.process.Child, |
| 1267 | prog_node: *std.Progress.Node, | 1277 | prog_node: std.Progress.Node, |
| 1268 | ) !StdIoResult { | 1278 | ) !StdIoResult { |
| 1269 | const gpa = run.step.owner.allocator; | 1279 | const gpa = run.step.owner.allocator; |
| 1270 | const arena = run.step.owner.allocator; | 1280 | const arena = run.step.owner.allocator; |
| ... | @@ -1291,7 +1301,7 @@ fn evalZigTest( | ... | @@ -1291,7 +1301,7 @@ fn evalZigTest( |
| 1291 | var metadata: ?TestMetadata = null; | 1301 | var metadata: ?TestMetadata = null; |
| 1292 | 1302 | ||
| 1293 | var sub_prog_node: ?std.Progress.Node = null; | 1303 | var sub_prog_node: ?std.Progress.Node = null; |
| 1294 | defer if (sub_prog_node) |*n| n.end(); | 1304 | defer if (sub_prog_node) |n| n.end(); |
| 1295 | 1305 | ||
| 1296 | poll: while (true) { | 1306 | poll: while (true) { |
| 1297 | while (stdout.readableLength() < @sizeOf(Header)) { | 1307 | while (stdout.readableLength() < @sizeOf(Header)) { |
| ... | @@ -1406,7 +1416,7 @@ const TestMetadata = struct { | ... | @@ -1406,7 +1416,7 @@ const TestMetadata = struct { |
| 1406 | expected_panic_msgs: []const u32, | 1416 | expected_panic_msgs: []const u32, |
| 1407 | string_bytes: []const u8, | 1417 | string_bytes: []const u8, |
| 1408 | next_index: u32, | 1418 | next_index: u32, |
| 1409 | prog_node: *std.Progress.Node, | 1419 | prog_node: std.Progress.Node, |
| 1410 | 1420 | ||
| 1411 | fn testName(tm: TestMetadata, index: u32) []const u8 { | 1421 | fn testName(tm: TestMetadata, index: u32) []const u8 { |
| 1412 | return std.mem.sliceTo(tm.string_bytes[tm.names[index]..], 0); | 1422 | return std.mem.sliceTo(tm.string_bytes[tm.names[index]..], 0); |
| ... | @@ -1421,7 +1431,7 @@ fn requestNextTest(in: fs.File, metadata: *TestMetadata, sub_prog_node: *?std.Pr | ... | @@ -1421,7 +1431,7 @@ fn requestNextTest(in: fs.File, metadata: *TestMetadata, sub_prog_node: *?std.Pr |
| 1421 | if (metadata.expected_panic_msgs[i] != 0) continue; | 1431 | if (metadata.expected_panic_msgs[i] != 0) continue; |
| 1422 | 1432 | ||
| 1423 | const name = metadata.testName(i); | 1433 | const name = metadata.testName(i); |
| 1424 | if (sub_prog_node.*) |*n| n.end(); | 1434 | if (sub_prog_node.*) |n| n.end(); |
| 1425 | sub_prog_node.* = metadata.prog_node.start(name, 0); | 1435 | sub_prog_node.* = metadata.prog_node.start(name, 0); |
| 1426 | 1436 | ||
| 1427 | try sendRunTestMessage(in, i); | 1437 | try sendRunTestMessage(in, i); |
lib/std/Build/Step/TranslateC.zig+1-1| ... | @@ -116,7 +116,7 @@ pub fn defineCMacroRaw(translate_c: *TranslateC, name_and_value: []const u8) voi | ... | @@ -116,7 +116,7 @@ pub fn defineCMacroRaw(translate_c: *TranslateC, name_and_value: []const u8) voi |
| 116 | translate_c.c_macros.append(translate_c.step.owner.dupe(name_and_value)) catch @panic("OOM"); | 116 | translate_c.c_macros.append(translate_c.step.owner.dupe(name_and_value)) catch @panic("OOM"); |
| 117 | } | 117 | } |
| 118 | 118 | ||
| 119 | fn make(step: *Step, prog_node: *std.Progress.Node) !void { | 119 | fn make(step: *Step, prog_node: std.Progress.Node) !void { |
| 120 | const b = step.owner; | 120 | const b = step.owner; |
| 121 | const translate_c: *TranslateC = @fieldParentPtr("step", step); | 121 | const translate_c: *TranslateC = @fieldParentPtr("step", step); |
| 122 | 122 |
lib/std/Build/Step/WriteFile.zig+1-1| ... | @@ -198,7 +198,7 @@ fn maybeUpdateName(write_file: *WriteFile) void { | ... | @@ -198,7 +198,7 @@ fn maybeUpdateName(write_file: *WriteFile) void { |
| 198 | } | 198 | } |
| 199 | } | 199 | } |
| 200 | 200 | ||
| 201 | fn make(step: *Step, prog_node: *std.Progress.Node) !void { | 201 | fn make(step: *Step, prog_node: std.Progress.Node) !void { |
| 202 | _ = prog_node; | 202 | _ = prog_node; |
| 203 | const b = step.owner; | 203 | const b = step.owner; |
| 204 | const write_file: *WriteFile = @fieldParentPtr("step", step); | 204 | const write_file: *WriteFile = @fieldParentPtr("step", step); |
lib/std/Progress.zig+1194-343| ... | @@ -1,10 +1,4 @@ | ... | @@ -1,10 +1,4 @@ |
| 1 | //! This API is non-allocating, non-fallible, and thread-safe. | 1 | //! This API is non-allocating, non-fallible, thread-safe, and lock-free. |
| 2 | //! The tradeoff is that users of this API must provide the storage | ||
| 3 | //! for each `Progress.Node`. | ||
| 4 | //! | ||
| 5 | //! Initialize the struct directly, overriding these fields as desired: | ||
| 6 | //! * `refresh_rate_ms` | ||
| 7 | //! * `initial_delay_ms` | ||
| 8 | 2 | ||
| 9 | const std = @import("std"); | 3 | const std = @import("std"); |
| 10 | const builtin = @import("builtin"); | 4 | const builtin = @import("builtin"); |
| ... | @@ -12,436 +6,1293 @@ const windows = std.os.windows; | ... | @@ -12,436 +6,1293 @@ const windows = std.os.windows; |
| 12 | const testing = std.testing; | 6 | const testing = std.testing; |
| 13 | const assert = std.debug.assert; | 7 | const assert = std.debug.assert; |
| 14 | const Progress = @This(); | 8 | const Progress = @This(); |
| 9 | const posix = std.posix; | ||
| 10 | const is_big_endian = builtin.cpu.arch.endian() == .big; | ||
| 11 | const is_windows = builtin.os.tag == .windows; | ||
| 15 | 12 | ||
| 16 | /// `null` if the current node (and its children) should | 13 | /// `null` if the current node (and its children) should |
| 17 | /// not print on update() | 14 | /// not print on update() |
| 18 | terminal: ?std.fs.File = undefined, | 15 | terminal: std.fs.File, |
| 19 | 16 | ||
| 20 | /// Is this a windows API terminal (note: this is not the same as being run on windows | 17 | terminal_mode: TerminalMode, |
| 21 | /// because other terminals exist like MSYS/git-bash) | ||
| 22 | is_windows_terminal: bool = false, | ||
| 23 | 18 | ||
| 24 | /// Whether the terminal supports ANSI escape codes. | 19 | update_thread: ?std.Thread, |
| 25 | supports_ansi_escape_codes: bool = false, | ||
| 26 | 20 | ||
| 27 | /// If the terminal is "dumb", don't print output. | 21 | /// Atomically set by SIGWINCH as well as the root done() function. |
| 28 | /// This can be useful if you don't want to print all | 22 | redraw_event: std.Thread.ResetEvent, |
| 29 | /// the stages of code generation if there are a lot. | 23 | /// Indicates a request to shut down and reset global state. |
| 30 | /// You should not use it if the user should see output | 24 | /// Accessed atomically. |
| 31 | /// for example showing the user what tests run. | 25 | done: bool, |
| 32 | dont_print_on_dumb: bool = false, | ||
| 33 | 26 | ||
| 34 | root: Node = undefined, | 27 | refresh_rate_ns: u64, |
| 28 | initial_delay_ns: u64, | ||
| 35 | 29 | ||
| 36 | /// Keeps track of how much time has passed since the beginning. | 30 | rows: u16, |
| 37 | /// Used to compare with `initial_delay_ms` and `refresh_rate_ms`. | 31 | cols: u16, |
| 38 | timer: ?std.time.Timer = null, | 32 | /// Tracks the number of newlines that have been actually written to the terminal. |
| 33 | written_newline_count: u16, | ||
| 34 | /// Tracks the number of newlines that will be written to the terminal if the | ||
| 35 | /// draw buffer is sent. | ||
| 36 | accumulated_newline_count: u16, | ||
| 39 | 37 | ||
| 40 | /// When the previous refresh was written to the terminal. | 38 | /// Accessed only by the update thread. |
| 41 | /// Used to compare with `refresh_rate_ms`. | 39 | draw_buffer: []u8, |
| 42 | prev_refresh_timestamp: u64 = undefined, | ||
| 43 | 40 | ||
| 44 | /// This buffer represents the maximum number of bytes written to the terminal | 41 | /// This is in a separate array from `node_storage` but with the same length so |
| 45 | /// with each refresh. | 42 | /// that it can be iterated over efficiently without trashing too much of the |
| 46 | output_buffer: [100]u8 = undefined, | 43 | /// CPU cache. |
| 44 | node_parents: []Node.Parent, | ||
| 45 | node_storage: []Node.Storage, | ||
| 46 | node_freelist: []Node.OptionalIndex, | ||
| 47 | node_freelist_first: Node.OptionalIndex, | ||
| 48 | node_end_index: u32, | ||
| 47 | 49 | ||
| 48 | /// How many nanoseconds between writing updates to the terminal. | 50 | pub const TerminalMode = union(enum) { |
| 49 | refresh_rate_ns: u64 = 50 * std.time.ns_per_ms, | 51 | off, |
| 52 | ansi_escape_codes, | ||
| 53 | /// This is not the same as being run on windows because other terminals | ||
| 54 | /// exist like MSYS/git-bash. | ||
| 55 | windows_api: if (is_windows) WindowsApi else void, | ||
| 50 | 56 | ||
| 51 | /// How many nanoseconds to keep the output hidden | 57 | pub const WindowsApi = struct { |
| 52 | initial_delay_ns: u64 = 500 * std.time.ns_per_ms, | 58 | /// The output code page of the console. |
| 53 | 59 | code_page: windows.UINT, | |
| 54 | done: bool = true, | 60 | }; |
| 55 | 61 | }; | |
| 56 | /// Protects the `refresh` function, as well as `node.recently_updated_child`. | ||
| 57 | /// Without this, callsites would call `Node.end` and then free `Node` memory | ||
| 58 | /// while it was still being accessed by the `refresh` function. | ||
| 59 | update_mutex: std.Thread.Mutex = .{}, | ||
| 60 | 62 | ||
| 61 | /// Keeps track of how many columns in the terminal have been output, so that | 63 | pub const Options = struct { |
| 62 | /// we can move the cursor back later. | 64 | /// User-provided buffer with static lifetime. |
| 63 | columns_written: usize = undefined, | 65 | /// |
| 66 | /// Used to store the entire write buffer sent to the terminal. Progress output will be truncated if it | ||
| 67 | /// cannot fit into this buffer which will look bad but not cause any malfunctions. | ||
| 68 | /// | ||
| 69 | /// Must be at least 200 bytes. | ||
| 70 | draw_buffer: []u8 = &default_draw_buffer, | ||
| 71 | /// How many nanoseconds between writing updates to the terminal. | ||
| 72 | refresh_rate_ns: u64 = 80 * std.time.ns_per_ms, | ||
| 73 | /// How many nanoseconds to keep the output hidden | ||
| 74 | initial_delay_ns: u64 = 200 * std.time.ns_per_ms, | ||
| 75 | /// If provided, causes the progress item to have a denominator. | ||
| 76 | /// 0 means unknown. | ||
| 77 | estimated_total_items: usize = 0, | ||
| 78 | root_name: []const u8 = "", | ||
| 79 | disable_printing: bool = false, | ||
| 80 | }; | ||
| 64 | 81 | ||
| 65 | /// Represents one unit of progress. Each node can have children nodes, or | 82 | /// Represents one unit of progress. Each node can have children nodes, or |
| 66 | /// one can use integers with `update`. | 83 | /// one can use integers with `update`. |
| 67 | pub const Node = struct { | 84 | pub const Node = struct { |
| 68 | context: *Progress, | 85 | index: OptionalIndex, |
| 69 | parent: ?*Node, | 86 | |
| 70 | name: []const u8, | 87 | pub const max_name_len = 40; |
| 71 | unit: []const u8 = "", | 88 | |
| 72 | /// Must be handled atomically to be thread-safe. | 89 | const Storage = extern struct { |
| 73 | recently_updated_child: ?*Node = null, | 90 | /// Little endian. |
| 74 | /// Must be handled atomically to be thread-safe. 0 means null. | 91 | completed_count: u32, |
| 75 | unprotected_estimated_total_items: usize, | 92 | /// 0 means unknown. |
| 76 | /// Must be handled atomically to be thread-safe. | 93 | /// Little endian. |
| 77 | unprotected_completed_items: usize, | 94 | estimated_total_count: u32, |
| 95 | name: [max_name_len]u8, | ||
| 96 | |||
| 97 | /// Not thread-safe. | ||
| 98 | fn getIpcFd(s: Storage) ?posix.fd_t { | ||
| 99 | return if (s.estimated_total_count == std.math.maxInt(u32)) switch (@typeInfo(posix.fd_t)) { | ||
| 100 | .Int => @bitCast(s.completed_count), | ||
| 101 | .Pointer => @ptrFromInt(s.completed_count), | ||
| 102 | else => @compileError("unsupported fd_t of " ++ @typeName(posix.fd_t)), | ||
| 103 | } else null; | ||
| 104 | } | ||
| 105 | |||
| 106 | /// Thread-safe. | ||
| 107 | fn setIpcFd(s: *Storage, fd: posix.fd_t) void { | ||
| 108 | const integer: u32 = switch (@typeInfo(posix.fd_t)) { | ||
| 109 | .Int => @bitCast(fd), | ||
| 110 | .Pointer => @intFromPtr(fd), | ||
| 111 | else => @compileError("unsupported fd_t of " ++ @typeName(posix.fd_t)), | ||
| 112 | }; | ||
| 113 | // `estimated_total_count` max int indicates the special state that | ||
| 114 | // causes `completed_count` to be treated as a file descriptor, so | ||
| 115 | // the order here matters. | ||
| 116 | @atomicStore(u32, &s.completed_count, integer, .monotonic); | ||
| 117 | @atomicStore(u32, &s.estimated_total_count, std.math.maxInt(u32), .release); | ||
| 118 | } | ||
| 119 | |||
| 120 | /// Not thread-safe. | ||
| 121 | fn byteSwap(s: *Storage) void { | ||
| 122 | s.completed_count = @byteSwap(s.completed_count); | ||
| 123 | s.estimated_total_count = @byteSwap(s.estimated_total_count); | ||
| 124 | } | ||
| 125 | |||
| 126 | comptime { | ||
| 127 | assert((@sizeOf(Storage) % 4) == 0); | ||
| 128 | } | ||
| 129 | }; | ||
| 130 | |||
| 131 | const Parent = enum(u8) { | ||
| 132 | /// Unallocated storage. | ||
| 133 | unused = std.math.maxInt(u8) - 1, | ||
| 134 | /// Indicates root node. | ||
| 135 | none = std.math.maxInt(u8), | ||
| 136 | /// Index into `node_storage`. | ||
| 137 | _, | ||
| 138 | |||
| 139 | fn unwrap(i: @This()) ?Index { | ||
| 140 | return switch (i) { | ||
| 141 | .unused, .none => return null, | ||
| 142 | else => @enumFromInt(@intFromEnum(i)), | ||
| 143 | }; | ||
| 144 | } | ||
| 145 | }; | ||
| 146 | |||
| 147 | pub const OptionalIndex = enum(u8) { | ||
| 148 | none = std.math.maxInt(u8), | ||
| 149 | /// Index into `node_storage`. | ||
| 150 | _, | ||
| 151 | |||
| 152 | pub fn unwrap(i: @This()) ?Index { | ||
| 153 | if (i == .none) return null; | ||
| 154 | return @enumFromInt(@intFromEnum(i)); | ||
| 155 | } | ||
| 156 | |||
| 157 | fn toParent(i: @This()) Parent { | ||
| 158 | assert(@intFromEnum(i) != @intFromEnum(Parent.unused)); | ||
| 159 | return @enumFromInt(@intFromEnum(i)); | ||
| 160 | } | ||
| 161 | }; | ||
| 162 | |||
| 163 | /// Index into `node_storage`. | ||
| 164 | pub const Index = enum(u8) { | ||
| 165 | _, | ||
| 166 | |||
| 167 | fn toParent(i: @This()) Parent { | ||
| 168 | assert(@intFromEnum(i) != @intFromEnum(Parent.unused)); | ||
| 169 | assert(@intFromEnum(i) != @intFromEnum(Parent.none)); | ||
| 170 | return @enumFromInt(@intFromEnum(i)); | ||
| 171 | } | ||
| 172 | |||
| 173 | pub fn toOptional(i: @This()) OptionalIndex { | ||
| 174 | return @enumFromInt(@intFromEnum(i)); | ||
| 175 | } | ||
| 176 | }; | ||
| 78 | 177 | ||
| 79 | /// Create a new child progress node. Thread-safe. | 178 | /// Create a new child progress node. Thread-safe. |
| 80 | /// Call `Node.end` when done. | 179 | /// |
| 81 | /// TODO solve https://github.com/ziglang/zig/issues/2765 and then change this | ||
| 82 | /// API to set `self.parent.recently_updated_child` with the return value. | ||
| 83 | /// Until that is fixed you probably want to call `activate` on the return value. | ||
| 84 | /// Passing 0 for `estimated_total_items` means unknown. | 180 | /// Passing 0 for `estimated_total_items` means unknown. |
| 85 | pub fn start(self: *Node, name: []const u8, estimated_total_items: usize) Node { | 181 | pub fn start(node: Node, name: []const u8, estimated_total_items: usize) Node { |
| 86 | return Node{ | 182 | if (noop_impl) { |
| 87 | .context = self.context, | 183 | assert(node.index == .none); |
| 88 | .parent = self, | 184 | return .{ .index = .none }; |
| 89 | .name = name, | 185 | } |
| 90 | .unprotected_estimated_total_items = estimated_total_items, | 186 | const node_index = node.index.unwrap() orelse return .{ .index = .none }; |
| 91 | .unprotected_completed_items = 0, | 187 | const parent = node_index.toParent(); |
| 92 | }; | 188 | |
| 189 | const freelist_head = &global_progress.node_freelist_first; | ||
| 190 | var opt_free_index = @atomicLoad(Node.OptionalIndex, freelist_head, .seq_cst); | ||
| 191 | while (opt_free_index.unwrap()) |free_index| { | ||
| 192 | const freelist_ptr = freelistByIndex(free_index); | ||
| 193 | opt_free_index = @cmpxchgWeak(Node.OptionalIndex, freelist_head, opt_free_index, freelist_ptr.*, .seq_cst, .seq_cst) orelse { | ||
| 194 | // We won the allocation race. | ||
| 195 | return init(free_index, parent, name, estimated_total_items); | ||
| 196 | }; | ||
| 197 | } | ||
| 198 | |||
| 199 | const free_index = @atomicRmw(u32, &global_progress.node_end_index, .Add, 1, .monotonic); | ||
| 200 | if (free_index >= global_progress.node_storage.len) { | ||
| 201 | // Ran out of node storage memory. Progress for this node will not be tracked. | ||
| 202 | _ = @atomicRmw(u32, &global_progress.node_end_index, .Sub, 1, .monotonic); | ||
| 203 | return .{ .index = .none }; | ||
| 204 | } | ||
| 205 | |||
| 206 | return init(@enumFromInt(free_index), parent, name, estimated_total_items); | ||
| 93 | } | 207 | } |
| 94 | 208 | ||
| 95 | /// This is the same as calling `start` and then `end` on the returned `Node`. Thread-safe. | 209 | /// This is the same as calling `start` and then `end` on the returned `Node`. Thread-safe. |
| 96 | pub fn completeOne(self: *Node) void { | 210 | pub fn completeOne(n: Node) void { |
| 97 | if (self.parent) |parent| { | 211 | const index = n.index.unwrap() orelse return; |
| 98 | @atomicStore(?*Node, &parent.recently_updated_child, self, .release); | 212 | const storage = storageByIndex(index); |
| 99 | } | 213 | _ = @atomicRmw(u32, &storage.completed_count, .Add, 1, .monotonic); |
| 100 | _ = @atomicRmw(usize, &self.unprotected_completed_items, .Add, 1, .monotonic); | 214 | } |
| 101 | self.context.maybeRefresh(); | 215 | |
| 216 | /// Thread-safe. | ||
| 217 | pub fn setCompletedItems(n: Node, completed_items: usize) void { | ||
| 218 | const index = n.index.unwrap() orelse return; | ||
| 219 | const storage = storageByIndex(index); | ||
| 220 | @atomicStore(u32, &storage.completed_count, std.math.lossyCast(u32, completed_items), .monotonic); | ||
| 221 | } | ||
| 222 | |||
| 223 | /// Thread-safe. 0 means unknown. | ||
| 224 | pub fn setEstimatedTotalItems(n: Node, count: usize) void { | ||
| 225 | const index = n.index.unwrap() orelse return; | ||
| 226 | const storage = storageByIndex(index); | ||
| 227 | // Avoid u32 max int which is used to indicate a special state. | ||
| 228 | const saturated = @min(std.math.maxInt(u32) - 1, count); | ||
| 229 | @atomicStore(u32, &storage.estimated_total_count, saturated, .monotonic); | ||
| 230 | } | ||
| 231 | |||
| 232 | /// Thread-safe. | ||
| 233 | pub fn increaseEstimatedTotalItems(n: Node, count: usize) void { | ||
| 234 | const index = n.index.unwrap() orelse return; | ||
| 235 | const storage = storageByIndex(index); | ||
| 236 | _ = @atomicRmw(u32, &storage.estimated_total_count, .Add, std.math.lossyCast(u32, count), .monotonic); | ||
| 102 | } | 237 | } |
| 103 | 238 | ||
| 104 | /// Finish a started `Node`. Thread-safe. | 239 | /// Finish a started `Node`. Thread-safe. |
| 105 | pub fn end(self: *Node) void { | 240 | pub fn end(n: Node) void { |
| 106 | self.context.maybeRefresh(); | 241 | if (noop_impl) { |
| 107 | if (self.parent) |parent| { | 242 | assert(n.index == .none); |
| 108 | { | 243 | return; |
| 109 | self.context.update_mutex.lock(); | 244 | } |
| 110 | defer self.context.update_mutex.unlock(); | 245 | const index = n.index.unwrap() orelse return; |
| 111 | _ = @cmpxchgStrong(?*Node, &parent.recently_updated_child, self, null, .monotonic, .monotonic); | 246 | const parent_ptr = parentByIndex(index); |
| 247 | if (parent_ptr.unwrap()) |parent_index| { | ||
| 248 | _ = @atomicRmw(u32, &storageByIndex(parent_index).completed_count, .Add, 1, .monotonic); | ||
| 249 | @atomicStore(Node.Parent, parent_ptr, .unused, .seq_cst); | ||
| 250 | |||
| 251 | const freelist_head = &global_progress.node_freelist_first; | ||
| 252 | var first = @atomicLoad(Node.OptionalIndex, freelist_head, .seq_cst); | ||
| 253 | while (true) { | ||
| 254 | freelistByIndex(index).* = first; | ||
| 255 | first = @cmpxchgWeak(Node.OptionalIndex, freelist_head, first, index.toOptional(), .seq_cst, .seq_cst) orelse break; | ||
| 112 | } | 256 | } |
| 113 | parent.completeOne(); | ||
| 114 | } else { | 257 | } else { |
| 115 | self.context.update_mutex.lock(); | 258 | @atomicStore(bool, &global_progress.done, true, .seq_cst); |
| 116 | defer self.context.update_mutex.unlock(); | 259 | global_progress.redraw_event.set(); |
| 117 | self.context.done = true; | 260 | if (global_progress.update_thread) |thread| thread.join(); |
| 118 | self.context.refreshWithHeldLock(); | ||
| 119 | } | 261 | } |
| 120 | } | 262 | } |
| 121 | 263 | ||
| 122 | /// Tell the parent node that this node is actively being worked on. Thread-safe. | 264 | /// Posix-only. Used by `std.process.Child`. Thread-safe. |
| 123 | pub fn activate(self: *Node) void { | 265 | pub fn setIpcFd(node: Node, fd: posix.fd_t) void { |
| 124 | if (self.parent) |parent| { | 266 | const index = node.index.unwrap() orelse return; |
| 125 | @atomicStore(?*Node, &parent.recently_updated_child, self, .release); | 267 | assert(fd >= 0); |
| 126 | self.context.maybeRefresh(); | 268 | assert(fd != posix.STDOUT_FILENO); |
| 127 | } | 269 | assert(fd != posix.STDIN_FILENO); |
| 270 | assert(fd != posix.STDERR_FILENO); | ||
| 271 | storageByIndex(index).setIpcFd(fd); | ||
| 128 | } | 272 | } |
| 129 | 273 | ||
| 130 | /// Thread-safe. | 274 | fn storageByIndex(index: Node.Index) *Node.Storage { |
| 131 | pub fn setName(self: *Node, name: []const u8) void { | 275 | return &global_progress.node_storage[@intFromEnum(index)]; |
| 132 | const progress = self.context; | ||
| 133 | progress.update_mutex.lock(); | ||
| 134 | defer progress.update_mutex.unlock(); | ||
| 135 | self.name = name; | ||
| 136 | if (self.parent) |parent| { | ||
| 137 | @atomicStore(?*Node, &parent.recently_updated_child, self, .release); | ||
| 138 | if (parent.parent) |grand_parent| { | ||
| 139 | @atomicStore(?*Node, &grand_parent.recently_updated_child, parent, .release); | ||
| 140 | } | ||
| 141 | if (progress.timer) |*timer| progress.maybeRefreshWithHeldLock(timer); | ||
| 142 | } | ||
| 143 | } | 276 | } |
| 144 | 277 | ||
| 145 | /// Thread-safe. | 278 | fn parentByIndex(index: Node.Index) *Node.Parent { |
| 146 | pub fn setUnit(self: *Node, unit: []const u8) void { | 279 | return &global_progress.node_parents[@intFromEnum(index)]; |
| 147 | const progress = self.context; | ||
| 148 | progress.update_mutex.lock(); | ||
| 149 | defer progress.update_mutex.unlock(); | ||
| 150 | self.unit = unit; | ||
| 151 | if (self.parent) |parent| { | ||
| 152 | @atomicStore(?*Node, &parent.recently_updated_child, self, .release); | ||
| 153 | if (parent.parent) |grand_parent| { | ||
| 154 | @atomicStore(?*Node, &grand_parent.recently_updated_child, parent, .release); | ||
| 155 | } | ||
| 156 | if (progress.timer) |*timer| progress.maybeRefreshWithHeldLock(timer); | ||
| 157 | } | ||
| 158 | } | 280 | } |
| 159 | 281 | ||
| 160 | /// Thread-safe. 0 means unknown. | 282 | fn freelistByIndex(index: Node.Index) *Node.OptionalIndex { |
| 161 | pub fn setEstimatedTotalItems(self: *Node, count: usize) void { | 283 | return &global_progress.node_freelist[@intFromEnum(index)]; |
| 162 | @atomicStore(usize, &self.unprotected_estimated_total_items, count, .monotonic); | ||
| 163 | } | 284 | } |
| 164 | 285 | ||
| 165 | /// Thread-safe. | 286 | fn init(free_index: Index, parent: Parent, name: []const u8, estimated_total_items: usize) Node { |
| 166 | pub fn setCompletedItems(self: *Node, completed_items: usize) void { | 287 | assert(parent != .unused); |
| 167 | @atomicStore(usize, &self.unprotected_completed_items, completed_items, .monotonic); | 288 | |
| 289 | const storage = storageByIndex(free_index); | ||
| 290 | storage.* = .{ | ||
| 291 | .completed_count = 0, | ||
| 292 | .estimated_total_count = std.math.lossyCast(u32, estimated_total_items), | ||
| 293 | .name = [1]u8{0} ** max_name_len, | ||
| 294 | }; | ||
| 295 | const name_len = @min(max_name_len, name.len); | ||
| 296 | @memcpy(storage.name[0..name_len], name[0..name_len]); | ||
| 297 | |||
| 298 | const parent_ptr = parentByIndex(free_index); | ||
| 299 | assert(parent_ptr.* == .unused); | ||
| 300 | @atomicStore(Node.Parent, parent_ptr, parent, .release); | ||
| 301 | |||
| 302 | return .{ .index = free_index.toOptional() }; | ||
| 168 | } | 303 | } |
| 169 | }; | 304 | }; |
| 170 | 305 | ||
| 171 | /// Create a new progress node. | 306 | var global_progress: Progress = .{ |
| 307 | .terminal = undefined, | ||
| 308 | .terminal_mode = .off, | ||
| 309 | .update_thread = null, | ||
| 310 | .redraw_event = .{}, | ||
| 311 | .refresh_rate_ns = undefined, | ||
| 312 | .initial_delay_ns = undefined, | ||
| 313 | .rows = 0, | ||
| 314 | .cols = 0, | ||
| 315 | .written_newline_count = 0, | ||
| 316 | .accumulated_newline_count = 0, | ||
| 317 | .draw_buffer = undefined, | ||
| 318 | .done = false, | ||
| 319 | |||
| 320 | .node_parents = &node_parents_buffer, | ||
| 321 | .node_storage = &node_storage_buffer, | ||
| 322 | .node_freelist = &node_freelist_buffer, | ||
| 323 | .node_freelist_first = .none, | ||
| 324 | .node_end_index = 0, | ||
| 325 | }; | ||
| 326 | |||
| 327 | const node_storage_buffer_len = 200; | ||
| 328 | var node_parents_buffer: [node_storage_buffer_len]Node.Parent = undefined; | ||
| 329 | var node_storage_buffer: [node_storage_buffer_len]Node.Storage = undefined; | ||
| 330 | var node_freelist_buffer: [node_storage_buffer_len]Node.OptionalIndex = undefined; | ||
| 331 | |||
| 332 | var default_draw_buffer: [4096]u8 = undefined; | ||
| 333 | |||
| 334 | var debug_start_trace = std.debug.Trace.init; | ||
| 335 | |||
| 336 | const noop_impl = builtin.single_threaded or switch (builtin.os.tag) { | ||
| 337 | .wasi, .freestanding => true, | ||
| 338 | else => false, | ||
| 339 | }; | ||
| 340 | |||
| 341 | /// Initializes a global Progress instance. | ||
| 342 | /// | ||
| 343 | /// Asserts there is only one global Progress instance. | ||
| 344 | /// | ||
| 172 | /// Call `Node.end` when done. | 345 | /// Call `Node.end` when done. |
| 173 | /// TODO solve https://github.com/ziglang/zig/issues/2765 and then change this | 346 | pub fn start(options: Options) Node { |
| 174 | /// API to return Progress rather than accept it as a parameter. | 347 | // Ensure there is only 1 global Progress object. |
| 175 | /// `estimated_total_items` value of 0 means unknown. | 348 | if (global_progress.node_end_index != 0) { |
| 176 | pub fn start(self: *Progress, name: []const u8, estimated_total_items: usize) *Node { | 349 | debug_start_trace.dump(); |
| 177 | const stderr = std.io.getStdErr(); | 350 | unreachable; |
| 178 | self.terminal = null; | 351 | } |
| 179 | if (stderr.supportsAnsiEscapeCodes()) { | 352 | debug_start_trace.add("first initialized here"); |
| 180 | self.terminal = stderr; | 353 | |
| 181 | self.supports_ansi_escape_codes = true; | 354 | @memset(global_progress.node_parents, .unused); |
| 182 | } else if (builtin.os.tag == .windows and stderr.isTty()) { | 355 | const root_node = Node.init(@enumFromInt(0), .none, options.root_name, options.estimated_total_items); |
| 183 | self.is_windows_terminal = true; | 356 | global_progress.done = false; |
| 184 | self.terminal = stderr; | 357 | global_progress.node_end_index = 1; |
| 185 | } else if (builtin.os.tag != .windows) { | 358 | |
| 186 | // we are in a "dumb" terminal like in acme or writing to a file | 359 | assert(options.draw_buffer.len >= 200); |
| 187 | self.terminal = stderr; | 360 | global_progress.draw_buffer = options.draw_buffer; |
| 188 | } | 361 | global_progress.refresh_rate_ns = options.refresh_rate_ns; |
| 189 | self.root = Node{ | 362 | global_progress.initial_delay_ns = options.initial_delay_ns; |
| 190 | .context = self, | 363 | |
| 191 | .parent = null, | 364 | if (noop_impl) |
| 192 | .name = name, | 365 | return .{ .index = .none }; |
| 193 | .unprotected_estimated_total_items = estimated_total_items, | 366 | |
| 194 | .unprotected_completed_items = 0, | 367 | if (std.process.parseEnvVarInt("ZIG_PROGRESS", u31, 10)) |ipc_fd| { |
| 368 | global_progress.update_thread = std.Thread.spawn(.{}, ipcThreadRun, .{ | ||
| 369 | @as(posix.fd_t, switch (@typeInfo(posix.fd_t)) { | ||
| 370 | .Int => ipc_fd, | ||
| 371 | .Pointer => @ptrFromInt(ipc_fd), | ||
| 372 | else => @compileError("unsupported fd_t of " ++ @typeName(posix.fd_t)), | ||
| 373 | }), | ||
| 374 | }) catch |err| { | ||
| 375 | std.log.warn("failed to spawn IPC thread for communicating progress to parent: {s}", .{@errorName(err)}); | ||
| 376 | return .{ .index = .none }; | ||
| 377 | }; | ||
| 378 | } else |env_err| switch (env_err) { | ||
| 379 | error.EnvironmentVariableNotFound => { | ||
| 380 | if (options.disable_printing) { | ||
| 381 | return .{ .index = .none }; | ||
| 382 | } | ||
| 383 | const stderr = std.io.getStdErr(); | ||
| 384 | global_progress.terminal = stderr; | ||
| 385 | if (stderr.supportsAnsiEscapeCodes()) { | ||
| 386 | global_progress.terminal_mode = .ansi_escape_codes; | ||
| 387 | } else if (is_windows and stderr.isTty()) { | ||
| 388 | global_progress.terminal_mode = TerminalMode{ .windows_api = .{ | ||
| 389 | .code_page = windows.kernel32.GetConsoleOutputCP(), | ||
| 390 | } }; | ||
| 391 | } | ||
| 392 | |||
| 393 | if (global_progress.terminal_mode == .off) { | ||
| 394 | return .{ .index = .none }; | ||
| 395 | } | ||
| 396 | |||
| 397 | if (have_sigwinch) { | ||
| 398 | var act: posix.Sigaction = .{ | ||
| 399 | .handler = .{ .sigaction = handleSigWinch }, | ||
| 400 | .mask = posix.empty_sigset, | ||
| 401 | .flags = (posix.SA.SIGINFO | posix.SA.RESTART), | ||
| 402 | }; | ||
| 403 | posix.sigaction(posix.SIG.WINCH, &act, null) catch |err| { | ||
| 404 | std.log.warn("failed to install SIGWINCH signal handler for noticing terminal resizes: {s}", .{@errorName(err)}); | ||
| 405 | }; | ||
| 406 | } | ||
| 407 | |||
| 408 | if (switch (global_progress.terminal_mode) { | ||
| 409 | .off => unreachable, // handled a few lines above | ||
| 410 | .ansi_escape_codes => std.Thread.spawn(.{}, updateThreadRun, .{}), | ||
| 411 | .windows_api => if (is_windows) std.Thread.spawn(.{}, windowsApiUpdateThreadRun, .{}) else unreachable, | ||
| 412 | }) |thread| { | ||
| 413 | global_progress.update_thread = thread; | ||
| 414 | } else |err| { | ||
| 415 | std.log.warn("unable to spawn thread for printing progress to terminal: {s}", .{@errorName(err)}); | ||
| 416 | return .{ .index = .none }; | ||
| 417 | } | ||
| 418 | }, | ||
| 419 | else => |e| { | ||
| 420 | std.log.warn("invalid ZIG_PROGRESS file descriptor integer: {s}", .{@errorName(e)}); | ||
| 421 | return .{ .index = .none }; | ||
| 422 | }, | ||
| 423 | } | ||
| 424 | |||
| 425 | return root_node; | ||
| 426 | } | ||
| 427 | |||
| 428 | /// Returns whether a resize is needed to learn the terminal size. | ||
| 429 | fn wait(timeout_ns: u64) bool { | ||
| 430 | const resize_flag = if (global_progress.redraw_event.timedWait(timeout_ns)) |_| | ||
| 431 | true | ||
| 432 | else |err| switch (err) { | ||
| 433 | error.Timeout => false, | ||
| 195 | }; | 434 | }; |
| 196 | self.columns_written = 0; | 435 | global_progress.redraw_event.reset(); |
| 197 | self.prev_refresh_timestamp = 0; | 436 | return resize_flag or (global_progress.cols == 0); |
| 198 | self.timer = std.time.Timer.start() catch null; | ||
| 199 | self.done = false; | ||
| 200 | return &self.root; | ||
| 201 | } | 437 | } |
| 202 | 438 | ||
| 203 | /// Updates the terminal if enough time has passed since last update. Thread-safe. | 439 | fn updateThreadRun() void { |
| 204 | pub fn maybeRefresh(self: *Progress) void { | 440 | // Store this data in the thread so that it does not need to be part of the |
| 205 | if (self.timer) |*timer| { | 441 | // linker data of the main executable. |
| 206 | if (!self.update_mutex.tryLock()) return; | 442 | var serialized_buffer: Serialized.Buffer = undefined; |
| 207 | defer self.update_mutex.unlock(); | 443 | |
| 208 | maybeRefreshWithHeldLock(self, timer); | 444 | { |
| 445 | const resize_flag = wait(global_progress.initial_delay_ns); | ||
| 446 | if (@atomicLoad(bool, &global_progress.done, .seq_cst)) return; | ||
| 447 | maybeUpdateSize(resize_flag); | ||
| 448 | |||
| 449 | const buffer = computeRedraw(&serialized_buffer); | ||
| 450 | if (stderr_mutex.tryLock()) { | ||
| 451 | defer stderr_mutex.unlock(); | ||
| 452 | write(buffer) catch return; | ||
| 453 | } | ||
| 454 | } | ||
| 455 | |||
| 456 | while (true) { | ||
| 457 | const resize_flag = wait(global_progress.refresh_rate_ns); | ||
| 458 | |||
| 459 | if (@atomicLoad(bool, &global_progress.done, .seq_cst)) { | ||
| 460 | stderr_mutex.lock(); | ||
| 461 | defer stderr_mutex.unlock(); | ||
| 462 | return clearWrittenWithEscapeCodes() catch {}; | ||
| 463 | } | ||
| 464 | |||
| 465 | maybeUpdateSize(resize_flag); | ||
| 466 | |||
| 467 | const buffer = computeRedraw(&serialized_buffer); | ||
| 468 | if (stderr_mutex.tryLock()) { | ||
| 469 | defer stderr_mutex.unlock(); | ||
| 470 | write(buffer) catch return; | ||
| 471 | } | ||
| 472 | } | ||
| 473 | } | ||
| 474 | |||
| 475 | fn windowsApiUpdateThreadRun() void { | ||
| 476 | var serialized_buffer: Serialized.Buffer = undefined; | ||
| 477 | |||
| 478 | { | ||
| 479 | const resize_flag = wait(global_progress.initial_delay_ns); | ||
| 480 | if (@atomicLoad(bool, &global_progress.done, .seq_cst)) return; | ||
| 481 | maybeUpdateSize(resize_flag); | ||
| 482 | |||
| 483 | const buffer = computeRedraw(&serialized_buffer); | ||
| 484 | if (stderr_mutex.tryLock()) { | ||
| 485 | defer stderr_mutex.unlock(); | ||
| 486 | write(buffer) catch return; | ||
| 487 | } | ||
| 488 | } | ||
| 489 | |||
| 490 | while (true) { | ||
| 491 | const resize_flag = wait(global_progress.refresh_rate_ns); | ||
| 492 | |||
| 493 | if (@atomicLoad(bool, &global_progress.done, .seq_cst)) { | ||
| 494 | stderr_mutex.lock(); | ||
| 495 | defer stderr_mutex.unlock(); | ||
| 496 | return clearWrittenWindowsApi() catch {}; | ||
| 497 | } | ||
| 498 | |||
| 499 | maybeUpdateSize(resize_flag); | ||
| 500 | |||
| 501 | const buffer = computeRedraw(&serialized_buffer); | ||
| 502 | if (stderr_mutex.tryLock()) { | ||
| 503 | defer stderr_mutex.unlock(); | ||
| 504 | clearWrittenWindowsApi() catch return; | ||
| 505 | write(buffer) catch return; | ||
| 506 | } | ||
| 209 | } | 507 | } |
| 210 | } | 508 | } |
| 211 | 509 | ||
| 212 | fn maybeRefreshWithHeldLock(self: *Progress, timer: *std.time.Timer) void { | 510 | /// Allows the caller to freely write to stderr until `unlockStdErr` is called. |
| 213 | const now = timer.read(); | 511 | /// |
| 214 | if (now < self.initial_delay_ns) return; | 512 | /// During the lock, any `std.Progress` information is cleared from the terminal. |
| 215 | // TODO I have observed this to happen sometimes. I think we need to follow Rust's | 513 | pub fn lockStdErr() void { |
| 216 | // lead and guarantee monotonically increasing times in the std lib itself. | 514 | stderr_mutex.lock(); |
| 217 | if (now < self.prev_refresh_timestamp) return; | 515 | clearWrittenWithEscapeCodes() catch {}; |
| 218 | if (now - self.prev_refresh_timestamp < self.refresh_rate_ns) return; | 516 | } |
| 219 | return self.refreshWithHeldLock(); | 517 | |
| 518 | pub fn unlockStdErr() void { | ||
| 519 | stderr_mutex.unlock(); | ||
| 220 | } | 520 | } |
| 221 | 521 | ||
| 222 | /// Updates the terminal and resets `self.next_refresh_timestamp`. Thread-safe. | 522 | fn ipcThreadRun(fd: posix.fd_t) anyerror!void { |
| 223 | pub fn refresh(self: *Progress) void { | 523 | // Store this data in the thread so that it does not need to be part of the |
| 224 | if (!self.update_mutex.tryLock()) return; | 524 | // linker data of the main executable. |
| 225 | defer self.update_mutex.unlock(); | 525 | var serialized_buffer: Serialized.Buffer = undefined; |
| 526 | |||
| 527 | { | ||
| 528 | _ = wait(global_progress.initial_delay_ns); | ||
| 226 | 529 | ||
| 227 | return self.refreshWithHeldLock(); | 530 | if (@atomicLoad(bool, &global_progress.done, .seq_cst)) |
| 531 | return; | ||
| 532 | |||
| 533 | const serialized = serialize(&serialized_buffer); | ||
| 534 | writeIpc(fd, serialized) catch |err| switch (err) { | ||
| 535 | error.BrokenPipe => return, | ||
| 536 | }; | ||
| 537 | } | ||
| 538 | |||
| 539 | while (true) { | ||
| 540 | _ = wait(global_progress.refresh_rate_ns); | ||
| 541 | |||
| 542 | if (@atomicLoad(bool, &global_progress.done, .seq_cst)) | ||
| 543 | return; | ||
| 544 | |||
| 545 | const serialized = serialize(&serialized_buffer); | ||
| 546 | writeIpc(fd, serialized) catch |err| switch (err) { | ||
| 547 | error.BrokenPipe => return, | ||
| 548 | }; | ||
| 549 | } | ||
| 228 | } | 550 | } |
| 229 | 551 | ||
| 230 | fn clearWithHeldLock(p: *Progress, end_ptr: *usize) void { | 552 | const start_sync = "\x1b[?2026h"; |
| 231 | const file = p.terminal orelse return; | 553 | const up_one_line = "\x1bM"; |
| 232 | var end = end_ptr.*; | 554 | const clear = "\x1b[J"; |
| 233 | if (p.columns_written > 0) { | 555 | const save = "\x1b7"; |
| 234 | // restore the cursor position by moving the cursor | 556 | const restore = "\x1b8"; |
| 235 | // `columns_written` cells to the left, then clear the rest of the | 557 | const finish_sync = "\x1b[?2026l"; |
| 236 | // line | ||
| 237 | if (p.supports_ansi_escape_codes) { | ||
| 238 | end += (std.fmt.bufPrint(p.output_buffer[end..], "\x1b[{d}D", .{p.columns_written}) catch unreachable).len; | ||
| 239 | end += (std.fmt.bufPrint(p.output_buffer[end..], "\x1b[0K", .{}) catch unreachable).len; | ||
| 240 | } else if (builtin.os.tag == .windows) winapi: { | ||
| 241 | std.debug.assert(p.is_windows_terminal); | ||
| 242 | |||
| 243 | var info: windows.CONSOLE_SCREEN_BUFFER_INFO = undefined; | ||
| 244 | if (windows.kernel32.GetConsoleScreenBufferInfo(file.handle, &info) != windows.TRUE) { | ||
| 245 | // stop trying to write to this file | ||
| 246 | p.terminal = null; | ||
| 247 | break :winapi; | ||
| 248 | } | ||
| 249 | 558 | ||
| 250 | var cursor_pos = windows.COORD{ | 559 | const TreeSymbol = enum { |
| 251 | .X = info.dwCursorPosition.X - @as(windows.SHORT, @intCast(p.columns_written)), | 560 | /// ├─ |
| 252 | .Y = info.dwCursorPosition.Y, | 561 | tee, |
| 562 | /// │ | ||
| 563 | line, | ||
| 564 | /// └─ | ||
| 565 | langle, | ||
| 566 | |||
| 567 | const Encoding = enum { | ||
| 568 | ansi_escapes, | ||
| 569 | code_page_437, | ||
| 570 | utf8, | ||
| 571 | ascii, | ||
| 572 | }; | ||
| 573 | |||
| 574 | /// The escape sequence representation as a string literal | ||
| 575 | fn escapeSeq(symbol: TreeSymbol) *const [9:0]u8 { | ||
| 576 | return switch (symbol) { | ||
| 577 | .tee => "\x1B\x28\x30\x74\x71\x1B\x28\x42 ", | ||
| 578 | .line => "\x1B\x28\x30\x78\x1B\x28\x42 ", | ||
| 579 | .langle => "\x1B\x28\x30\x6d\x71\x1B\x28\x42 ", | ||
| 580 | }; | ||
| 581 | } | ||
| 582 | |||
| 583 | fn bytes(symbol: TreeSymbol, encoding: Encoding) []const u8 { | ||
| 584 | return switch (encoding) { | ||
| 585 | .ansi_escapes => escapeSeq(symbol), | ||
| 586 | .code_page_437 => switch (symbol) { | ||
| 587 | .tee => "\xC3\xC4 ", | ||
| 588 | .line => "\xB3 ", | ||
| 589 | .langle => "\xC0\xC4 ", | ||
| 590 | }, | ||
| 591 | .utf8 => switch (symbol) { | ||
| 592 | .tee => "├─ ", | ||
| 593 | .line => "│ ", | ||
| 594 | .langle => "└─ ", | ||
| 595 | }, | ||
| 596 | .ascii => switch (symbol) { | ||
| 597 | .tee => "|- ", | ||
| 598 | .line => "| ", | ||
| 599 | .langle => "+- ", | ||
| 600 | }, | ||
| 601 | }; | ||
| 602 | } | ||
| 603 | |||
| 604 | fn maxByteLen(symbol: TreeSymbol) usize { | ||
| 605 | var max: usize = 0; | ||
| 606 | inline for (@typeInfo(Encoding).Enum.fields) |field| { | ||
| 607 | const len = symbol.bytes(@field(Encoding, field.name)).len; | ||
| 608 | max = @max(max, len); | ||
| 609 | } | ||
| 610 | return max; | ||
| 611 | } | ||
| 612 | }; | ||
| 613 | |||
| 614 | fn appendTreeSymbol(symbol: TreeSymbol, buf: []u8, start_i: usize) usize { | ||
| 615 | switch (global_progress.terminal_mode) { | ||
| 616 | .off => unreachable, | ||
| 617 | .ansi_escape_codes => { | ||
| 618 | const bytes = symbol.escapeSeq(); | ||
| 619 | buf[start_i..][0..bytes.len].* = bytes.*; | ||
| 620 | return start_i + bytes.len; | ||
| 621 | }, | ||
| 622 | .windows_api => |windows_api| { | ||
| 623 | const bytes = if (!is_windows) unreachable else switch (windows_api.code_page) { | ||
| 624 | // Code page 437 is the default code page and contains the box drawing symbols | ||
| 625 | 437 => symbol.bytes(.code_page_437), | ||
| 626 | // UTF-8 | ||
| 627 | 65001 => symbol.bytes(.utf8), | ||
| 628 | // Fall back to ASCII approximation | ||
| 629 | else => symbol.bytes(.ascii), | ||
| 253 | }; | 630 | }; |
| 631 | @memcpy(buf[start_i..][0..bytes.len], bytes); | ||
| 632 | return start_i + bytes.len; | ||
| 633 | }, | ||
| 634 | } | ||
| 635 | } | ||
| 254 | 636 | ||
| 255 | if (cursor_pos.X < 0) | 637 | fn clearWrittenWithEscapeCodes() anyerror!void { |
| 256 | cursor_pos.X = 0; | 638 | if (global_progress.written_newline_count == 0) return; |
| 257 | 639 | ||
| 258 | const fill_chars = @as(windows.DWORD, @intCast(info.dwSize.X - cursor_pos.X)); | 640 | var i: usize = 0; |
| 259 | 641 | const buf = global_progress.draw_buffer; | |
| 260 | var written: windows.DWORD = undefined; | 642 | |
| 261 | if (windows.kernel32.FillConsoleOutputAttribute( | 643 | buf[i..][0..start_sync.len].* = start_sync.*; |
| 262 | file.handle, | 644 | i += start_sync.len; |
| 263 | info.wAttributes, | 645 | |
| 264 | fill_chars, | 646 | i = computeClear(buf, i); |
| 265 | cursor_pos, | 647 | |
| 266 | &written, | 648 | buf[i..][0..finish_sync.len].* = finish_sync.*; |
| 267 | ) != windows.TRUE) { | 649 | i += finish_sync.len; |
| 268 | // stop trying to write to this file | 650 | |
| 269 | p.terminal = null; | 651 | global_progress.accumulated_newline_count = 0; |
| 270 | break :winapi; | 652 | try write(buf[0..i]); |
| 271 | } | 653 | } |
| 272 | if (windows.kernel32.FillConsoleOutputCharacterW( | 654 | |
| 273 | file.handle, | 655 | fn computeClear(buf: []u8, start_i: usize) usize { |
| 274 | ' ', | 656 | var i = start_i; |
| 275 | fill_chars, | 657 | |
| 276 | cursor_pos, | 658 | const prev_nl_n = global_progress.written_newline_count; |
| 277 | &written, | 659 | if (prev_nl_n > 0) { |
| 278 | ) != windows.TRUE) { | 660 | buf[i] = '\r'; |
| 279 | // stop trying to write to this file | 661 | i += 1; |
| 280 | p.terminal = null; | 662 | for (0..prev_nl_n) |_| { |
| 281 | break :winapi; | 663 | buf[i..][0..up_one_line.len].* = up_one_line.*; |
| 282 | } | 664 | i += up_one_line.len; |
| 283 | if (windows.kernel32.SetConsoleCursorPosition(file.handle, cursor_pos) != windows.TRUE) { | 665 | } |
| 284 | // stop trying to write to this file | 666 | } |
| 285 | p.terminal = null; | 667 | |
| 286 | break :winapi; | 668 | buf[i..][0..clear.len].* = clear.*; |
| 669 | i += clear.len; | ||
| 670 | |||
| 671 | return i; | ||
| 672 | } | ||
| 673 | |||
| 674 | /// U+25BA or â–º | ||
| 675 | const windows_api_start_marker = 0x25BA; | ||
| 676 | |||
| 677 | fn clearWrittenWindowsApi() error{Unexpected}!void { | ||
| 678 | // This uses a 'marker' strategy. The idea is: | ||
| 679 | // - Always write a marker (in this case U+25BA or â–º) at the beginning of the progress | ||
| 680 | // - Get the current cursor position (at the end of the progress) | ||
| 681 | // - Subtract the number of lines written to get the expected start of the progress | ||
| 682 | // - Check to see if the first character at the start of the progress is the marker | ||
| 683 | // - If it's not the marker, keep checking the line before until we find it | ||
| 684 | // - Clear the screen from that position down, and set the cursor position to the start | ||
| 685 | // | ||
| 686 | // This strategy works even if there is line wrapping, and can handle the window | ||
| 687 | // being resized/scrolled arbitrarily. | ||
| 688 | // | ||
| 689 | // Notes: | ||
| 690 | // - Ideally, the marker would be a zero-width character, but the Windows console | ||
| 691 | // doesn't seem to support rendering zero-width characters (they show up as a space) | ||
| 692 | // - This same marker idea could technically be done with an attribute instead | ||
| 693 | // (https://learn.microsoft.com/en-us/windows/console/console-screen-buffers#character-attributes) | ||
| 694 | // but it must be a valid attribute and it actually needs to apply to the first | ||
| 695 | // character in order to be readable via ReadConsoleOutputAttribute. It doesn't seem | ||
| 696 | // like any of the available attributes are invisible/benign. | ||
| 697 | const prev_nl_n = global_progress.written_newline_count; | ||
| 698 | if (prev_nl_n > 0) { | ||
| 699 | const handle = global_progress.terminal.handle; | ||
| 700 | const screen_area = @as(windows.DWORD, global_progress.cols) * global_progress.rows; | ||
| 701 | |||
| 702 | var console_info: windows.CONSOLE_SCREEN_BUFFER_INFO = undefined; | ||
| 703 | if (windows.kernel32.GetConsoleScreenBufferInfo(handle, &console_info) == 0) { | ||
| 704 | return error.Unexpected; | ||
| 705 | } | ||
| 706 | const cursor_pos = console_info.dwCursorPosition; | ||
| 707 | const expected_y = cursor_pos.Y - @as(i16, @intCast(prev_nl_n)); | ||
| 708 | var start_pos = windows.COORD{ .X = 0, .Y = expected_y }; | ||
| 709 | while (start_pos.Y >= 0) { | ||
| 710 | var wchar: [1]u16 = undefined; | ||
| 711 | var num_console_chars_read: windows.DWORD = undefined; | ||
| 712 | if (windows.kernel32.ReadConsoleOutputCharacterW(handle, &wchar, wchar.len, start_pos, &num_console_chars_read) == 0) { | ||
| 713 | return error.Unexpected; | ||
| 287 | } | 714 | } |
| 715 | |||
| 716 | if (wchar[0] == windows_api_start_marker) break; | ||
| 717 | start_pos.Y -= 1; | ||
| 288 | } else { | 718 | } else { |
| 289 | // we are in a "dumb" terminal like in acme or writing to a file | 719 | // If we couldn't find the marker, then just assume that no lines wrapped |
| 290 | p.output_buffer[end] = '\n'; | 720 | start_pos = .{ .X = 0, .Y = expected_y }; |
| 291 | end += 1; | 721 | } |
| 722 | var num_chars_written: windows.DWORD = undefined; | ||
| 723 | if (windows.kernel32.FillConsoleOutputCharacterW(handle, ' ', screen_area, start_pos, &num_chars_written) == 0) { | ||
| 724 | return error.Unexpected; | ||
| 725 | } | ||
| 726 | if (windows.kernel32.SetConsoleCursorPosition(handle, start_pos) == 0) { | ||
| 727 | return error.Unexpected; | ||
| 292 | } | 728 | } |
| 293 | |||
| 294 | p.columns_written = 0; | ||
| 295 | } | 729 | } |
| 296 | end_ptr.* = end; | ||
| 297 | } | 730 | } |
| 298 | 731 | ||
| 299 | fn refreshWithHeldLock(self: *Progress) void { | 732 | const Children = struct { |
| 300 | const is_dumb = !self.supports_ansi_escape_codes and !self.is_windows_terminal; | 733 | child: Node.OptionalIndex, |
| 301 | if (is_dumb and self.dont_print_on_dumb) return; | 734 | sibling: Node.OptionalIndex, |
| 735 | }; | ||
| 736 | |||
| 737 | const Serialized = struct { | ||
| 738 | parents: []Node.Parent, | ||
| 739 | storage: []Node.Storage, | ||
| 302 | 740 | ||
| 303 | const file = self.terminal orelse return; | 741 | const Buffer = struct { |
| 742 | parents: [node_storage_buffer_len]Node.Parent, | ||
| 743 | storage: [node_storage_buffer_len]Node.Storage, | ||
| 744 | map: [node_storage_buffer_len]Node.Index, | ||
| 304 | 745 | ||
| 305 | var end: usize = 0; | 746 | parents_copy: [node_storage_buffer_len]Node.Parent, |
| 306 | clearWithHeldLock(self, &end); | 747 | storage_copy: [node_storage_buffer_len]Node.Storage, |
| 748 | ipc_metadata_copy: [node_storage_buffer_len]SavedMetadata, | ||
| 307 | 749 | ||
| 308 | if (!self.done) { | 750 | ipc_metadata: [node_storage_buffer_len]SavedMetadata, |
| 309 | var need_ellipse = false; | 751 | }; |
| 310 | var maybe_node: ?*Node = &self.root; | 752 | }; |
| 311 | while (maybe_node) |node| { | 753 | |
| 312 | if (need_ellipse) { | 754 | fn serialize(serialized_buffer: *Serialized.Buffer) Serialized { |
| 313 | self.bufWrite(&end, "... ", .{}); | 755 | var serialized_len: usize = 0; |
| 756 | var any_ipc = false; | ||
| 757 | |||
| 758 | // Iterate all of the nodes and construct a serializable copy of the state that can be examined | ||
| 759 | // without atomics. | ||
| 760 | const end_index = @atomicLoad(u32, &global_progress.node_end_index, .monotonic); | ||
| 761 | const node_parents = global_progress.node_parents[0..end_index]; | ||
| 762 | const node_storage = global_progress.node_storage[0..end_index]; | ||
| 763 | for (node_parents, node_storage, 0..) |*parent_ptr, *storage_ptr, i| { | ||
| 764 | var begin_parent = @atomicLoad(Node.Parent, parent_ptr, .acquire); | ||
| 765 | while (begin_parent != .unused) { | ||
| 766 | const dest_storage = &serialized_buffer.storage[serialized_len]; | ||
| 767 | @memcpy(&dest_storage.name, &storage_ptr.name); | ||
| 768 | dest_storage.estimated_total_count = @atomicLoad(u32, &storage_ptr.estimated_total_count, .acquire); | ||
| 769 | dest_storage.completed_count = @atomicLoad(u32, &storage_ptr.completed_count, .monotonic); | ||
| 770 | const end_parent = @atomicLoad(Node.Parent, parent_ptr, .acquire); | ||
| 771 | if (begin_parent == end_parent) { | ||
| 772 | any_ipc = any_ipc or (dest_storage.getIpcFd() != null); | ||
| 773 | serialized_buffer.parents[serialized_len] = begin_parent; | ||
| 774 | serialized_buffer.map[i] = @enumFromInt(serialized_len); | ||
| 775 | serialized_len += 1; | ||
| 776 | break; | ||
| 314 | } | 777 | } |
| 315 | need_ellipse = false; | 778 | |
| 316 | const eti = @atomicLoad(usize, &node.unprotected_estimated_total_items, .monotonic); | 779 | begin_parent = end_parent; |
| 317 | const completed_items = @atomicLoad(usize, &node.unprotected_completed_items, .monotonic); | 780 | } |
| 318 | const current_item = completed_items + 1; | 781 | } |
| 319 | if (node.name.len != 0 or eti > 0) { | 782 | |
| 320 | if (node.name.len != 0) { | 783 | // Remap parents to point inside serialized arrays. |
| 321 | self.bufWrite(&end, "{s}", .{node.name}); | 784 | for (serialized_buffer.parents[0..serialized_len]) |*parent| { |
| 322 | need_ellipse = true; | 785 | parent.* = switch (parent.*) { |
| 323 | } | 786 | .unused => unreachable, |
| 324 | if (eti > 0) { | 787 | .none => .none, |
| 325 | if (need_ellipse) self.bufWrite(&end, " ", .{}); | 788 | _ => |p| serialized_buffer.map[@intFromEnum(p)].toParent(), |
| 326 | self.bufWrite(&end, "[{d}/{d}{s}] ", .{ current_item, eti, node.unit }); | 789 | }; |
| 327 | need_ellipse = false; | 790 | } |
| 328 | } else if (completed_items != 0) { | 791 | |
| 329 | if (need_ellipse) self.bufWrite(&end, " ", .{}); | 792 | // Find nodes which correspond to child processes. |
| 330 | self.bufWrite(&end, "[{d}{s}] ", .{ current_item, node.unit }); | 793 | if (any_ipc) |
| 331 | need_ellipse = false; | 794 | serialized_len = serializeIpc(serialized_len, serialized_buffer); |
| 795 | |||
| 796 | return .{ | ||
| 797 | .parents = serialized_buffer.parents[0..serialized_len], | ||
| 798 | .storage = serialized_buffer.storage[0..serialized_len], | ||
| 799 | }; | ||
| 800 | } | ||
| 801 | |||
| 802 | const SavedMetadata = struct { | ||
| 803 | ipc_fd: u16, | ||
| 804 | main_index: u8, | ||
| 805 | start_index: u8, | ||
| 806 | nodes_len: u8, | ||
| 807 | |||
| 808 | fn getIpcFd(metadata: SavedMetadata) posix.fd_t { | ||
| 809 | return if (is_windows) | ||
| 810 | @ptrFromInt(@as(usize, metadata.ipc_fd) << 2) | ||
| 811 | else | ||
| 812 | metadata.ipc_fd; | ||
| 813 | } | ||
| 814 | |||
| 815 | fn setIpcFd(fd: posix.fd_t) u16 { | ||
| 816 | return @intCast(if (is_windows) | ||
| 817 | @shrExact(@intFromPtr(fd), 2) | ||
| 818 | else | ||
| 819 | fd); | ||
| 820 | } | ||
| 821 | }; | ||
| 822 | |||
| 823 | var ipc_metadata_len: u8 = 0; | ||
| 824 | var remaining_read_trash_bytes: usize = 0; | ||
| 825 | |||
| 826 | fn serializeIpc(start_serialized_len: usize, serialized_buffer: *Serialized.Buffer) usize { | ||
| 827 | const ipc_metadata_copy = &serialized_buffer.ipc_metadata_copy; | ||
| 828 | const ipc_metadata = &serialized_buffer.ipc_metadata; | ||
| 829 | |||
| 830 | var serialized_len = start_serialized_len; | ||
| 831 | var pipe_buf: [2 * 4096]u8 align(4) = undefined; | ||
| 832 | |||
| 833 | const old_ipc_metadata = ipc_metadata_copy[0..ipc_metadata_len]; | ||
| 834 | ipc_metadata_len = 0; | ||
| 835 | |||
| 836 | main_loop: for ( | ||
| 837 | serialized_buffer.parents[0..serialized_len], | ||
| 838 | serialized_buffer.storage[0..serialized_len], | ||
| 839 | 0.., | ||
| 840 | ) |main_parent, *main_storage, main_index| { | ||
| 841 | if (main_parent == .unused) continue; | ||
| 842 | const fd = main_storage.getIpcFd() orelse continue; | ||
| 843 | var bytes_read: usize = 0; | ||
| 844 | while (true) { | ||
| 845 | const n = posix.read(fd, pipe_buf[bytes_read..]) catch |err| switch (err) { | ||
| 846 | error.WouldBlock => break, | ||
| 847 | else => |e| { | ||
| 848 | std.log.debug("failed to read child progress data: {s}", .{@errorName(e)}); | ||
| 849 | main_storage.completed_count = 0; | ||
| 850 | main_storage.estimated_total_count = 0; | ||
| 851 | continue :main_loop; | ||
| 852 | }, | ||
| 853 | }; | ||
| 854 | if (n == 0) break; | ||
| 855 | if (remaining_read_trash_bytes > 0) { | ||
| 856 | assert(bytes_read == 0); | ||
| 857 | if (remaining_read_trash_bytes >= n) { | ||
| 858 | remaining_read_trash_bytes -= n; | ||
| 859 | continue; | ||
| 332 | } | 860 | } |
| 861 | const src = pipe_buf[remaining_read_trash_bytes..n]; | ||
| 862 | std.mem.copyForwards(u8, &pipe_buf, src); | ||
| 863 | remaining_read_trash_bytes = 0; | ||
| 864 | bytes_read = src.len; | ||
| 865 | continue; | ||
| 333 | } | 866 | } |
| 334 | maybe_node = @atomicLoad(?*Node, &node.recently_updated_child, .acquire); | 867 | bytes_read += n; |
| 335 | } | 868 | } |
| 336 | if (need_ellipse) { | 869 | // Ignore all but the last message on the pipe. |
| 337 | self.bufWrite(&end, "... ", .{}); | 870 | var input: []u8 = pipe_buf[0..bytes_read]; |
| 871 | if (input.len == 0) { | ||
| 872 | serialized_len = useSavedIpcData(serialized_len, serialized_buffer, main_storage, main_index, old_ipc_metadata); | ||
| 873 | continue; | ||
| 874 | } | ||
| 875 | |||
| 876 | const storage, const parents = while (true) { | ||
| 877 | const subtree_len: usize = input[0]; | ||
| 878 | const expected_bytes = 1 + subtree_len * (@sizeOf(Node.Storage) + @sizeOf(Node.Parent)); | ||
| 879 | if (input.len < expected_bytes) { | ||
| 880 | // Ignore short reads. We'll handle the next full message when it comes instead. | ||
| 881 | assert(remaining_read_trash_bytes == 0); | ||
| 882 | remaining_read_trash_bytes = expected_bytes - input.len; | ||
| 883 | serialized_len = useSavedIpcData(serialized_len, serialized_buffer, main_storage, main_index, old_ipc_metadata); | ||
| 884 | continue :main_loop; | ||
| 885 | } | ||
| 886 | if (input.len > expected_bytes) { | ||
| 887 | input = input[expected_bytes..]; | ||
| 888 | continue; | ||
| 889 | } | ||
| 890 | const storage_bytes = input[1..][0 .. subtree_len * @sizeOf(Node.Storage)]; | ||
| 891 | const parents_bytes = input[1 + storage_bytes.len ..][0 .. subtree_len * @sizeOf(Node.Parent)]; | ||
| 892 | break .{ | ||
| 893 | std.mem.bytesAsSlice(Node.Storage, storage_bytes), | ||
| 894 | std.mem.bytesAsSlice(Node.Parent, parents_bytes), | ||
| 895 | }; | ||
| 896 | }; | ||
| 897 | |||
| 898 | const nodes_len: u8 = @intCast(@min(parents.len - 1, serialized_buffer.storage.len - serialized_len)); | ||
| 899 | |||
| 900 | // Remember in case the pipe is empty on next update. | ||
| 901 | ipc_metadata[ipc_metadata_len] = .{ | ||
| 902 | .ipc_fd = SavedMetadata.setIpcFd(fd), | ||
| 903 | .start_index = @intCast(serialized_len), | ||
| 904 | .nodes_len = nodes_len, | ||
| 905 | .main_index = @intCast(main_index), | ||
| 906 | }; | ||
| 907 | ipc_metadata_len += 1; | ||
| 908 | |||
| 909 | // Mount the root here. | ||
| 910 | copyRoot(main_storage, &storage[0]); | ||
| 911 | if (is_big_endian) main_storage.byteSwap(); | ||
| 912 | |||
| 913 | // Copy the rest of the tree to the end. | ||
| 914 | const storage_dest = serialized_buffer.storage[serialized_len..][0..nodes_len]; | ||
| 915 | @memcpy(storage_dest, storage[1..][0..nodes_len]); | ||
| 916 | |||
| 917 | // Always little-endian over the pipe. | ||
| 918 | if (is_big_endian) for (storage_dest) |*s| s.byteSwap(); | ||
| 919 | |||
| 920 | // Patch up parent pointers taking into account how the subtree is mounted. | ||
| 921 | for (serialized_buffer.parents[serialized_len..][0..nodes_len], parents[1..][0..nodes_len]) |*dest, p| { | ||
| 922 | dest.* = switch (p) { | ||
| 923 | // Fix bad data so the rest of the code does not see `unused`. | ||
| 924 | .none, .unused => .none, | ||
| 925 | // Root node is being mounted here. | ||
| 926 | @as(Node.Parent, @enumFromInt(0)) => @enumFromInt(main_index), | ||
| 927 | // Other nodes mounted at the end. | ||
| 928 | // Don't trust child data; if the data is outside the expected range, ignore the data. | ||
| 929 | // This also handles the case when data was truncated. | ||
| 930 | _ => |off| if (@intFromEnum(off) > nodes_len) | ||
| 931 | .none | ||
| 932 | else | ||
| 933 | @enumFromInt(serialized_len + @intFromEnum(off) - 1), | ||
| 934 | }; | ||
| 338 | } | 935 | } |
| 936 | |||
| 937 | serialized_len += nodes_len; | ||
| 339 | } | 938 | } |
| 340 | 939 | ||
| 341 | _ = file.write(self.output_buffer[0..end]) catch { | 940 | // Save a copy in case any pipes are empty on the next update. |
| 342 | // stop trying to write to this file | 941 | @memcpy(serialized_buffer.parents_copy[0..serialized_len], serialized_buffer.parents[0..serialized_len]); |
| 343 | self.terminal = null; | 942 | @memcpy(serialized_buffer.storage_copy[0..serialized_len], serialized_buffer.storage[0..serialized_len]); |
| 943 | @memcpy(ipc_metadata_copy[0..ipc_metadata_len], ipc_metadata[0..ipc_metadata_len]); | ||
| 944 | |||
| 945 | return serialized_len; | ||
| 946 | } | ||
| 947 | |||
| 948 | fn copyRoot(dest: *Node.Storage, src: *align(1) Node.Storage) void { | ||
| 949 | dest.* = .{ | ||
| 950 | .completed_count = src.completed_count, | ||
| 951 | .estimated_total_count = src.estimated_total_count, | ||
| 952 | .name = if (src.name[0] == 0) dest.name else src.name, | ||
| 344 | }; | 953 | }; |
| 345 | if (self.timer) |*timer| { | 954 | } |
| 346 | self.prev_refresh_timestamp = timer.read(); | 955 | |
| 956 | fn findOld(ipc_fd: posix.fd_t, old_metadata: []const SavedMetadata) ?*const SavedMetadata { | ||
| 957 | for (old_metadata) |*m| { | ||
| 958 | if (m.getIpcFd() == ipc_fd) | ||
| 959 | return m; | ||
| 347 | } | 960 | } |
| 961 | return null; | ||
| 348 | } | 962 | } |
| 349 | 963 | ||
| 350 | pub fn log(self: *Progress, comptime format: []const u8, args: anytype) void { | 964 | fn useSavedIpcData( |
| 351 | const file = self.terminal orelse { | 965 | start_serialized_len: usize, |
| 352 | std.debug.print(format, args); | 966 | serialized_buffer: *Serialized.Buffer, |
| 353 | return; | 967 | main_storage: *Node.Storage, |
| 968 | main_index: usize, | ||
| 969 | old_metadata: []const SavedMetadata, | ||
| 970 | ) usize { | ||
| 971 | const parents_copy = &serialized_buffer.parents_copy; | ||
| 972 | const storage_copy = &serialized_buffer.storage_copy; | ||
| 973 | const ipc_metadata = &serialized_buffer.ipc_metadata; | ||
| 974 | |||
| 975 | const ipc_fd = main_storage.getIpcFd().?; | ||
| 976 | const saved_metadata = findOld(ipc_fd, old_metadata) orelse { | ||
| 977 | main_storage.completed_count = 0; | ||
| 978 | main_storage.estimated_total_count = 0; | ||
| 979 | return start_serialized_len; | ||
| 354 | }; | 980 | }; |
| 355 | self.refresh(); | 981 | |
| 356 | file.writer().print(format, args) catch { | 982 | const start_index = saved_metadata.start_index; |
| 357 | self.terminal = null; | 983 | const nodes_len = @min(saved_metadata.nodes_len, serialized_buffer.storage.len - start_serialized_len); |
| 358 | return; | 984 | const old_main_index = saved_metadata.main_index; |
| 985 | |||
| 986 | ipc_metadata[ipc_metadata_len] = .{ | ||
| 987 | .ipc_fd = SavedMetadata.setIpcFd(ipc_fd), | ||
| 988 | .start_index = @intCast(start_serialized_len), | ||
| 989 | .nodes_len = nodes_len, | ||
| 990 | .main_index = @intCast(main_index), | ||
| 359 | }; | 991 | }; |
| 360 | self.columns_written = 0; | 992 | ipc_metadata_len += 1; |
| 361 | } | 993 | |
| 994 | const parents = parents_copy[start_index..][0..nodes_len]; | ||
| 995 | const storage = storage_copy[start_index..][0..nodes_len]; | ||
| 362 | 996 | ||
| 363 | /// Allows the caller to freely write to stderr until unlock_stderr() is called. | 997 | copyRoot(main_storage, &storage_copy[old_main_index]); |
| 364 | /// During the lock, the progress information is cleared from the terminal. | 998 | |
| 365 | pub fn lock_stderr(p: *Progress) void { | 999 | @memcpy(serialized_buffer.storage[start_serialized_len..][0..storage.len], storage); |
| 366 | p.update_mutex.lock(); | 1000 | |
| 367 | if (p.terminal) |file| { | 1001 | for (serialized_buffer.parents[start_serialized_len..][0..parents.len], parents) |*dest, p| { |
| 368 | var end: usize = 0; | 1002 | dest.* = switch (p) { |
| 369 | clearWithHeldLock(p, &end); | 1003 | .none, .unused => .none, |
| 370 | _ = file.write(p.output_buffer[0..end]) catch { | 1004 | _ => |prev| d: { |
| 371 | // stop trying to write to this file | 1005 | if (@intFromEnum(prev) == old_main_index) { |
| 372 | p.terminal = null; | 1006 | break :d @enumFromInt(main_index); |
| 1007 | } else if (@intFromEnum(prev) > nodes_len) { | ||
| 1008 | break :d .none; | ||
| 1009 | } else { | ||
| 1010 | break :d @enumFromInt(@intFromEnum(prev) - start_index + start_serialized_len); | ||
| 1011 | } | ||
| 1012 | }, | ||
| 373 | }; | 1013 | }; |
| 374 | } | 1014 | } |
| 375 | std.debug.getStderrMutex().lock(); | 1015 | |
| 1016 | return start_serialized_len + storage.len; | ||
| 1017 | } | ||
| 1018 | |||
| 1019 | fn computeRedraw(serialized_buffer: *Serialized.Buffer) []u8 { | ||
| 1020 | const serialized = serialize(serialized_buffer); | ||
| 1021 | |||
| 1022 | // Now we can analyze our copy of the graph without atomics, reconstructing | ||
| 1023 | // children lists which do not exist in the canonical data. These are | ||
| 1024 | // needed for tree traversal below. | ||
| 1025 | |||
| 1026 | var children_buffer: [node_storage_buffer_len]Children = undefined; | ||
| 1027 | const children = children_buffer[0..serialized.parents.len]; | ||
| 1028 | |||
| 1029 | @memset(children, .{ .child = .none, .sibling = .none }); | ||
| 1030 | |||
| 1031 | for (serialized.parents, 0..) |parent, child_index_usize| { | ||
| 1032 | const child_index: Node.Index = @enumFromInt(child_index_usize); | ||
| 1033 | assert(parent != .unused); | ||
| 1034 | const parent_index = parent.unwrap() orelse continue; | ||
| 1035 | const children_node = &children[@intFromEnum(parent_index)]; | ||
| 1036 | if (children_node.child.unwrap()) |existing_child_index| { | ||
| 1037 | const existing_child = &children[@intFromEnum(existing_child_index)]; | ||
| 1038 | children[@intFromEnum(child_index)].sibling = existing_child.sibling; | ||
| 1039 | existing_child.sibling = child_index.toOptional(); | ||
| 1040 | } else { | ||
| 1041 | children_node.child = child_index.toOptional(); | ||
| 1042 | } | ||
| 1043 | } | ||
| 1044 | |||
| 1045 | // The strategy is: keep the cursor at the end, and then with every redraw: | ||
| 1046 | // move cursor to beginning of line, move cursor up N lines, erase to end of screen, write | ||
| 1047 | |||
| 1048 | var i: usize = 0; | ||
| 1049 | const buf = global_progress.draw_buffer; | ||
| 1050 | |||
| 1051 | buf[i..][0..start_sync.len].* = start_sync.*; | ||
| 1052 | i += start_sync.len; | ||
| 1053 | |||
| 1054 | switch (global_progress.terminal_mode) { | ||
| 1055 | .off => unreachable, | ||
| 1056 | .ansi_escape_codes => i = computeClear(buf, i), | ||
| 1057 | .windows_api => if (!is_windows) unreachable, | ||
| 1058 | } | ||
| 1059 | |||
| 1060 | global_progress.accumulated_newline_count = 0; | ||
| 1061 | const root_node_index: Node.Index = @enumFromInt(0); | ||
| 1062 | i = computeNode(buf, i, serialized, children, root_node_index); | ||
| 1063 | |||
| 1064 | buf[i..][0..finish_sync.len].* = finish_sync.*; | ||
| 1065 | i += finish_sync.len; | ||
| 1066 | |||
| 1067 | return buf[0..i]; | ||
| 1068 | } | ||
| 1069 | |||
| 1070 | fn computePrefix( | ||
| 1071 | buf: []u8, | ||
| 1072 | start_i: usize, | ||
| 1073 | serialized: Serialized, | ||
| 1074 | children: []const Children, | ||
| 1075 | node_index: Node.Index, | ||
| 1076 | ) usize { | ||
| 1077 | var i = start_i; | ||
| 1078 | const parent_index = serialized.parents[@intFromEnum(node_index)].unwrap() orelse return i; | ||
| 1079 | if (serialized.parents[@intFromEnum(parent_index)] == .none) return i; | ||
| 1080 | if (@intFromEnum(serialized.parents[@intFromEnum(parent_index)]) == 0 and | ||
| 1081 | serialized.storage[0].name[0] == 0) | ||
| 1082 | { | ||
| 1083 | return i; | ||
| 1084 | } | ||
| 1085 | i = computePrefix(buf, i, serialized, children, parent_index); | ||
| 1086 | if (children[@intFromEnum(parent_index)].sibling == .none) { | ||
| 1087 | const prefix = " "; | ||
| 1088 | const upper_bound_len = prefix.len + line_upper_bound_len; | ||
| 1089 | if (i + upper_bound_len > buf.len) return buf.len; | ||
| 1090 | buf[i..][0..prefix.len].* = prefix.*; | ||
| 1091 | i += prefix.len; | ||
| 1092 | } else { | ||
| 1093 | const upper_bound_len = comptime (TreeSymbol.line.maxByteLen() + line_upper_bound_len); | ||
| 1094 | if (i + upper_bound_len > buf.len) return buf.len; | ||
| 1095 | i = appendTreeSymbol(.line, buf, i); | ||
| 1096 | } | ||
| 1097 | return i; | ||
| 1098 | } | ||
| 1099 | |||
| 1100 | const line_upper_bound_len = @max(TreeSymbol.tee.maxByteLen(), TreeSymbol.langle.maxByteLen()) + | ||
| 1101 | "[4294967296/4294967296] ".len + Node.max_name_len + finish_sync.len; | ||
| 1102 | |||
| 1103 | fn computeNode( | ||
| 1104 | buf: []u8, | ||
| 1105 | start_i: usize, | ||
| 1106 | serialized: Serialized, | ||
| 1107 | children: []const Children, | ||
| 1108 | node_index: Node.Index, | ||
| 1109 | ) usize { | ||
| 1110 | var i = start_i; | ||
| 1111 | i = computePrefix(buf, i, serialized, children, node_index); | ||
| 1112 | |||
| 1113 | if (i + line_upper_bound_len > buf.len) | ||
| 1114 | return start_i; | ||
| 1115 | |||
| 1116 | const storage = &serialized.storage[@intFromEnum(node_index)]; | ||
| 1117 | const estimated_total = storage.estimated_total_count; | ||
| 1118 | const completed_items = storage.completed_count; | ||
| 1119 | const name = if (std.mem.indexOfScalar(u8, &storage.name, 0)) |end| storage.name[0..end] else &storage.name; | ||
| 1120 | const parent = serialized.parents[@intFromEnum(node_index)]; | ||
| 1121 | |||
| 1122 | if (parent != .none) p: { | ||
| 1123 | if (@intFromEnum(parent) == 0 and serialized.storage[0].name[0] == 0) { | ||
| 1124 | break :p; | ||
| 1125 | } | ||
| 1126 | if (children[@intFromEnum(node_index)].sibling == .none) { | ||
| 1127 | i = appendTreeSymbol(.langle, buf, i); | ||
| 1128 | } else { | ||
| 1129 | i = appendTreeSymbol(.tee, buf, i); | ||
| 1130 | } | ||
| 1131 | } | ||
| 1132 | |||
| 1133 | const is_empty_root = @intFromEnum(node_index) == 0 and serialized.storage[0].name[0] == 0; | ||
| 1134 | if (!is_empty_root) { | ||
| 1135 | if (name.len != 0 or estimated_total > 0) { | ||
| 1136 | if (estimated_total > 0) { | ||
| 1137 | i += (std.fmt.bufPrint(buf[i..], "[{d}/{d}] ", .{ completed_items, estimated_total }) catch &.{}).len; | ||
| 1138 | } else if (completed_items != 0) { | ||
| 1139 | i += (std.fmt.bufPrint(buf[i..], "[{d}] ", .{completed_items}) catch &.{}).len; | ||
| 1140 | } | ||
| 1141 | if (name.len != 0) { | ||
| 1142 | i += (std.fmt.bufPrint(buf[i..], "{s}", .{name}) catch &.{}).len; | ||
| 1143 | } | ||
| 1144 | } | ||
| 1145 | |||
| 1146 | i = @min(global_progress.cols + start_i, i); | ||
| 1147 | buf[i] = '\n'; | ||
| 1148 | i += 1; | ||
| 1149 | global_progress.accumulated_newline_count += 1; | ||
| 1150 | } | ||
| 1151 | |||
| 1152 | if (global_progress.withinRowLimit()) { | ||
| 1153 | if (children[@intFromEnum(node_index)].child.unwrap()) |child| { | ||
| 1154 | i = computeNode(buf, i, serialized, children, child); | ||
| 1155 | } | ||
| 1156 | } | ||
| 1157 | |||
| 1158 | if (global_progress.withinRowLimit()) { | ||
| 1159 | if (children[@intFromEnum(node_index)].sibling.unwrap()) |sibling| { | ||
| 1160 | i = computeNode(buf, i, serialized, children, sibling); | ||
| 1161 | } | ||
| 1162 | } | ||
| 1163 | |||
| 1164 | return i; | ||
| 376 | } | 1165 | } |
| 377 | 1166 | ||
| 378 | pub fn unlock_stderr(p: *Progress) void { | 1167 | fn withinRowLimit(p: *Progress) bool { |
| 379 | std.debug.getStderrMutex().unlock(); | 1168 | // The +2 here is so that the PS1 is not scrolled off the top of the terminal. |
| 380 | p.update_mutex.unlock(); | 1169 | // one because we keep the cursor on the next line |
| 1170 | // one more to account for the PS1 | ||
| 1171 | return p.accumulated_newline_count + 2 < p.rows; | ||
| 381 | } | 1172 | } |
| 382 | 1173 | ||
| 383 | fn bufWrite(self: *Progress, end: *usize, comptime format: []const u8, args: anytype) void { | 1174 | fn write(buf: []const u8) anyerror!void { |
| 384 | if (std.fmt.bufPrint(self.output_buffer[end.*..], format, args)) |written| { | 1175 | try global_progress.terminal.writeAll(buf); |
| 385 | const amt = written.len; | 1176 | global_progress.written_newline_count = global_progress.accumulated_newline_count; |
| 386 | end.* += amt; | 1177 | } |
| 387 | self.columns_written += amt; | 1178 | |
| 1179 | var remaining_write_trash_bytes: usize = 0; | ||
| 1180 | |||
| 1181 | fn writeIpc(fd: posix.fd_t, serialized: Serialized) error{BrokenPipe}!void { | ||
| 1182 | // Byteswap if necessary to ensure little endian over the pipe. This is | ||
| 1183 | // needed because the parent or child process might be running in qemu. | ||
| 1184 | if (is_big_endian) for (serialized.storage) |*s| s.byteSwap(); | ||
| 1185 | |||
| 1186 | assert(serialized.parents.len == serialized.storage.len); | ||
| 1187 | const serialized_len: u8 = @intCast(serialized.parents.len); | ||
| 1188 | const header = std.mem.asBytes(&serialized_len); | ||
| 1189 | const storage = std.mem.sliceAsBytes(serialized.storage); | ||
| 1190 | const parents = std.mem.sliceAsBytes(serialized.parents); | ||
| 1191 | |||
| 1192 | var vecs: [3]posix.iovec_const = .{ | ||
| 1193 | .{ .base = header.ptr, .len = header.len }, | ||
| 1194 | .{ .base = storage.ptr, .len = storage.len }, | ||
| 1195 | .{ .base = parents.ptr, .len = parents.len }, | ||
| 1196 | }; | ||
| 1197 | |||
| 1198 | while (remaining_write_trash_bytes > 0) { | ||
| 1199 | // We do this in a separate write call to give a better chance for the | ||
| 1200 | // writev below to be in a single packet. | ||
| 1201 | const n = @min(parents.len, remaining_write_trash_bytes); | ||
| 1202 | if (posix.write(fd, parents[0..n])) |written| { | ||
| 1203 | remaining_write_trash_bytes -= written; | ||
| 1204 | continue; | ||
| 1205 | } else |err| switch (err) { | ||
| 1206 | error.WouldBlock => return, | ||
| 1207 | error.BrokenPipe => return error.BrokenPipe, | ||
| 1208 | else => |e| { | ||
| 1209 | std.log.debug("failed to send progress to parent process: {s}", .{@errorName(e)}); | ||
| 1210 | return error.BrokenPipe; | ||
| 1211 | }, | ||
| 1212 | } | ||
| 1213 | } | ||
| 1214 | |||
| 1215 | // If this write would block we do not want to keep trying, but we need to | ||
| 1216 | // know if a partial message was written. | ||
| 1217 | if (posix.writev(fd, &vecs)) |written| { | ||
| 1218 | const total = header.len + storage.len + parents.len; | ||
| 1219 | if (written < total) { | ||
| 1220 | remaining_write_trash_bytes = total - written; | ||
| 1221 | } | ||
| 388 | } else |err| switch (err) { | 1222 | } else |err| switch (err) { |
| 389 | error.NoSpaceLeft => { | 1223 | error.WouldBlock => {}, |
| 390 | self.columns_written += self.output_buffer.len - end.*; | 1224 | error.BrokenPipe => return error.BrokenPipe, |
| 391 | end.* = self.output_buffer.len; | 1225 | else => |e| { |
| 392 | const suffix = "... "; | 1226 | std.log.debug("failed to send progress to parent process: {s}", .{@errorName(e)}); |
| 393 | @memcpy(self.output_buffer[self.output_buffer.len - suffix.len ..], suffix); | 1227 | return error.BrokenPipe; |
| 394 | }, | 1228 | }, |
| 395 | } | 1229 | } |
| 396 | } | 1230 | } |
| 397 | 1231 | ||
| 398 | test "basic functionality" { | 1232 | fn maybeUpdateSize(resize_flag: bool) void { |
| 399 | var disable = true; | 1233 | if (!resize_flag) return; |
| 400 | _ = &disable; | ||
| 401 | if (disable) { | ||
| 402 | // This test is disabled because it uses time.sleep() and is therefore slow. It also | ||
| 403 | // prints bogus progress data to stderr. | ||
| 404 | return error.SkipZigTest; | ||
| 405 | } | ||
| 406 | var progress = Progress{}; | ||
| 407 | const root_node = progress.start("", 100); | ||
| 408 | defer root_node.end(); | ||
| 409 | |||
| 410 | const speed_factor = std.time.ns_per_ms; | ||
| 411 | |||
| 412 | const sub_task_names = [_][]const u8{ | ||
| 413 | "reticulating splines", | ||
| 414 | "adjusting shoes", | ||
| 415 | "climbing towers", | ||
| 416 | "pouring juice", | ||
| 417 | }; | ||
| 418 | var next_sub_task: usize = 0; | ||
| 419 | 1234 | ||
| 420 | var i: usize = 0; | 1235 | const fd = global_progress.terminal.handle; |
| 421 | while (i < 100) : (i += 1) { | ||
| 422 | var node = root_node.start(sub_task_names[next_sub_task], 5); | ||
| 423 | node.activate(); | ||
| 424 | next_sub_task = (next_sub_task + 1) % sub_task_names.len; | ||
| 425 | 1236 | ||
| 426 | node.completeOne(); | 1237 | if (is_windows) { |
| 427 | std.time.sleep(5 * speed_factor); | 1238 | var info: windows.CONSOLE_SCREEN_BUFFER_INFO = undefined; |
| 428 | node.completeOne(); | ||
| 429 | node.completeOne(); | ||
| 430 | std.time.sleep(5 * speed_factor); | ||
| 431 | node.completeOne(); | ||
| 432 | node.completeOne(); | ||
| 433 | std.time.sleep(5 * speed_factor); | ||
| 434 | 1239 | ||
| 435 | node.end(); | 1240 | if (windows.kernel32.GetConsoleScreenBufferInfo(fd, &info) != windows.FALSE) { |
| 1241 | // In the old Windows console, dwSize.Y is the line count of the | ||
| 1242 | // entire scrollback buffer, so we use this instead so that we | ||
| 1243 | // always get the size of the screen. | ||
| 1244 | const screen_height = info.srWindow.Bottom - info.srWindow.Top; | ||
| 1245 | global_progress.rows = @intCast(screen_height); | ||
| 1246 | global_progress.cols = @intCast(info.dwSize.X); | ||
| 1247 | } else { | ||
| 1248 | std.log.debug("failed to determine terminal size; using conservative guess 80x25", .{}); | ||
| 1249 | global_progress.rows = 25; | ||
| 1250 | global_progress.cols = 80; | ||
| 1251 | } | ||
| 1252 | } else { | ||
| 1253 | var winsize: posix.winsize = .{ | ||
| 1254 | .ws_row = 0, | ||
| 1255 | .ws_col = 0, | ||
| 1256 | .ws_xpixel = 0, | ||
| 1257 | .ws_ypixel = 0, | ||
| 1258 | }; | ||
| 436 | 1259 | ||
| 437 | std.time.sleep(5 * speed_factor); | 1260 | const err = posix.system.ioctl(fd, posix.T.IOCGWINSZ, @intFromPtr(&winsize)); |
| 438 | } | 1261 | if (posix.errno(err) == .SUCCESS) { |
| 439 | { | 1262 | global_progress.rows = winsize.ws_row; |
| 440 | var node = root_node.start("this is a really long name designed to activate the truncation code. let's find out if it works", 0); | 1263 | global_progress.cols = winsize.ws_col; |
| 441 | node.activate(); | 1264 | } else { |
| 442 | std.time.sleep(10 * speed_factor); | 1265 | std.log.debug("failed to determine terminal size; using conservative guess 80x25", .{}); |
| 443 | progress.refresh(); | 1266 | global_progress.rows = 25; |
| 444 | std.time.sleep(10 * speed_factor); | 1267 | global_progress.cols = 80; |
| 445 | node.end(); | 1268 | } |
| 446 | } | 1269 | } |
| 447 | } | 1270 | } |
| 1271 | |||
| 1272 | fn handleSigWinch(sig: i32, info: *const posix.siginfo_t, ctx_ptr: ?*anyopaque) callconv(.C) void { | ||
| 1273 | _ = info; | ||
| 1274 | _ = ctx_ptr; | ||
| 1275 | assert(sig == posix.SIG.WINCH); | ||
| 1276 | global_progress.redraw_event.set(); | ||
| 1277 | } | ||
| 1278 | |||
| 1279 | const have_sigwinch = switch (builtin.os.tag) { | ||
| 1280 | .linux, | ||
| 1281 | .plan9, | ||
| 1282 | .solaris, | ||
| 1283 | .netbsd, | ||
| 1284 | .openbsd, | ||
| 1285 | .haiku, | ||
| 1286 | .macos, | ||
| 1287 | .ios, | ||
| 1288 | .watchos, | ||
| 1289 | .tvos, | ||
| 1290 | .visionos, | ||
| 1291 | .dragonfly, | ||
| 1292 | .freebsd, | ||
| 1293 | => true, | ||
| 1294 | |||
| 1295 | else => false, | ||
| 1296 | }; | ||
| 1297 | |||
| 1298 | var stderr_mutex: std.Thread.Mutex = .{}; |
lib/std/debug.zig+24-9| ... | @@ -77,19 +77,28 @@ const PdbOrDwarf = union(enum) { | ... | @@ -77,19 +77,28 @@ const PdbOrDwarf = union(enum) { |
| 77 | } | 77 | } |
| 78 | }; | 78 | }; |
| 79 | 79 | ||
| 80 | var stderr_mutex = std.Thread.Mutex{}; | 80 | /// Allows the caller to freely write to stderr until `unlockStdErr` is called. |
| 81 | /// | ||
| 82 | /// During the lock, any `std.Progress` information is cleared from the terminal. | ||
| 83 | pub fn lockStdErr() void { | ||
| 84 | std.Progress.lockStdErr(); | ||
| 85 | } | ||
| 86 | |||
| 87 | pub fn unlockStdErr() void { | ||
| 88 | std.Progress.unlockStdErr(); | ||
| 89 | } | ||
| 81 | 90 | ||
| 82 | /// Print to stderr, unbuffered, and silently returning on failure. Intended | 91 | /// Print to stderr, unbuffered, and silently returning on failure. Intended |
| 83 | /// for use in "printf debugging." Use `std.log` functions for proper logging. | 92 | /// for use in "printf debugging." Use `std.log` functions for proper logging. |
| 84 | pub fn print(comptime fmt: []const u8, args: anytype) void { | 93 | pub fn print(comptime fmt: []const u8, args: anytype) void { |
| 85 | stderr_mutex.lock(); | 94 | lockStdErr(); |
| 86 | defer stderr_mutex.unlock(); | 95 | defer unlockStdErr(); |
| 87 | const stderr = io.getStdErr().writer(); | 96 | const stderr = io.getStdErr().writer(); |
| 88 | nosuspend stderr.print(fmt, args) catch return; | 97 | nosuspend stderr.print(fmt, args) catch return; |
| 89 | } | 98 | } |
| 90 | 99 | ||
| 91 | pub fn getStderrMutex() *std.Thread.Mutex { | 100 | pub fn getStderrMutex() *std.Thread.Mutex { |
| 92 | return &stderr_mutex; | 101 | @compileError("deprecated. call std.debug.lockStdErr() and std.debug.unlockStdErr() instead which will integrate properly with std.Progress"); |
| 93 | } | 102 | } |
| 94 | 103 | ||
| 95 | /// TODO multithreaded awareness | 104 | /// TODO multithreaded awareness |
| ... | @@ -107,8 +116,8 @@ pub fn getSelfDebugInfo() !*DebugInfo { | ... | @@ -107,8 +116,8 @@ pub fn getSelfDebugInfo() !*DebugInfo { |
| 107 | /// Tries to print a hexadecimal view of the bytes, unbuffered, and ignores any error returned. | 116 | /// Tries to print a hexadecimal view of the bytes, unbuffered, and ignores any error returned. |
| 108 | /// Obtains the stderr mutex while dumping. | 117 | /// Obtains the stderr mutex while dumping. |
| 109 | pub fn dump_hex(bytes: []const u8) void { | 118 | pub fn dump_hex(bytes: []const u8) void { |
| 110 | stderr_mutex.lock(); | 119 | lockStdErr(); |
| 111 | defer stderr_mutex.unlock(); | 120 | defer unlockStdErr(); |
| 112 | dump_hex_fallible(bytes) catch {}; | 121 | dump_hex_fallible(bytes) catch {}; |
| 113 | } | 122 | } |
| 114 | 123 | ||
| ... | @@ -2750,13 +2759,19 @@ pub const Trace = ConfigurableTrace(2, 4, builtin.mode == .Debug); | ... | @@ -2750,13 +2759,19 @@ pub const Trace = ConfigurableTrace(2, 4, builtin.mode == .Debug); |
| 2750 | 2759 | ||
| 2751 | pub fn ConfigurableTrace(comptime size: usize, comptime stack_frame_count: usize, comptime is_enabled: bool) type { | 2760 | pub fn ConfigurableTrace(comptime size: usize, comptime stack_frame_count: usize, comptime is_enabled: bool) type { |
| 2752 | return struct { | 2761 | return struct { |
| 2753 | addrs: [actual_size][stack_frame_count]usize = undefined, | 2762 | addrs: [actual_size][stack_frame_count]usize, |
| 2754 | notes: [actual_size][]const u8 = undefined, | 2763 | notes: [actual_size][]const u8, |
| 2755 | index: Index = 0, | 2764 | index: Index, |
| 2756 | 2765 | ||
| 2757 | const actual_size = if (enabled) size else 0; | 2766 | const actual_size = if (enabled) size else 0; |
| 2758 | const Index = if (enabled) usize else u0; | 2767 | const Index = if (enabled) usize else u0; |
| 2759 | 2768 | ||
| 2769 | pub const init: @This() = .{ | ||
| 2770 | .addrs = undefined, | ||
| 2771 | .notes = undefined, | ||
| 2772 | .index = 0, | ||
| 2773 | }; | ||
| 2774 | |||
| 2760 | pub const enabled = is_enabled; | 2775 | pub const enabled = is_enabled; |
| 2761 | 2776 | ||
| 2762 | pub const add = if (enabled) addNoInline else addNoOp; | 2777 | pub const add = if (enabled) addNoInline else addNoOp; |
lib/std/fmt.zig+35-24| ... | @@ -9,7 +9,7 @@ const assert = std.debug.assert; | ... | @@ -9,7 +9,7 @@ const assert = std.debug.assert; |
| 9 | const mem = std.mem; | 9 | const mem = std.mem; |
| 10 | const unicode = std.unicode; | 10 | const unicode = std.unicode; |
| 11 | const meta = std.meta; | 11 | const meta = std.meta; |
| 12 | const lossyCast = std.math.lossyCast; | 12 | const lossyCast = math.lossyCast; |
| 13 | const expectFmt = std.testing.expectFmt; | 13 | const expectFmt = std.testing.expectFmt; |
| 14 | 14 | ||
| 15 | pub const default_max_depth = 3; | 15 | pub const default_max_depth = 3; |
| ... | @@ -1494,10 +1494,20 @@ pub fn Formatter(comptime format_fn: anytype) type { | ... | @@ -1494,10 +1494,20 @@ pub fn Formatter(comptime format_fn: anytype) type { |
| 1494 | /// Ignores '_' character in `buf`. | 1494 | /// Ignores '_' character in `buf`. |
| 1495 | /// See also `parseUnsigned`. | 1495 | /// See also `parseUnsigned`. |
| 1496 | pub fn parseInt(comptime T: type, buf: []const u8, base: u8) ParseIntError!T { | 1496 | pub fn parseInt(comptime T: type, buf: []const u8, base: u8) ParseIntError!T { |
| 1497 | return parseIntWithGenericCharacter(T, u8, buf, base); | ||
| 1498 | } | ||
| 1499 | |||
| 1500 | /// Like `parseInt`, but with a generic `Character` type. | ||
| 1501 | pub fn parseIntWithGenericCharacter( | ||
| 1502 | comptime Result: type, | ||
| 1503 | comptime Character: type, | ||
| 1504 | buf: []const Character, | ||
| 1505 | base: u8, | ||
| 1506 | ) ParseIntError!Result { | ||
| 1497 | if (buf.len == 0) return error.InvalidCharacter; | 1507 | if (buf.len == 0) return error.InvalidCharacter; |
| 1498 | if (buf[0] == '+') return parseWithSign(T, buf[1..], base, .pos); | 1508 | if (buf[0] == '+') return parseIntWithSign(Result, Character, buf[1..], base, .pos); |
| 1499 | if (buf[0] == '-') return parseWithSign(T, buf[1..], base, .neg); | 1509 | if (buf[0] == '-') return parseIntWithSign(Result, Character, buf[1..], base, .neg); |
| 1500 | return parseWithSign(T, buf, base, .pos); | 1510 | return parseIntWithSign(Result, Character, buf, base, .pos); |
| 1501 | } | 1511 | } |
| 1502 | 1512 | ||
| 1503 | test parseInt { | 1513 | test parseInt { |
| ... | @@ -1560,12 +1570,13 @@ test parseInt { | ... | @@ -1560,12 +1570,13 @@ test parseInt { |
| 1560 | try std.testing.expectEqual(@as(i5, -16), try std.fmt.parseInt(i5, "-10", 16)); | 1570 | try std.testing.expectEqual(@as(i5, -16), try std.fmt.parseInt(i5, "-10", 16)); |
| 1561 | } | 1571 | } |
| 1562 | 1572 | ||
| 1563 | fn parseWithSign( | 1573 | fn parseIntWithSign( |
| 1564 | comptime T: type, | 1574 | comptime Result: type, |
| 1565 | buf: []const u8, | 1575 | comptime Character: type, |
| 1576 | buf: []const Character, | ||
| 1566 | base: u8, | 1577 | base: u8, |
| 1567 | comptime sign: enum { pos, neg }, | 1578 | comptime sign: enum { pos, neg }, |
| 1568 | ) ParseIntError!T { | 1579 | ) ParseIntError!Result { |
| 1569 | if (buf.len == 0) return error.InvalidCharacter; | 1580 | if (buf.len == 0) return error.InvalidCharacter; |
| 1570 | 1581 | ||
| 1571 | var buf_base = base; | 1582 | var buf_base = base; |
| ... | @@ -1575,7 +1586,7 @@ fn parseWithSign( | ... | @@ -1575,7 +1586,7 @@ fn parseWithSign( |
| 1575 | buf_base = 10; | 1586 | buf_base = 10; |
| 1576 | // Detect the base by looking at buf prefix. | 1587 | // Detect the base by looking at buf prefix. |
| 1577 | if (buf.len > 2 and buf[0] == '0') { | 1588 | if (buf.len > 2 and buf[0] == '0') { |
| 1578 | switch (std.ascii.toLower(buf[1])) { | 1589 | if (math.cast(u8, buf[1])) |c| switch (std.ascii.toLower(c)) { |
| 1579 | 'b' => { | 1590 | 'b' => { |
| 1580 | buf_base = 2; | 1591 | buf_base = 2; |
| 1581 | buf_start = buf[2..]; | 1592 | buf_start = buf[2..]; |
| ... | @@ -1589,7 +1600,7 @@ fn parseWithSign( | ... | @@ -1589,7 +1600,7 @@ fn parseWithSign( |
| 1589 | buf_start = buf[2..]; | 1600 | buf_start = buf[2..]; |
| 1590 | }, | 1601 | }, |
| 1591 | else => {}, | 1602 | else => {}, |
| 1592 | } | 1603 | }; |
| 1593 | } | 1604 | } |
| 1594 | } | 1605 | } |
| 1595 | 1606 | ||
| ... | @@ -1598,33 +1609,33 @@ fn parseWithSign( | ... | @@ -1598,33 +1609,33 @@ fn parseWithSign( |
| 1598 | .neg => math.sub, | 1609 | .neg => math.sub, |
| 1599 | }; | 1610 | }; |
| 1600 | 1611 | ||
| 1601 | // accumulate into U which is always 8 bits or larger. this prevents | 1612 | // accumulate into Accumulate which is always 8 bits or larger. this prevents |
| 1602 | // `buf_base` from overflowing T. | 1613 | // `buf_base` from overflowing Result. |
| 1603 | const info = @typeInfo(T); | 1614 | const info = @typeInfo(Result); |
| 1604 | const U = std.meta.Int(info.Int.signedness, @max(8, info.Int.bits)); | 1615 | const Accumulate = std.meta.Int(info.Int.signedness, @max(8, info.Int.bits)); |
| 1605 | var x: U = 0; | 1616 | var accumulate: Accumulate = 0; |
| 1606 | 1617 | ||
| 1607 | if (buf_start[0] == '_' or buf_start[buf_start.len - 1] == '_') return error.InvalidCharacter; | 1618 | if (buf_start[0] == '_' or buf_start[buf_start.len - 1] == '_') return error.InvalidCharacter; |
| 1608 | 1619 | ||
| 1609 | for (buf_start) |c| { | 1620 | for (buf_start) |c| { |
| 1610 | if (c == '_') continue; | 1621 | if (c == '_') continue; |
| 1611 | const digit = try charToDigit(c, buf_base); | 1622 | const digit = try charToDigit(math.cast(u8, c) orelse return error.InvalidCharacter, buf_base); |
| 1612 | if (x != 0) { | 1623 | if (accumulate != 0) { |
| 1613 | x = try math.mul(U, x, math.cast(U, buf_base) orelse return error.Overflow); | 1624 | accumulate = try math.mul(Accumulate, accumulate, math.cast(Accumulate, buf_base) orelse return error.Overflow); |
| 1614 | } else if (sign == .neg) { | 1625 | } else if (sign == .neg) { |
| 1615 | // The first digit of a negative number. | 1626 | // The first digit of a negative number. |
| 1616 | // Consider parsing "-4" as an i3. | 1627 | // Consider parsing "-4" as an i3. |
| 1617 | // This should work, but positive 4 overflows i3, so we can't cast the digit to T and subtract. | 1628 | // This should work, but positive 4 overflows i3, so we can't cast the digit to T and subtract. |
| 1618 | x = math.cast(U, -@as(i8, @intCast(digit))) orelse return error.Overflow; | 1629 | accumulate = math.cast(Accumulate, -@as(i8, @intCast(digit))) orelse return error.Overflow; |
| 1619 | continue; | 1630 | continue; |
| 1620 | } | 1631 | } |
| 1621 | x = try add(U, x, math.cast(U, digit) orelse return error.Overflow); | 1632 | accumulate = try add(Accumulate, accumulate, math.cast(Accumulate, digit) orelse return error.Overflow); |
| 1622 | } | 1633 | } |
| 1623 | 1634 | ||
| 1624 | return if (T == U) | 1635 | return if (Result == Accumulate) |
| 1625 | x | 1636 | accumulate |
| 1626 | else | 1637 | else |
| 1627 | math.cast(T, x) orelse return error.Overflow; | 1638 | math.cast(Result, accumulate) orelse return error.Overflow; |
| 1628 | } | 1639 | } |
| 1629 | 1640 | ||
| 1630 | /// Parses the string `buf` as unsigned representation in the specified base | 1641 | /// Parses the string `buf` as unsigned representation in the specified base |
| ... | @@ -1639,7 +1650,7 @@ fn parseWithSign( | ... | @@ -1639,7 +1650,7 @@ fn parseWithSign( |
| 1639 | /// Ignores '_' character in `buf`. | 1650 | /// Ignores '_' character in `buf`. |
| 1640 | /// See also `parseInt`. | 1651 | /// See also `parseInt`. |
| 1641 | pub fn parseUnsigned(comptime T: type, buf: []const u8, base: u8) ParseIntError!T { | 1652 | pub fn parseUnsigned(comptime T: type, buf: []const u8, base: u8) ParseIntError!T { |
| 1642 | return parseWithSign(T, buf, base, .pos); | 1653 | return parseIntWithSign(T, u8, buf, base, .pos); |
| 1643 | } | 1654 | } |
| 1644 | 1655 | ||
| 1645 | test parseUnsigned { | 1656 | test parseUnsigned { |
lib/std/io/tty.zig+1-1| ... | @@ -24,7 +24,7 @@ pub fn detectConfig(file: File) Config { | ... | @@ -24,7 +24,7 @@ pub fn detectConfig(file: File) Config { |
| 24 | 24 | ||
| 25 | if (native_os == .windows and file.isTty()) { | 25 | if (native_os == .windows and file.isTty()) { |
| 26 | var info: windows.CONSOLE_SCREEN_BUFFER_INFO = undefined; | 26 | var info: windows.CONSOLE_SCREEN_BUFFER_INFO = undefined; |
| 27 | if (windows.kernel32.GetConsoleScreenBufferInfo(file.handle, &info) != windows.TRUE) { | 27 | if (windows.kernel32.GetConsoleScreenBufferInfo(file.handle, &info) == windows.FALSE) { |
| 28 | return if (force_color == true) .escape_codes else .no_color; | 28 | return if (force_color == true) .escape_codes else .no_color; |
| 29 | } | 29 | } |
| 30 | return .{ .windows_api = .{ | 30 | return .{ .windows_api = .{ |
lib/std/json/dynamic.zig+2-2| ... | @@ -52,8 +52,8 @@ pub const Value = union(enum) { | ... | @@ -52,8 +52,8 @@ pub const Value = union(enum) { |
| 52 | } | 52 | } |
| 53 | 53 | ||
| 54 | pub fn dump(self: Value) void { | 54 | pub fn dump(self: Value) void { |
| 55 | std.debug.getStderrMutex().lock(); | 55 | std.debug.lockStdErr(); |
| 56 | defer std.debug.getStderrMutex().unlock(); | 56 | defer std.debug.unlockStdErr(); |
| 57 | 57 | ||
| 58 | const stderr = std.io.getStdErr().writer(); | 58 | const stderr = std.io.getStdErr().writer(); |
| 59 | stringify(self, .{}, stderr) catch return; | 59 | stringify(self, .{}, stderr) catch return; |
lib/std/log.zig+4-4| ... | @@ -45,8 +45,8 @@ | ... | @@ -45,8 +45,8 @@ |
| 45 | //! const prefix = "[" ++ comptime level.asText() ++ "] " ++ scope_prefix; | 45 | //! const prefix = "[" ++ comptime level.asText() ++ "] " ++ scope_prefix; |
| 46 | //! | 46 | //! |
| 47 | //! // Print the message to stderr, silently ignoring any errors | 47 | //! // Print the message to stderr, silently ignoring any errors |
| 48 | //! std.debug.getStderrMutex().lock(); | 48 | //! std.debug.lockStdErr(); |
| 49 | //! defer std.debug.getStderrMutex().unlock(); | 49 | //! defer std.debug.unlockStdErr(); |
| 50 | //! const stderr = std.io.getStdErr().writer(); | 50 | //! const stderr = std.io.getStdErr().writer(); |
| 51 | //! nosuspend stderr.print(prefix ++ format ++ "\n", args) catch return; | 51 | //! nosuspend stderr.print(prefix ++ format ++ "\n", args) catch return; |
| 52 | //! } | 52 | //! } |
| ... | @@ -152,8 +152,8 @@ pub fn defaultLog( | ... | @@ -152,8 +152,8 @@ pub fn defaultLog( |
| 152 | var bw = std.io.bufferedWriter(stderr); | 152 | var bw = std.io.bufferedWriter(stderr); |
| 153 | const writer = bw.writer(); | 153 | const writer = bw.writer(); |
| 154 | 154 | ||
| 155 | std.debug.getStderrMutex().lock(); | 155 | std.debug.lockStdErr(); |
| 156 | defer std.debug.getStderrMutex().unlock(); | 156 | defer std.debug.unlockStdErr(); |
| 157 | nosuspend { | 157 | nosuspend { |
| 158 | writer.print(level_txt ++ prefix2 ++ format ++ "\n", args) catch return; | 158 | writer.print(level_txt ++ prefix2 ++ format ++ "\n", args) catch return; |
| 159 | bw.flush() catch return; | 159 | bw.flush() catch return; |
lib/std/os/windows/kernel32.zig+9| ... | @@ -175,6 +175,15 @@ pub extern "kernel32" fn FillConsoleOutputCharacterW(hConsoleOutput: HANDLE, cCh | ... | @@ -175,6 +175,15 @@ pub extern "kernel32" fn FillConsoleOutputCharacterW(hConsoleOutput: HANDLE, cCh |
| 175 | pub extern "kernel32" fn FillConsoleOutputAttribute(hConsoleOutput: HANDLE, wAttribute: WORD, nLength: DWORD, dwWriteCoord: COORD, lpNumberOfAttrsWritten: *DWORD) callconv(WINAPI) BOOL; | 175 | pub extern "kernel32" fn FillConsoleOutputAttribute(hConsoleOutput: HANDLE, wAttribute: WORD, nLength: DWORD, dwWriteCoord: COORD, lpNumberOfAttrsWritten: *DWORD) callconv(WINAPI) BOOL; |
| 176 | pub extern "kernel32" fn SetConsoleCursorPosition(hConsoleOutput: HANDLE, dwCursorPosition: COORD) callconv(WINAPI) BOOL; | 176 | pub extern "kernel32" fn SetConsoleCursorPosition(hConsoleOutput: HANDLE, dwCursorPosition: COORD) callconv(WINAPI) BOOL; |
| 177 | 177 | ||
| 178 | pub extern "kernel32" fn WriteConsoleW(hConsoleOutput: HANDLE, lpBuffer: [*]const u16, nNumberOfCharsToWrite: DWORD, lpNumberOfCharsWritten: ?*DWORD, lpReserved: ?LPVOID) callconv(WINAPI) BOOL; | ||
| 179 | pub extern "kernel32" fn ReadConsoleOutputCharacterW( | ||
| 180 | hConsoleOutput: windows.HANDLE, | ||
| 181 | lpCharacter: [*]u16, | ||
| 182 | nLength: windows.DWORD, | ||
| 183 | dwReadCoord: windows.COORD, | ||
| 184 | lpNumberOfCharsRead: *windows.DWORD, | ||
| 185 | ) callconv(windows.WINAPI) windows.BOOL; | ||
| 186 | |||
| 178 | pub extern "kernel32" fn GetCurrentDirectoryW(nBufferLength: DWORD, lpBuffer: ?[*]WCHAR) callconv(WINAPI) DWORD; | 187 | pub extern "kernel32" fn GetCurrentDirectoryW(nBufferLength: DWORD, lpBuffer: ?[*]WCHAR) callconv(WINAPI) DWORD; |
| 179 | 188 | ||
| 180 | pub extern "kernel32" fn GetCurrentThread() callconv(WINAPI) HANDLE; | 189 | pub extern "kernel32" fn GetCurrentThread() callconv(WINAPI) HANDLE; |
lib/std/process.zig+151-11| ... | @@ -431,6 +431,26 @@ pub fn hasEnvVarConstant(comptime key: []const u8) bool { | ... | @@ -431,6 +431,26 @@ pub fn hasEnvVarConstant(comptime key: []const u8) bool { |
| 431 | } | 431 | } |
| 432 | } | 432 | } |
| 433 | 433 | ||
| 434 | pub const ParseEnvVarIntError = std.fmt.ParseIntError || error{EnvironmentVariableNotFound}; | ||
| 435 | |||
| 436 | /// Parses an environment variable as an integer. | ||
| 437 | /// | ||
| 438 | /// Since the key is comptime-known, no allocation is needed. | ||
| 439 | /// | ||
| 440 | /// On Windows, `key` must be valid UTF-8. | ||
| 441 | pub fn parseEnvVarInt(comptime key: []const u8, comptime I: type, base: u8) ParseEnvVarIntError!I { | ||
| 442 | if (native_os == .windows) { | ||
| 443 | const key_w = comptime std.unicode.utf8ToUtf16LeStringLiteral(key); | ||
| 444 | const text = getenvW(key_w) orelse return error.EnvironmentVariableNotFound; | ||
| 445 | return std.fmt.parseIntWithGenericCharacter(I, u16, text, base); | ||
| 446 | } else if (native_os == .wasi and !builtin.link_libc) { | ||
| 447 | @compileError("parseEnvVarInt is not supported for WASI without libc"); | ||
| 448 | } else { | ||
| 449 | const text = posix.getenv(key) orelse return error.EnvironmentVariableNotFound; | ||
| 450 | return std.fmt.parseInt(I, text, base); | ||
| 451 | } | ||
| 452 | } | ||
| 453 | |||
| 434 | pub const HasEnvVarError = error{ | 454 | pub const HasEnvVarError = error{ |
| 435 | OutOfMemory, | 455 | OutOfMemory, |
| 436 | 456 | ||
| ... | @@ -1740,6 +1760,7 @@ pub fn cleanExit() void { | ... | @@ -1740,6 +1760,7 @@ pub fn cleanExit() void { |
| 1740 | if (builtin.mode == .Debug) { | 1760 | if (builtin.mode == .Debug) { |
| 1741 | return; | 1761 | return; |
| 1742 | } else { | 1762 | } else { |
| 1763 | std.debug.lockStdErr(); | ||
| 1743 | exit(0); | 1764 | exit(0); |
| 1744 | } | 1765 | } |
| 1745 | } | 1766 | } |
| ... | @@ -1790,24 +1811,143 @@ test raiseFileDescriptorLimit { | ... | @@ -1790,24 +1811,143 @@ test raiseFileDescriptorLimit { |
| 1790 | raiseFileDescriptorLimit(); | 1811 | raiseFileDescriptorLimit(); |
| 1791 | } | 1812 | } |
| 1792 | 1813 | ||
| 1793 | pub fn createNullDelimitedEnvMap(arena: mem.Allocator, env_map: *const EnvMap) ![:null]?[*:0]u8 { | 1814 | pub const CreateEnvironOptions = struct { |
| 1794 | const envp_count = env_map.count(); | 1815 | /// `null` means to leave the `ZIG_PROGRESS` environment variable unmodified. |
| 1816 | /// If non-null, negative means to remove the environment variable, and >= 0 | ||
| 1817 | /// means to provide it with the given integer. | ||
| 1818 | zig_progress_fd: ?i32 = null, | ||
| 1819 | }; | ||
| 1820 | |||
| 1821 | /// Creates a null-deliminated environment variable block in the format | ||
| 1822 | /// expected by POSIX, from a hash map plus options. | ||
| 1823 | pub fn createEnvironFromMap( | ||
| 1824 | arena: Allocator, | ||
| 1825 | map: *const EnvMap, | ||
| 1826 | options: CreateEnvironOptions, | ||
| 1827 | ) Allocator.Error![:null]?[*:0]u8 { | ||
| 1828 | const ZigProgressAction = enum { nothing, edit, delete, add }; | ||
| 1829 | const zig_progress_action: ZigProgressAction = a: { | ||
| 1830 | const fd = options.zig_progress_fd orelse break :a .nothing; | ||
| 1831 | const contains = map.get("ZIG_PROGRESS") != null; | ||
| 1832 | if (fd >= 0) { | ||
| 1833 | break :a if (contains) .edit else .add; | ||
| 1834 | } else { | ||
| 1835 | if (contains) break :a .delete; | ||
| 1836 | } | ||
| 1837 | break :a .nothing; | ||
| 1838 | }; | ||
| 1839 | |||
| 1840 | const envp_count: usize = c: { | ||
| 1841 | var count: usize = map.count(); | ||
| 1842 | switch (zig_progress_action) { | ||
| 1843 | .add => count += 1, | ||
| 1844 | .delete => count -= 1, | ||
| 1845 | .nothing, .edit => {}, | ||
| 1846 | } | ||
| 1847 | break :c count; | ||
| 1848 | }; | ||
| 1849 | |||
| 1795 | const envp_buf = try arena.allocSentinel(?[*:0]u8, envp_count, null); | 1850 | const envp_buf = try arena.allocSentinel(?[*:0]u8, envp_count, null); |
| 1851 | var i: usize = 0; | ||
| 1852 | |||
| 1853 | if (zig_progress_action == .add) { | ||
| 1854 | envp_buf[i] = try std.fmt.allocPrintZ(arena, "ZIG_PROGRESS={d}", .{options.zig_progress_fd.?}); | ||
| 1855 | i += 1; | ||
| 1856 | } | ||
| 1857 | |||
| 1796 | { | 1858 | { |
| 1797 | var it = env_map.iterator(); | 1859 | var it = map.iterator(); |
| 1798 | var i: usize = 0; | 1860 | while (it.next()) |pair| { |
| 1799 | while (it.next()) |pair| : (i += 1) { | 1861 | if (mem.eql(u8, pair.key_ptr.*, "ZIG_PROGRESS")) switch (zig_progress_action) { |
| 1800 | const env_buf = try arena.allocSentinel(u8, pair.key_ptr.len + pair.value_ptr.len + 1, 0); | 1862 | .add => unreachable, |
| 1801 | @memcpy(env_buf[0..pair.key_ptr.len], pair.key_ptr.*); | 1863 | .delete => continue, |
| 1802 | env_buf[pair.key_ptr.len] = '='; | 1864 | .edit => { |
| 1803 | @memcpy(env_buf[pair.key_ptr.len + 1 ..][0..pair.value_ptr.len], pair.value_ptr.*); | 1865 | envp_buf[i] = try std.fmt.allocPrintZ(arena, "{s}={d}", .{ |
| 1804 | envp_buf[i] = env_buf.ptr; | 1866 | pair.key_ptr.*, options.zig_progress_fd.?, |
| 1867 | }); | ||
| 1868 | i += 1; | ||
| 1869 | continue; | ||
| 1870 | }, | ||
| 1871 | .nothing => {}, | ||
| 1872 | }; | ||
| 1873 | |||
| 1874 | envp_buf[i] = try std.fmt.allocPrintZ(arena, "{s}={s}", .{ pair.key_ptr.*, pair.value_ptr.* }); | ||
| 1875 | i += 1; | ||
| 1876 | } | ||
| 1877 | } | ||
| 1878 | |||
| 1879 | assert(i == envp_count); | ||
| 1880 | return envp_buf; | ||
| 1881 | } | ||
| 1882 | |||
| 1883 | /// Creates a null-deliminated environment variable block in the format | ||
| 1884 | /// expected by POSIX, from a hash map plus options. | ||
| 1885 | pub fn createEnvironFromExisting( | ||
| 1886 | arena: Allocator, | ||
| 1887 | existing: [*:null]const ?[*:0]const u8, | ||
| 1888 | options: CreateEnvironOptions, | ||
| 1889 | ) Allocator.Error![:null]?[*:0]u8 { | ||
| 1890 | const existing_count, const contains_zig_progress = c: { | ||
| 1891 | var count: usize = 0; | ||
| 1892 | var contains = false; | ||
| 1893 | while (existing[count]) |line| : (count += 1) { | ||
| 1894 | contains = contains or mem.eql(u8, mem.sliceTo(line, '='), "ZIG_PROGRESS"); | ||
| 1895 | } | ||
| 1896 | break :c .{ count, contains }; | ||
| 1897 | }; | ||
| 1898 | const ZigProgressAction = enum { nothing, edit, delete, add }; | ||
| 1899 | const zig_progress_action: ZigProgressAction = a: { | ||
| 1900 | const fd = options.zig_progress_fd orelse break :a .nothing; | ||
| 1901 | if (fd >= 0) { | ||
| 1902 | break :a if (contains_zig_progress) .edit else .add; | ||
| 1903 | } else { | ||
| 1904 | if (contains_zig_progress) break :a .delete; | ||
| 1905 | } | ||
| 1906 | break :a .nothing; | ||
| 1907 | }; | ||
| 1908 | |||
| 1909 | const envp_count: usize = c: { | ||
| 1910 | var count: usize = existing_count; | ||
| 1911 | switch (zig_progress_action) { | ||
| 1912 | .add => count += 1, | ||
| 1913 | .delete => count -= 1, | ||
| 1914 | .nothing, .edit => {}, | ||
| 1805 | } | 1915 | } |
| 1806 | assert(i == envp_count); | 1916 | break :c count; |
| 1917 | }; | ||
| 1918 | |||
| 1919 | const envp_buf = try arena.allocSentinel(?[*:0]u8, envp_count, null); | ||
| 1920 | var i: usize = 0; | ||
| 1921 | var existing_index: usize = 0; | ||
| 1922 | |||
| 1923 | if (zig_progress_action == .add) { | ||
| 1924 | envp_buf[i] = try std.fmt.allocPrintZ(arena, "ZIG_PROGRESS={d}", .{options.zig_progress_fd.?}); | ||
| 1925 | i += 1; | ||
| 1926 | } | ||
| 1927 | |||
| 1928 | while (existing[existing_index]) |line| : (existing_index += 1) { | ||
| 1929 | if (mem.eql(u8, mem.sliceTo(line, '='), "ZIG_PROGRESS")) switch (zig_progress_action) { | ||
| 1930 | .add => unreachable, | ||
| 1931 | .delete => continue, | ||
| 1932 | .edit => { | ||
| 1933 | envp_buf[i] = try std.fmt.allocPrintZ(arena, "ZIG_PROGRESS={d}", .{options.zig_progress_fd.?}); | ||
| 1934 | i += 1; | ||
| 1935 | continue; | ||
| 1936 | }, | ||
| 1937 | .nothing => {}, | ||
| 1938 | }; | ||
| 1939 | envp_buf[i] = try arena.dupeZ(u8, mem.span(line)); | ||
| 1940 | i += 1; | ||
| 1807 | } | 1941 | } |
| 1942 | |||
| 1943 | assert(i == envp_count); | ||
| 1808 | return envp_buf; | 1944 | return envp_buf; |
| 1809 | } | 1945 | } |
| 1810 | 1946 | ||
| 1947 | pub fn createNullDelimitedEnvMap(arena: mem.Allocator, env_map: *const EnvMap) Allocator.Error![:null]?[*:0]u8 { | ||
| 1948 | return createEnvironFromMap(arena, env_map, .{}); | ||
| 1949 | } | ||
| 1950 | |||
| 1811 | test createNullDelimitedEnvMap { | 1951 | test createNullDelimitedEnvMap { |
| 1812 | const allocator = testing.allocator; | 1952 | const allocator = testing.allocator; |
| 1813 | var envmap = EnvMap.init(allocator); | 1953 | var envmap = EnvMap.init(allocator); |
lib/std/process/Child.zig+64-25| ... | @@ -12,6 +12,7 @@ const EnvMap = std.process.EnvMap; | ... | @@ -12,6 +12,7 @@ const EnvMap = std.process.EnvMap; |
| 12 | const maxInt = std.math.maxInt; | 12 | const maxInt = std.math.maxInt; |
| 13 | const assert = std.debug.assert; | 13 | const assert = std.debug.assert; |
| 14 | const native_os = builtin.os.tag; | 14 | const native_os = builtin.os.tag; |
| 15 | const Allocator = std.mem.Allocator; | ||
| 15 | const ChildProcess = @This(); | 16 | const ChildProcess = @This(); |
| 16 | 17 | ||
| 17 | pub const Id = switch (native_os) { | 18 | pub const Id = switch (native_os) { |
| ... | @@ -92,6 +93,16 @@ request_resource_usage_statistics: bool = false, | ... | @@ -92,6 +93,16 @@ request_resource_usage_statistics: bool = false, |
| 92 | /// `spawn`. | 93 | /// `spawn`. |
| 93 | resource_usage_statistics: ResourceUsageStatistics = .{}, | 94 | resource_usage_statistics: ResourceUsageStatistics = .{}, |
| 94 | 95 | ||
| 96 | /// When populated, a pipe will be created for the child process to | ||
| 97 | /// communicate progress back to the parent. The file descriptor of the | ||
| 98 | /// write end of the pipe will be specified in the `ZIG_PROGRESS` | ||
| 99 | /// environment variable inside the child process. The progress reported by | ||
| 100 | /// the child will be attached to this progress node in the parent process. | ||
| 101 | /// | ||
| 102 | /// The child's progress tree will be grafted into the parent's progress tree, | ||
| 103 | /// by substituting this node with the child's root node. | ||
| 104 | progress_node: std.Progress.Node = .{ .index = .none }, | ||
| 105 | |||
| 95 | pub const ResourceUsageStatistics = struct { | 106 | pub const ResourceUsageStatistics = struct { |
| 96 | rusage: @TypeOf(rusage_init) = rusage_init, | 107 | rusage: @TypeOf(rusage_init) = rusage_init, |
| 97 | 108 | ||
| ... | @@ -205,9 +216,9 @@ pub fn init(argv: []const []const u8, allocator: mem.Allocator) ChildProcess { | ... | @@ -205,9 +216,9 @@ pub fn init(argv: []const []const u8, allocator: mem.Allocator) ChildProcess { |
| 205 | .stdin = null, | 216 | .stdin = null, |
| 206 | .stdout = null, | 217 | .stdout = null, |
| 207 | .stderr = null, | 218 | .stderr = null, |
| 208 | .stdin_behavior = StdIo.Inherit, | 219 | .stdin_behavior = .Inherit, |
| 209 | .stdout_behavior = StdIo.Inherit, | 220 | .stdout_behavior = .Inherit, |
| 210 | .stderr_behavior = StdIo.Inherit, | 221 | .stderr_behavior = .Inherit, |
| 211 | .expand_arg0 = .no_expand, | 222 | .expand_arg0 = .no_expand, |
| 212 | }; | 223 | }; |
| 213 | } | 224 | } |
| ... | @@ -538,22 +549,22 @@ fn spawnPosix(self: *ChildProcess) SpawnError!void { | ... | @@ -538,22 +549,22 @@ fn spawnPosix(self: *ChildProcess) SpawnError!void { |
| 538 | // turns out, we `dup2` everything anyway, so there's no need! | 549 | // turns out, we `dup2` everything anyway, so there's no need! |
| 539 | const pipe_flags: posix.O = .{ .CLOEXEC = true }; | 550 | const pipe_flags: posix.O = .{ .CLOEXEC = true }; |
| 540 | 551 | ||
| 541 | const stdin_pipe = if (self.stdin_behavior == StdIo.Pipe) try posix.pipe2(pipe_flags) else undefined; | 552 | const stdin_pipe = if (self.stdin_behavior == .Pipe) try posix.pipe2(pipe_flags) else undefined; |
| 542 | errdefer if (self.stdin_behavior == StdIo.Pipe) { | 553 | errdefer if (self.stdin_behavior == .Pipe) { |
| 543 | destroyPipe(stdin_pipe); | 554 | destroyPipe(stdin_pipe); |
| 544 | }; | 555 | }; |
| 545 | 556 | ||
| 546 | const stdout_pipe = if (self.stdout_behavior == StdIo.Pipe) try posix.pipe2(pipe_flags) else undefined; | 557 | const stdout_pipe = if (self.stdout_behavior == .Pipe) try posix.pipe2(pipe_flags) else undefined; |
| 547 | errdefer if (self.stdout_behavior == StdIo.Pipe) { | 558 | errdefer if (self.stdout_behavior == .Pipe) { |
| 548 | destroyPipe(stdout_pipe); | 559 | destroyPipe(stdout_pipe); |
| 549 | }; | 560 | }; |
| 550 | 561 | ||
| 551 | const stderr_pipe = if (self.stderr_behavior == StdIo.Pipe) try posix.pipe2(pipe_flags) else undefined; | 562 | const stderr_pipe = if (self.stderr_behavior == .Pipe) try posix.pipe2(pipe_flags) else undefined; |
| 552 | errdefer if (self.stderr_behavior == StdIo.Pipe) { | 563 | errdefer if (self.stderr_behavior == .Pipe) { |
| 553 | destroyPipe(stderr_pipe); | 564 | destroyPipe(stderr_pipe); |
| 554 | }; | 565 | }; |
| 555 | 566 | ||
| 556 | const any_ignore = (self.stdin_behavior == StdIo.Ignore or self.stdout_behavior == StdIo.Ignore or self.stderr_behavior == StdIo.Ignore); | 567 | const any_ignore = (self.stdin_behavior == .Ignore or self.stdout_behavior == .Ignore or self.stderr_behavior == .Ignore); |
| 557 | const dev_null_fd = if (any_ignore) | 568 | const dev_null_fd = if (any_ignore) |
| 558 | posix.openZ("/dev/null", .{ .ACCMODE = .RDWR }, 0) catch |err| switch (err) { | 569 | posix.openZ("/dev/null", .{ .ACCMODE = .RDWR }, 0) catch |err| switch (err) { |
| 559 | error.PathAlreadyExists => unreachable, | 570 | error.PathAlreadyExists => unreachable, |
| ... | @@ -572,6 +583,16 @@ fn spawnPosix(self: *ChildProcess) SpawnError!void { | ... | @@ -572,6 +583,16 @@ fn spawnPosix(self: *ChildProcess) SpawnError!void { |
| 572 | if (any_ignore) posix.close(dev_null_fd); | 583 | if (any_ignore) posix.close(dev_null_fd); |
| 573 | } | 584 | } |
| 574 | 585 | ||
| 586 | const prog_pipe: [2]posix.fd_t = p: { | ||
| 587 | if (self.progress_node.index == .none) { | ||
| 588 | break :p .{ -1, -1 }; | ||
| 589 | } else { | ||
| 590 | // We use CLOEXEC for the same reason as in `pipe_flags`. | ||
| 591 | break :p try posix.pipe2(.{ .NONBLOCK = true, .CLOEXEC = true }); | ||
| 592 | } | ||
| 593 | }; | ||
| 594 | errdefer destroyPipe(prog_pipe); | ||
| 595 | |||
| 575 | var arena_allocator = std.heap.ArenaAllocator.init(self.allocator); | 596 | var arena_allocator = std.heap.ArenaAllocator.init(self.allocator); |
| 576 | defer arena_allocator.deinit(); | 597 | defer arena_allocator.deinit(); |
| 577 | const arena = arena_allocator.allocator(); | 598 | const arena = arena_allocator.allocator(); |
| ... | @@ -588,16 +609,25 @@ fn spawnPosix(self: *ChildProcess) SpawnError!void { | ... | @@ -588,16 +609,25 @@ fn spawnPosix(self: *ChildProcess) SpawnError!void { |
| 588 | const argv_buf = try arena.allocSentinel(?[*:0]const u8, self.argv.len, null); | 609 | const argv_buf = try arena.allocSentinel(?[*:0]const u8, self.argv.len, null); |
| 589 | for (self.argv, 0..) |arg, i| argv_buf[i] = (try arena.dupeZ(u8, arg)).ptr; | 610 | for (self.argv, 0..) |arg, i| argv_buf[i] = (try arena.dupeZ(u8, arg)).ptr; |
| 590 | 611 | ||
| 591 | const envp = m: { | 612 | const prog_fileno = 3; |
| 613 | comptime assert(@max(posix.STDIN_FILENO, posix.STDOUT_FILENO, posix.STDERR_FILENO) + 1 == prog_fileno); | ||
| 614 | |||
| 615 | const envp: [*:null]const ?[*:0]const u8 = m: { | ||
| 616 | const prog_fd: i32 = if (prog_pipe[1] == -1) -1 else prog_fileno; | ||
| 592 | if (self.env_map) |env_map| { | 617 | if (self.env_map) |env_map| { |
| 593 | const envp_buf = try process.createNullDelimitedEnvMap(arena, env_map); | 618 | break :m (try process.createEnvironFromMap(arena, env_map, .{ |
| 594 | break :m envp_buf.ptr; | 619 | .zig_progress_fd = prog_fd, |
| 620 | })).ptr; | ||
| 595 | } else if (builtin.link_libc) { | 621 | } else if (builtin.link_libc) { |
| 596 | break :m std.c.environ; | 622 | break :m (try process.createEnvironFromExisting(arena, std.c.environ, .{ |
| 623 | .zig_progress_fd = prog_fd, | ||
| 624 | })).ptr; | ||
| 597 | } else if (builtin.output_mode == .Exe) { | 625 | } else if (builtin.output_mode == .Exe) { |
| 598 | // Then we have Zig start code and this works. | 626 | // Then we have Zig start code and this works. |
| 599 | // TODO type-safety for null-termination of `os.environ`. | 627 | // TODO type-safety for null-termination of `os.environ`. |
| 600 | break :m @as([*:null]const ?[*:0]const u8, @ptrCast(std.os.environ.ptr)); | 628 | break :m (try process.createEnvironFromExisting(arena, @ptrCast(std.os.environ.ptr), .{ |
| 629 | .zig_progress_fd = prog_fd, | ||
| 630 | })).ptr; | ||
| 601 | } else { | 631 | } else { |
| 602 | // TODO come up with a solution for this. | 632 | // TODO come up with a solution for this. |
| 603 | @compileError("missing std lib enhancement: ChildProcess implementation has no way to collect the environment variables to forward to the child process"); | 633 | @compileError("missing std lib enhancement: ChildProcess implementation has no way to collect the environment variables to forward to the child process"); |
| ... | @@ -631,6 +661,10 @@ fn spawnPosix(self: *ChildProcess) SpawnError!void { | ... | @@ -631,6 +661,10 @@ fn spawnPosix(self: *ChildProcess) SpawnError!void { |
| 631 | posix.chdir(cwd) catch |err| forkChildErrReport(err_pipe[1], err); | 661 | posix.chdir(cwd) catch |err| forkChildErrReport(err_pipe[1], err); |
| 632 | } | 662 | } |
| 633 | 663 | ||
| 664 | // Must happen after fchdir above, the cwd file descriptor might be | ||
| 665 | // equal to prog_fileno and be clobbered by this dup2 call. | ||
| 666 | if (prog_pipe[1] != -1) posix.dup2(prog_pipe[1], prog_fileno) catch |err| forkChildErrReport(err_pipe[1], err); | ||
| 667 | |||
| 634 | if (self.gid) |gid| { | 668 | if (self.gid) |gid| { |
| 635 | posix.setregid(gid, gid) catch |err| forkChildErrReport(err_pipe[1], err); | 669 | posix.setregid(gid, gid) catch |err| forkChildErrReport(err_pipe[1], err); |
| 636 | } | 670 | } |
| ... | @@ -648,18 +682,18 @@ fn spawnPosix(self: *ChildProcess) SpawnError!void { | ... | @@ -648,18 +682,18 @@ fn spawnPosix(self: *ChildProcess) SpawnError!void { |
| 648 | 682 | ||
| 649 | // we are the parent | 683 | // we are the parent |
| 650 | const pid: i32 = @intCast(pid_result); | 684 | const pid: i32 = @intCast(pid_result); |
| 651 | if (self.stdin_behavior == StdIo.Pipe) { | 685 | if (self.stdin_behavior == .Pipe) { |
| 652 | self.stdin = File{ .handle = stdin_pipe[1] }; | 686 | self.stdin = .{ .handle = stdin_pipe[1] }; |
| 653 | } else { | 687 | } else { |
| 654 | self.stdin = null; | 688 | self.stdin = null; |
| 655 | } | 689 | } |
| 656 | if (self.stdout_behavior == StdIo.Pipe) { | 690 | if (self.stdout_behavior == .Pipe) { |
| 657 | self.stdout = File{ .handle = stdout_pipe[0] }; | 691 | self.stdout = .{ .handle = stdout_pipe[0] }; |
| 658 | } else { | 692 | } else { |
| 659 | self.stdout = null; | 693 | self.stdout = null; |
| 660 | } | 694 | } |
| 661 | if (self.stderr_behavior == StdIo.Pipe) { | 695 | if (self.stderr_behavior == .Pipe) { |
| 662 | self.stderr = File{ .handle = stderr_pipe[0] }; | 696 | self.stderr = .{ .handle = stderr_pipe[0] }; |
| 663 | } else { | 697 | } else { |
| 664 | self.stderr = null; | 698 | self.stderr = null; |
| 665 | } | 699 | } |
| ... | @@ -668,15 +702,20 @@ fn spawnPosix(self: *ChildProcess) SpawnError!void { | ... | @@ -668,15 +702,20 @@ fn spawnPosix(self: *ChildProcess) SpawnError!void { |
| 668 | self.err_pipe = err_pipe; | 702 | self.err_pipe = err_pipe; |
| 669 | self.term = null; | 703 | self.term = null; |
| 670 | 704 | ||
| 671 | if (self.stdin_behavior == StdIo.Pipe) { | 705 | if (self.stdin_behavior == .Pipe) { |
| 672 | posix.close(stdin_pipe[0]); | 706 | posix.close(stdin_pipe[0]); |
| 673 | } | 707 | } |
| 674 | if (self.stdout_behavior == StdIo.Pipe) { | 708 | if (self.stdout_behavior == .Pipe) { |
| 675 | posix.close(stdout_pipe[1]); | 709 | posix.close(stdout_pipe[1]); |
| 676 | } | 710 | } |
| 677 | if (self.stderr_behavior == StdIo.Pipe) { | 711 | if (self.stderr_behavior == .Pipe) { |
| 678 | posix.close(stderr_pipe[1]); | 712 | posix.close(stderr_pipe[1]); |
| 679 | } | 713 | } |
| 714 | |||
| 715 | if (prog_pipe[1] != -1) { | ||
| 716 | posix.close(prog_pipe[1]); | ||
| 717 | } | ||
| 718 | self.progress_node.setIpcFd(prog_pipe[0]); | ||
| 680 | } | 719 | } |
| 681 | 720 | ||
| 682 | fn spawnWindows(self: *ChildProcess) SpawnError!void { | 721 | fn spawnWindows(self: *ChildProcess) SpawnError!void { |
| ... | @@ -962,7 +1001,7 @@ fn setUpChildIo(stdio: StdIo, pipe_fd: i32, std_fileno: i32, dev_null_fd: i32) ! | ... | @@ -962,7 +1001,7 @@ fn setUpChildIo(stdio: StdIo, pipe_fd: i32, std_fileno: i32, dev_null_fd: i32) ! |
| 962 | } | 1001 | } |
| 963 | 1002 | ||
| 964 | fn destroyPipe(pipe: [2]posix.fd_t) void { | 1003 | fn destroyPipe(pipe: [2]posix.fd_t) void { |
| 965 | posix.close(pipe[0]); | 1004 | if (pipe[0] != -1) posix.close(pipe[0]); |
| 966 | if (pipe[0] != pipe[1]) posix.close(pipe[1]); | 1005 | if (pipe[0] != pipe[1]) posix.close(pipe[1]); |
| 967 | } | 1006 | } |
| 968 | 1007 |
lib/std/zig.zig+1-1| ... | @@ -718,7 +718,7 @@ pub const LazySrcLoc = union(enum) { | ... | @@ -718,7 +718,7 @@ pub const LazySrcLoc = union(enum) { |
| 718 | /// where in semantic analysis the value got set. | 718 | /// where in semantic analysis the value got set. |
| 719 | pub const TracedOffset = struct { | 719 | pub const TracedOffset = struct { |
| 720 | x: i32, | 720 | x: i32, |
| 721 | trace: std.debug.Trace = .{}, | 721 | trace: std.debug.Trace = std.debug.Trace.init, |
| 722 | 722 | ||
| 723 | const want_tracing = false; | 723 | const want_tracing = false; |
| 724 | }; | 724 | }; |
lib/std/zig/ErrorBundle.zig+2-2| ... | @@ -155,8 +155,8 @@ pub const RenderOptions = struct { | ... | @@ -155,8 +155,8 @@ pub const RenderOptions = struct { |
| 155 | }; | 155 | }; |
| 156 | 156 | ||
| 157 | pub fn renderToStdErr(eb: ErrorBundle, options: RenderOptions) void { | 157 | pub fn renderToStdErr(eb: ErrorBundle, options: RenderOptions) void { |
| 158 | std.debug.getStderrMutex().lock(); | 158 | std.debug.lockStdErr(); |
| 159 | defer std.debug.getStderrMutex().unlock(); | 159 | defer std.debug.unlockStdErr(); |
| 160 | const stderr = std.io.getStdErr(); | 160 | const stderr = std.io.getStdErr(); |
| 161 | return renderToWriter(eb, options, stderr.writer()) catch return; | 161 | return renderToWriter(eb, options, stderr.writer()) catch return; |
| 162 | } | 162 | } |
lib/std/zig/Server.zig-2| ... | @@ -14,8 +14,6 @@ pub const Message = struct { | ... | @@ -14,8 +14,6 @@ pub const Message = struct { |
| 14 | zig_version, | 14 | zig_version, |
| 15 | /// Body is an ErrorBundle. | 15 | /// Body is an ErrorBundle. |
| 16 | error_bundle, | 16 | error_bundle, |
| 17 | /// Body is a UTF-8 string. | ||
| 18 | progress, | ||
| 19 | /// Body is a EmitBinPath. | 17 | /// Body is a EmitBinPath. |
| 20 | emit_bin_path, | 18 | emit_bin_path, |
| 21 | /// Body is a TestMetadata | 19 | /// Body is a TestMetadata |
src/Compilation.zig+44-72| ... | @@ -1273,8 +1273,8 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil | ... | @@ -1273,8 +1273,8 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil |
| 1273 | if (options.verbose_llvm_cpu_features) { | 1273 | if (options.verbose_llvm_cpu_features) { |
| 1274 | if (options.root_mod.resolved_target.llvm_cpu_features) |cf| print: { | 1274 | if (options.root_mod.resolved_target.llvm_cpu_features) |cf| print: { |
| 1275 | const target = options.root_mod.resolved_target.result; | 1275 | const target = options.root_mod.resolved_target.result; |
| 1276 | std.debug.getStderrMutex().lock(); | 1276 | std.debug.lockStdErr(); |
| 1277 | defer std.debug.getStderrMutex().unlock(); | 1277 | defer std.debug.unlockStdErr(); |
| 1278 | const stderr = std.io.getStdErr().writer(); | 1278 | const stderr = std.io.getStdErr().writer(); |
| 1279 | nosuspend { | 1279 | nosuspend { |
| 1280 | stderr.print("compilation: {s}\n", .{options.root_name}) catch break :print; | 1280 | stderr.print("compilation: {s}\n", .{options.root_name}) catch break :print; |
| ... | @@ -1934,7 +1934,7 @@ pub fn getTarget(self: Compilation) Target { | ... | @@ -1934,7 +1934,7 @@ pub fn getTarget(self: Compilation) Target { |
| 1934 | /// Only legal to call when cache mode is incremental and a link file is present. | 1934 | /// Only legal to call when cache mode is incremental and a link file is present. |
| 1935 | pub fn hotCodeSwap( | 1935 | pub fn hotCodeSwap( |
| 1936 | comp: *Compilation, | 1936 | comp: *Compilation, |
| 1937 | prog_node: *std.Progress.Node, | 1937 | prog_node: std.Progress.Node, |
| 1938 | pid: std.process.Child.Id, | 1938 | pid: std.process.Child.Id, |
| 1939 | ) !void { | 1939 | ) !void { |
| 1940 | const lf = comp.bin_file.?; | 1940 | const lf = comp.bin_file.?; |
| ... | @@ -1966,7 +1966,7 @@ fn cleanupAfterUpdate(comp: *Compilation) void { | ... | @@ -1966,7 +1966,7 @@ fn cleanupAfterUpdate(comp: *Compilation) void { |
| 1966 | } | 1966 | } |
| 1967 | 1967 | ||
| 1968 | /// Detect changes to source files, perform semantic analysis, and update the output files. | 1968 | /// Detect changes to source files, perform semantic analysis, and update the output files. |
| 1969 | pub fn update(comp: *Compilation, main_progress_node: *std.Progress.Node) !void { | 1969 | pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) !void { |
| 1970 | const tracy_trace = trace(@src()); | 1970 | const tracy_trace = trace(@src()); |
| 1971 | defer tracy_trace.end(); | 1971 | defer tracy_trace.end(); |
| 1972 | 1972 | ||
| ... | @@ -2256,7 +2256,7 @@ pub fn update(comp: *Compilation, main_progress_node: *std.Progress.Node) !void | ... | @@ -2256,7 +2256,7 @@ pub fn update(comp: *Compilation, main_progress_node: *std.Progress.Node) !void |
| 2256 | } | 2256 | } |
| 2257 | } | 2257 | } |
| 2258 | 2258 | ||
| 2259 | fn flush(comp: *Compilation, arena: Allocator, prog_node: *std.Progress.Node) !void { | 2259 | fn flush(comp: *Compilation, arena: Allocator, prog_node: std.Progress.Node) !void { |
| 2260 | if (comp.bin_file) |lf| { | 2260 | if (comp.bin_file) |lf| { |
| 2261 | // This is needed before reading the error flags. | 2261 | // This is needed before reading the error flags. |
| 2262 | lf.flush(arena, prog_node) catch |err| switch (err) { | 2262 | lf.flush(arena, prog_node) catch |err| switch (err) { |
| ... | @@ -2566,13 +2566,11 @@ pub fn emitLlvmObject( | ... | @@ -2566,13 +2566,11 @@ pub fn emitLlvmObject( |
| 2566 | default_emit: Emit, | 2566 | default_emit: Emit, |
| 2567 | bin_emit_loc: ?EmitLoc, | 2567 | bin_emit_loc: ?EmitLoc, |
| 2568 | llvm_object: *LlvmObject, | 2568 | llvm_object: *LlvmObject, |
| 2569 | prog_node: *std.Progress.Node, | 2569 | prog_node: std.Progress.Node, |
| 2570 | ) !void { | 2570 | ) !void { |
| 2571 | if (build_options.only_c) @compileError("unreachable"); | 2571 | if (build_options.only_c) @compileError("unreachable"); |
| 2572 | 2572 | ||
| 2573 | var sub_prog_node = prog_node.start("LLVM Emit Object", 0); | 2573 | const sub_prog_node = prog_node.start("LLVM Emit Object", 0); |
| 2574 | sub_prog_node.activate(); | ||
| 2575 | sub_prog_node.context.refresh(); | ||
| 2576 | defer sub_prog_node.end(); | 2574 | defer sub_prog_node.end(); |
| 2577 | 2575 | ||
| 2578 | try llvm_object.emit(.{ | 2576 | try llvm_object.emit(.{ |
| ... | @@ -3249,32 +3247,20 @@ pub fn addZirErrorMessages(eb: *ErrorBundle.Wip, file: *Module.File) !void { | ... | @@ -3249,32 +3247,20 @@ pub fn addZirErrorMessages(eb: *ErrorBundle.Wip, file: *Module.File) !void { |
| 3249 | 3247 | ||
| 3250 | pub fn performAllTheWork( | 3248 | pub fn performAllTheWork( |
| 3251 | comp: *Compilation, | 3249 | comp: *Compilation, |
| 3252 | main_progress_node: *std.Progress.Node, | 3250 | main_progress_node: std.Progress.Node, |
| 3253 | ) error{ TimerUnsupported, OutOfMemory }!void { | 3251 | ) error{ TimerUnsupported, OutOfMemory }!void { |
| 3254 | // Here we queue up all the AstGen tasks first, followed by C object compilation. | 3252 | // Here we queue up all the AstGen tasks first, followed by C object compilation. |
| 3255 | // We wait until the AstGen tasks are all completed before proceeding to the | 3253 | // We wait until the AstGen tasks are all completed before proceeding to the |
| 3256 | // (at least for now) single-threaded main work queue. However, C object compilation | 3254 | // (at least for now) single-threaded main work queue. However, C object compilation |
| 3257 | // only needs to be finished by the end of this function. | 3255 | // only needs to be finished by the end of this function. |
| 3258 | 3256 | ||
| 3259 | var zir_prog_node = main_progress_node.start("AST Lowering", 0); | ||
| 3260 | defer zir_prog_node.end(); | ||
| 3261 | |||
| 3262 | var wasm_prog_node = main_progress_node.start("Compile Autodocs", 0); | ||
| 3263 | defer wasm_prog_node.end(); | ||
| 3264 | |||
| 3265 | var c_obj_prog_node = main_progress_node.start("Compile C Objects", comp.c_source_files.len); | ||
| 3266 | defer c_obj_prog_node.end(); | ||
| 3267 | |||
| 3268 | var win32_resource_prog_node = main_progress_node.start("Compile Win32 Resources", comp.rc_source_files.len); | ||
| 3269 | defer win32_resource_prog_node.end(); | ||
| 3270 | |||
| 3271 | comp.work_queue_wait_group.reset(); | 3257 | comp.work_queue_wait_group.reset(); |
| 3272 | defer comp.work_queue_wait_group.wait(); | 3258 | defer comp.work_queue_wait_group.wait(); |
| 3273 | 3259 | ||
| 3274 | if (!build_options.only_c and !build_options.only_core_functionality) { | 3260 | if (!build_options.only_c and !build_options.only_core_functionality) { |
| 3275 | if (comp.docs_emit != null) { | 3261 | if (comp.docs_emit != null) { |
| 3276 | comp.thread_pool.spawnWg(&comp.work_queue_wait_group, workerDocsCopy, .{comp}); | 3262 | comp.thread_pool.spawnWg(&comp.work_queue_wait_group, workerDocsCopy, .{comp}); |
| 3277 | comp.work_queue_wait_group.spawnManager(workerDocsWasm, .{ comp, &wasm_prog_node }); | 3263 | comp.work_queue_wait_group.spawnManager(workerDocsWasm, .{ comp, main_progress_node }); |
| 3278 | } | 3264 | } |
| 3279 | } | 3265 | } |
| 3280 | 3266 | ||
| ... | @@ -3282,6 +3268,9 @@ pub fn performAllTheWork( | ... | @@ -3282,6 +3268,9 @@ pub fn performAllTheWork( |
| 3282 | const astgen_frame = tracy.namedFrame("astgen"); | 3268 | const astgen_frame = tracy.namedFrame("astgen"); |
| 3283 | defer astgen_frame.end(); | 3269 | defer astgen_frame.end(); |
| 3284 | 3270 | ||
| 3271 | const zir_prog_node = main_progress_node.start("AST Lowering", 0); | ||
| 3272 | defer zir_prog_node.end(); | ||
| 3273 | |||
| 3285 | comp.astgen_wait_group.reset(); | 3274 | comp.astgen_wait_group.reset(); |
| 3286 | defer comp.astgen_wait_group.wait(); | 3275 | defer comp.astgen_wait_group.wait(); |
| 3287 | 3276 | ||
| ... | @@ -3313,7 +3302,7 @@ pub fn performAllTheWork( | ... | @@ -3313,7 +3302,7 @@ pub fn performAllTheWork( |
| 3313 | 3302 | ||
| 3314 | while (comp.astgen_work_queue.readItem()) |file| { | 3303 | while (comp.astgen_work_queue.readItem()) |file| { |
| 3315 | comp.thread_pool.spawnWg(&comp.astgen_wait_group, workerAstGenFile, .{ | 3304 | comp.thread_pool.spawnWg(&comp.astgen_wait_group, workerAstGenFile, .{ |
| 3316 | comp, file, &zir_prog_node, &comp.astgen_wait_group, .root, | 3305 | comp, file, zir_prog_node, &comp.astgen_wait_group, .root, |
| 3317 | }); | 3306 | }); |
| 3318 | } | 3307 | } |
| 3319 | 3308 | ||
| ... | @@ -3325,14 +3314,14 @@ pub fn performAllTheWork( | ... | @@ -3325,14 +3314,14 @@ pub fn performAllTheWork( |
| 3325 | 3314 | ||
| 3326 | while (comp.c_object_work_queue.readItem()) |c_object| { | 3315 | while (comp.c_object_work_queue.readItem()) |c_object| { |
| 3327 | comp.thread_pool.spawnWg(&comp.work_queue_wait_group, workerUpdateCObject, .{ | 3316 | comp.thread_pool.spawnWg(&comp.work_queue_wait_group, workerUpdateCObject, .{ |
| 3328 | comp, c_object, &c_obj_prog_node, | 3317 | comp, c_object, main_progress_node, |
| 3329 | }); | 3318 | }); |
| 3330 | } | 3319 | } |
| 3331 | 3320 | ||
| 3332 | if (!build_options.only_core_functionality) { | 3321 | if (!build_options.only_core_functionality) { |
| 3333 | while (comp.win32_resource_work_queue.readItem()) |win32_resource| { | 3322 | while (comp.win32_resource_work_queue.readItem()) |win32_resource| { |
| 3334 | comp.thread_pool.spawnWg(&comp.work_queue_wait_group, workerUpdateWin32Resource, .{ | 3323 | comp.thread_pool.spawnWg(&comp.work_queue_wait_group, workerUpdateWin32Resource, .{ |
| 3335 | comp, win32_resource, &win32_resource_prog_node, | 3324 | comp, win32_resource, main_progress_node, |
| 3336 | }); | 3325 | }); |
| 3337 | } | 3326 | } |
| 3338 | } | 3327 | } |
| ... | @@ -3342,11 +3331,13 @@ pub fn performAllTheWork( | ... | @@ -3342,11 +3331,13 @@ pub fn performAllTheWork( |
| 3342 | try reportMultiModuleErrors(mod); | 3331 | try reportMultiModuleErrors(mod); |
| 3343 | try mod.flushRetryableFailures(); | 3332 | try mod.flushRetryableFailures(); |
| 3344 | mod.sema_prog_node = main_progress_node.start("Semantic Analysis", 0); | 3333 | mod.sema_prog_node = main_progress_node.start("Semantic Analysis", 0); |
| 3345 | mod.sema_prog_node.activate(); | 3334 | mod.codegen_prog_node = main_progress_node.start("Code Generation", 0); |
| 3346 | } | 3335 | } |
| 3347 | defer if (comp.module) |mod| { | 3336 | defer if (comp.module) |mod| { |
| 3348 | mod.sema_prog_node.end(); | 3337 | mod.sema_prog_node.end(); |
| 3349 | mod.sema_prog_node = undefined; | 3338 | mod.sema_prog_node = undefined; |
| 3339 | mod.codegen_prog_node.end(); | ||
| 3340 | mod.codegen_prog_node = undefined; | ||
| 3350 | }; | 3341 | }; |
| 3351 | 3342 | ||
| 3352 | while (true) { | 3343 | while (true) { |
| ... | @@ -3379,7 +3370,7 @@ pub fn performAllTheWork( | ... | @@ -3379,7 +3370,7 @@ pub fn performAllTheWork( |
| 3379 | } | 3370 | } |
| 3380 | } | 3371 | } |
| 3381 | 3372 | ||
| 3382 | fn processOneJob(comp: *Compilation, job: Job, prog_node: *std.Progress.Node) !void { | 3373 | fn processOneJob(comp: *Compilation, job: Job, prog_node: std.Progress.Node) !void { |
| 3383 | switch (job) { | 3374 | switch (job) { |
| 3384 | .codegen_decl => |decl_index| { | 3375 | .codegen_decl => |decl_index| { |
| 3385 | const module = comp.module.?; | 3376 | const module = comp.module.?; |
| ... | @@ -3803,7 +3794,10 @@ fn docsCopyModule(comp: *Compilation, module: *Package.Module, name: []const u8, | ... | @@ -3803,7 +3794,10 @@ fn docsCopyModule(comp: *Compilation, module: *Package.Module, name: []const u8, |
| 3803 | } | 3794 | } |
| 3804 | } | 3795 | } |
| 3805 | 3796 | ||
| 3806 | fn workerDocsWasm(comp: *Compilation, prog_node: *std.Progress.Node) void { | 3797 | fn workerDocsWasm(comp: *Compilation, parent_prog_node: std.Progress.Node) void { |
| 3798 | const prog_node = parent_prog_node.start("Compile Autodocs", 0); | ||
| 3799 | defer prog_node.end(); | ||
| 3800 | |||
| 3807 | workerDocsWasmFallible(comp, prog_node) catch |err| { | 3801 | workerDocsWasmFallible(comp, prog_node) catch |err| { |
| 3808 | comp.lockAndSetMiscFailure(.docs_wasm, "unable to build autodocs: {s}", .{ | 3802 | comp.lockAndSetMiscFailure(.docs_wasm, "unable to build autodocs: {s}", .{ |
| 3809 | @errorName(err), | 3803 | @errorName(err), |
| ... | @@ -3811,7 +3805,7 @@ fn workerDocsWasm(comp: *Compilation, prog_node: *std.Progress.Node) void { | ... | @@ -3811,7 +3805,7 @@ fn workerDocsWasm(comp: *Compilation, prog_node: *std.Progress.Node) void { |
| 3811 | }; | 3805 | }; |
| 3812 | } | 3806 | } |
| 3813 | 3807 | ||
| 3814 | fn workerDocsWasmFallible(comp: *Compilation, prog_node: *std.Progress.Node) anyerror!void { | 3808 | fn workerDocsWasmFallible(comp: *Compilation, prog_node: std.Progress.Node) anyerror!void { |
| 3815 | const gpa = comp.gpa; | 3809 | const gpa = comp.gpa; |
| 3816 | 3810 | ||
| 3817 | var arena_allocator = std.heap.ArenaAllocator.init(gpa); | 3811 | var arena_allocator = std.heap.ArenaAllocator.init(gpa); |
| ... | @@ -3952,12 +3946,11 @@ const AstGenSrc = union(enum) { | ... | @@ -3952,12 +3946,11 @@ const AstGenSrc = union(enum) { |
| 3952 | fn workerAstGenFile( | 3946 | fn workerAstGenFile( |
| 3953 | comp: *Compilation, | 3947 | comp: *Compilation, |
| 3954 | file: *Module.File, | 3948 | file: *Module.File, |
| 3955 | prog_node: *std.Progress.Node, | 3949 | prog_node: std.Progress.Node, |
| 3956 | wg: *WaitGroup, | 3950 | wg: *WaitGroup, |
| 3957 | src: AstGenSrc, | 3951 | src: AstGenSrc, |
| 3958 | ) void { | 3952 | ) void { |
| 3959 | var child_prog_node = prog_node.start(file.sub_file_path, 0); | 3953 | const child_prog_node = prog_node.start(file.sub_file_path, 0); |
| 3960 | child_prog_node.activate(); | ||
| 3961 | defer child_prog_node.end(); | 3954 | defer child_prog_node.end(); |
| 3962 | 3955 | ||
| 3963 | const mod = comp.module.?; | 3956 | const mod = comp.module.?; |
| ... | @@ -4265,7 +4258,7 @@ pub fn cImport(comp: *Compilation, c_src: []const u8, owner_mod: *Package.Module | ... | @@ -4265,7 +4258,7 @@ pub fn cImport(comp: *Compilation, c_src: []const u8, owner_mod: *Package.Module |
| 4265 | fn workerUpdateCObject( | 4258 | fn workerUpdateCObject( |
| 4266 | comp: *Compilation, | 4259 | comp: *Compilation, |
| 4267 | c_object: *CObject, | 4260 | c_object: *CObject, |
| 4268 | progress_node: *std.Progress.Node, | 4261 | progress_node: std.Progress.Node, |
| 4269 | ) void { | 4262 | ) void { |
| 4270 | comp.updateCObject(c_object, progress_node) catch |err| switch (err) { | 4263 | comp.updateCObject(c_object, progress_node) catch |err| switch (err) { |
| 4271 | error.AnalysisFail => return, | 4264 | error.AnalysisFail => return, |
| ... | @@ -4282,7 +4275,7 @@ fn workerUpdateCObject( | ... | @@ -4282,7 +4275,7 @@ fn workerUpdateCObject( |
| 4282 | fn workerUpdateWin32Resource( | 4275 | fn workerUpdateWin32Resource( |
| 4283 | comp: *Compilation, | 4276 | comp: *Compilation, |
| 4284 | win32_resource: *Win32Resource, | 4277 | win32_resource: *Win32Resource, |
| 4285 | progress_node: *std.Progress.Node, | 4278 | progress_node: std.Progress.Node, |
| 4286 | ) void { | 4279 | ) void { |
| 4287 | comp.updateWin32Resource(win32_resource, progress_node) catch |err| switch (err) { | 4280 | comp.updateWin32Resource(win32_resource, progress_node) catch |err| switch (err) { |
| 4288 | error.AnalysisFail => return, | 4281 | error.AnalysisFail => return, |
| ... | @@ -4300,7 +4293,7 @@ fn buildCompilerRtOneShot( | ... | @@ -4300,7 +4293,7 @@ fn buildCompilerRtOneShot( |
| 4300 | comp: *Compilation, | 4293 | comp: *Compilation, |
| 4301 | output_mode: std.builtin.OutputMode, | 4294 | output_mode: std.builtin.OutputMode, |
| 4302 | out: *?CRTFile, | 4295 | out: *?CRTFile, |
| 4303 | prog_node: *std.Progress.Node, | 4296 | prog_node: std.Progress.Node, |
| 4304 | ) void { | 4297 | ) void { |
| 4305 | comp.buildOutputFromZig( | 4298 | comp.buildOutputFromZig( |
| 4306 | "compiler_rt.zig", | 4299 | "compiler_rt.zig", |
| ... | @@ -4427,7 +4420,7 @@ fn reportRetryableEmbedFileError( | ... | @@ -4427,7 +4420,7 @@ fn reportRetryableEmbedFileError( |
| 4427 | } | 4420 | } |
| 4428 | } | 4421 | } |
| 4429 | 4422 | ||
| 4430 | fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: *std.Progress.Node) !void { | 4423 | fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: std.Progress.Node) !void { |
| 4431 | if (comp.config.c_frontend == .aro) { | 4424 | if (comp.config.c_frontend == .aro) { |
| 4432 | return comp.failCObj(c_object, "aro does not support compiling C objects yet", .{}); | 4425 | return comp.failCObj(c_object, "aro does not support compiling C objects yet", .{}); |
| 4433 | } | 4426 | } |
| ... | @@ -4467,9 +4460,7 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: *std.P | ... | @@ -4467,9 +4460,7 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: *std.P |
| 4467 | 4460 | ||
| 4468 | const c_source_basename = std.fs.path.basename(c_object.src.src_path); | 4461 | const c_source_basename = std.fs.path.basename(c_object.src.src_path); |
| 4469 | 4462 | ||
| 4470 | c_obj_prog_node.activate(); | 4463 | const child_progress_node = c_obj_prog_node.start(c_source_basename, 0); |
| 4471 | var child_progress_node = c_obj_prog_node.start(c_source_basename, 0); | ||
| 4472 | child_progress_node.activate(); | ||
| 4473 | defer child_progress_node.end(); | 4464 | defer child_progress_node.end(); |
| 4474 | 4465 | ||
| 4475 | // Special case when doing build-obj for just one C file. When there are more than one object | 4466 | // Special case when doing build-obj for just one C file. When there are more than one object |
| ... | @@ -4731,7 +4722,7 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: *std.P | ... | @@ -4731,7 +4722,7 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: *std.P |
| 4731 | }; | 4722 | }; |
| 4732 | } | 4723 | } |
| 4733 | 4724 | ||
| 4734 | fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32_resource_prog_node: *std.Progress.Node) !void { | 4725 | fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32_resource_prog_node: std.Progress.Node) !void { |
| 4735 | if (!std.process.can_spawn) { | 4726 | if (!std.process.can_spawn) { |
| 4736 | return comp.failWin32Resource(win32_resource, "{s} does not support spawning a child process", .{@tagName(builtin.os.tag)}); | 4727 | return comp.failWin32Resource(win32_resource, "{s} does not support spawning a child process", .{@tagName(builtin.os.tag)}); |
| 4737 | } | 4728 | } |
| ... | @@ -4763,9 +4754,7 @@ fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32 | ... | @@ -4763,9 +4754,7 @@ fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32 |
| 4763 | _ = comp.failed_win32_resources.swapRemove(win32_resource); | 4754 | _ = comp.failed_win32_resources.swapRemove(win32_resource); |
| 4764 | } | 4755 | } |
| 4765 | 4756 | ||
| 4766 | win32_resource_prog_node.activate(); | 4757 | const child_progress_node = win32_resource_prog_node.start(src_basename, 0); |
| 4767 | var child_progress_node = win32_resource_prog_node.start(src_basename, 0); | ||
| 4768 | child_progress_node.activate(); | ||
| 4769 | defer child_progress_node.end(); | 4758 | defer child_progress_node.end(); |
| 4770 | 4759 | ||
| 4771 | var man = comp.obtainWin32ResourceCacheManifest(); | 4760 | var man = comp.obtainWin32ResourceCacheManifest(); |
| ... | @@ -4833,7 +4822,7 @@ fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32 | ... | @@ -4833,7 +4822,7 @@ fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32 |
| 4833 | }); | 4822 | }); |
| 4834 | try argv.appendSlice(&.{ "--", in_rc_path, out_res_path }); | 4823 | try argv.appendSlice(&.{ "--", in_rc_path, out_res_path }); |
| 4835 | 4824 | ||
| 4836 | try spawnZigRc(comp, win32_resource, src_basename, arena, argv.items, &child_progress_node); | 4825 | try spawnZigRc(comp, win32_resource, arena, argv.items, child_progress_node); |
| 4837 | 4826 | ||
| 4838 | break :blk digest; | 4827 | break :blk digest; |
| 4839 | }; | 4828 | }; |
| ... | @@ -4901,7 +4890,7 @@ fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32 | ... | @@ -4901,7 +4890,7 @@ fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32 |
| 4901 | try argv.appendSlice(rc_src.extra_flags); | 4890 | try argv.appendSlice(rc_src.extra_flags); |
| 4902 | try argv.appendSlice(&.{ "--", rc_src.src_path, out_res_path }); | 4891 | try argv.appendSlice(&.{ "--", rc_src.src_path, out_res_path }); |
| 4903 | 4892 | ||
| 4904 | try spawnZigRc(comp, win32_resource, src_basename, arena, argv.items, &child_progress_node); | 4893 | try spawnZigRc(comp, win32_resource, arena, argv.items, child_progress_node); |
| 4905 | 4894 | ||
| 4906 | // Read depfile and update cache manifest | 4895 | // Read depfile and update cache manifest |
| 4907 | { | 4896 | { |
| ... | @@ -4966,10 +4955,9 @@ fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32 | ... | @@ -4966,10 +4955,9 @@ fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32 |
| 4966 | fn spawnZigRc( | 4955 | fn spawnZigRc( |
| 4967 | comp: *Compilation, | 4956 | comp: *Compilation, |
| 4968 | win32_resource: *Win32Resource, | 4957 | win32_resource: *Win32Resource, |
| 4969 | src_basename: []const u8, | ||
| 4970 | arena: Allocator, | 4958 | arena: Allocator, |
| 4971 | argv: []const []const u8, | 4959 | argv: []const []const u8, |
| 4972 | child_progress_node: *std.Progress.Node, | 4960 | child_progress_node: std.Progress.Node, |
| 4973 | ) !void { | 4961 | ) !void { |
| 4974 | var node_name: std.ArrayListUnmanaged(u8) = .{}; | 4962 | var node_name: std.ArrayListUnmanaged(u8) = .{}; |
| 4975 | defer node_name.deinit(arena); | 4963 | defer node_name.deinit(arena); |
| ... | @@ -4978,6 +4966,7 @@ fn spawnZigRc( | ... | @@ -4978,6 +4966,7 @@ fn spawnZigRc( |
| 4978 | child.stdin_behavior = .Ignore; | 4966 | child.stdin_behavior = .Ignore; |
| 4979 | child.stdout_behavior = .Pipe; | 4967 | child.stdout_behavior = .Pipe; |
| 4980 | child.stderr_behavior = .Pipe; | 4968 | child.stderr_behavior = .Pipe; |
| 4969 | child.progress_node = child_progress_node; | ||
| 4981 | 4970 | ||
| 4982 | child.spawn() catch |err| { | 4971 | child.spawn() catch |err| { |
| 4983 | return comp.failWin32Resource(win32_resource, "unable to spawn {s} rc: {s}", .{ argv[0], @errorName(err) }); | 4972 | return comp.failWin32Resource(win32_resource, "unable to spawn {s} rc: {s}", .{ argv[0], @errorName(err) }); |
| ... | @@ -5019,22 +5008,6 @@ fn spawnZigRc( | ... | @@ -5019,22 +5008,6 @@ fn spawnZigRc( |
| 5019 | }; | 5008 | }; |
| 5020 | return comp.failWin32ResourceWithOwnedBundle(win32_resource, error_bundle); | 5009 | return comp.failWin32ResourceWithOwnedBundle(win32_resource, error_bundle); |
| 5021 | }, | 5010 | }, |
| 5022 | .progress => { | ||
| 5023 | node_name.clearRetainingCapacity(); | ||
| 5024 | // <resinator> is a special string that indicates that the child | ||
| 5025 | // process has reached resinator's main function | ||
| 5026 | if (std.mem.eql(u8, body, "<resinator>")) { | ||
| 5027 | child_progress_node.setName(src_basename); | ||
| 5028 | } | ||
| 5029 | // Ignore 0-length strings since if multiple zig rc commands | ||
| 5030 | // are executed at the same time, only one will send progress strings | ||
| 5031 | // while the other(s) will send empty strings. | ||
| 5032 | else if (body.len > 0) { | ||
| 5033 | try node_name.appendSlice(arena, "build 'zig rc'... "); | ||
| 5034 | try node_name.appendSlice(arena, body); | ||
| 5035 | child_progress_node.setName(node_name.items); | ||
| 5036 | } | ||
| 5037 | }, | ||
| 5038 | else => {}, // ignore other messages | 5011 | else => {}, // ignore other messages |
| 5039 | } | 5012 | } |
| 5040 | 5013 | ||
| ... | @@ -5937,8 +5910,8 @@ pub fn lockAndParseLldStderr(comp: *Compilation, prefix: []const u8, stderr: []c | ... | @@ -5937,8 +5910,8 @@ pub fn lockAndParseLldStderr(comp: *Compilation, prefix: []const u8, stderr: []c |
| 5937 | } | 5910 | } |
| 5938 | 5911 | ||
| 5939 | pub fn dump_argv(argv: []const []const u8) void { | 5912 | pub fn dump_argv(argv: []const []const u8) void { |
| 5940 | std.debug.getStderrMutex().lock(); | 5913 | std.debug.lockStdErr(); |
| 5941 | defer std.debug.getStderrMutex().unlock(); | 5914 | defer std.debug.unlockStdErr(); |
| 5942 | const stderr = std.io.getStdErr().writer(); | 5915 | const stderr = std.io.getStdErr().writer(); |
| 5943 | for (argv[0 .. argv.len - 1]) |arg| { | 5916 | for (argv[0 .. argv.len - 1]) |arg| { |
| 5944 | nosuspend stderr.print("{s} ", .{arg}) catch return; | 5917 | nosuspend stderr.print("{s} ", .{arg}) catch return; |
| ... | @@ -5989,14 +5962,13 @@ pub fn updateSubCompilation( | ... | @@ -5989,14 +5962,13 @@ pub fn updateSubCompilation( |
| 5989 | parent_comp: *Compilation, | 5962 | parent_comp: *Compilation, |
| 5990 | sub_comp: *Compilation, | 5963 | sub_comp: *Compilation, |
| 5991 | misc_task: MiscTask, | 5964 | misc_task: MiscTask, |
| 5992 | prog_node: *std.Progress.Node, | 5965 | prog_node: std.Progress.Node, |
| 5993 | ) !void { | 5966 | ) !void { |
| 5994 | { | 5967 | { |
| 5995 | var sub_node = prog_node.start(@tagName(misc_task), 0); | 5968 | const sub_node = prog_node.start(@tagName(misc_task), 0); |
| 5996 | sub_node.activate(); | ||
| 5997 | defer sub_node.end(); | 5969 | defer sub_node.end(); |
| 5998 | 5970 | ||
| 5999 | try sub_comp.update(prog_node); | 5971 | try sub_comp.update(sub_node); |
| 6000 | } | 5972 | } |
| 6001 | 5973 | ||
| 6002 | // Look for compilation errors in this sub compilation | 5974 | // Look for compilation errors in this sub compilation |
| ... | @@ -6024,7 +5996,7 @@ fn buildOutputFromZig( | ... | @@ -6024,7 +5996,7 @@ fn buildOutputFromZig( |
| 6024 | output_mode: std.builtin.OutputMode, | 5996 | output_mode: std.builtin.OutputMode, |
| 6025 | out: *?CRTFile, | 5997 | out: *?CRTFile, |
| 6026 | misc_task_tag: MiscTask, | 5998 | misc_task_tag: MiscTask, |
| 6027 | prog_node: *std.Progress.Node, | 5999 | prog_node: std.Progress.Node, |
| 6028 | ) !void { | 6000 | ) !void { |
| 6029 | const tracy_trace = trace(@src()); | 6001 | const tracy_trace = trace(@src()); |
| 6030 | defer tracy_trace.end(); | 6002 | defer tracy_trace.end(); |
| ... | @@ -6131,7 +6103,7 @@ pub fn build_crt_file( | ... | @@ -6131,7 +6103,7 @@ pub fn build_crt_file( |
| 6131 | root_name: []const u8, | 6103 | root_name: []const u8, |
| 6132 | output_mode: std.builtin.OutputMode, | 6104 | output_mode: std.builtin.OutputMode, |
| 6133 | misc_task_tag: MiscTask, | 6105 | misc_task_tag: MiscTask, |
| 6134 | prog_node: *std.Progress.Node, | 6106 | prog_node: std.Progress.Node, |
| 6135 | /// These elements have to get mutated to add the owner module after it is | 6107 | /// These elements have to get mutated to add the owner module after it is |
| 6136 | /// created within this function. | 6108 | /// created within this function. |
| 6137 | c_source_files: []CSourceFile, | 6109 | c_source_files: []CSourceFile, |
src/Module.zig+28-11| ... | @@ -66,6 +66,7 @@ root_mod: *Package.Module, | ... | @@ -66,6 +66,7 @@ root_mod: *Package.Module, |
| 66 | main_mod: *Package.Module, | 66 | main_mod: *Package.Module, |
| 67 | std_mod: *Package.Module, | 67 | std_mod: *Package.Module, |
| 68 | sema_prog_node: std.Progress.Node = undefined, | 68 | sema_prog_node: std.Progress.Node = undefined, |
| 69 | codegen_prog_node: std.Progress.Node = undefined, | ||
| 69 | 70 | ||
| 70 | /// Used by AstGen worker to load and store ZIR cache. | 71 | /// Used by AstGen worker to load and store ZIR cache. |
| 71 | global_zir_cache: Compilation.Directory, | 72 | global_zir_cache: Compilation.Directory, |
| ... | @@ -2942,11 +2943,12 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void { | ... | @@ -2942,11 +2943,12 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void { |
| 2942 | const tracy = trace(@src()); | 2943 | const tracy = trace(@src()); |
| 2943 | defer tracy.end(); | 2944 | defer tracy.end(); |
| 2944 | 2945 | ||
| 2946 | const ip = &mod.intern_pool; | ||
| 2945 | const decl = mod.declPtr(decl_index); | 2947 | const decl = mod.declPtr(decl_index); |
| 2946 | 2948 | ||
| 2947 | log.debug("ensureDeclAnalyzed '{d}' (name '{}')", .{ | 2949 | log.debug("ensureDeclAnalyzed '{d}' (name '{}')", .{ |
| 2948 | @intFromEnum(decl_index), | 2950 | @intFromEnum(decl_index), |
| 2949 | decl.name.fmt(&mod.intern_pool), | 2951 | decl.name.fmt(ip), |
| 2950 | }); | 2952 | }); |
| 2951 | 2953 | ||
| 2952 | // Determine whether or not this Decl is outdated, i.e. requires re-analysis | 2954 | // Determine whether or not this Decl is outdated, i.e. requires re-analysis |
| ... | @@ -2991,10 +2993,6 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void { | ... | @@ -2991,10 +2993,6 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void { |
| 2991 | try mod.deleteDeclExports(decl_index); | 2993 | try mod.deleteDeclExports(decl_index); |
| 2992 | } | 2994 | } |
| 2993 | 2995 | ||
| 2994 | var decl_prog_node = mod.sema_prog_node.start("", 0); | ||
| 2995 | decl_prog_node.activate(); | ||
| 2996 | defer decl_prog_node.end(); | ||
| 2997 | |||
| 2998 | const sema_result: SemaDeclResult = blk: { | 2996 | const sema_result: SemaDeclResult = blk: { |
| 2999 | if (decl.zir_decl_index == .none and !mod.declIsRoot(decl_index)) { | 2997 | if (decl.zir_decl_index == .none and !mod.declIsRoot(decl_index)) { |
| 3000 | // Anonymous decl. We don't semantically analyze these. | 2998 | // Anonymous decl. We don't semantically analyze these. |
| ... | @@ -3012,6 +3010,9 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void { | ... | @@ -3012,6 +3010,9 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void { |
| 3012 | }; | 3010 | }; |
| 3013 | } | 3011 | } |
| 3014 | 3012 | ||
| 3013 | const decl_prog_node = mod.sema_prog_node.start((try decl.fullyQualifiedName(mod)).toSlice(ip), 0); | ||
| 3014 | defer decl_prog_node.end(); | ||
| 3015 | |||
| 3015 | break :blk mod.semaDecl(decl_index) catch |err| switch (err) { | 3016 | break :blk mod.semaDecl(decl_index) catch |err| switch (err) { |
| 3016 | error.AnalysisFail => { | 3017 | error.AnalysisFail => { |
| 3017 | if (decl.analysis == .in_progress) { | 3018 | if (decl.analysis == .in_progress) { |
| ... | @@ -3215,6 +3216,9 @@ pub fn ensureFuncBodyAnalyzed(zcu: *Zcu, maybe_coerced_func_index: InternPool.In | ... | @@ -3215,6 +3216,9 @@ pub fn ensureFuncBodyAnalyzed(zcu: *Zcu, maybe_coerced_func_index: InternPool.In |
| 3215 | }; | 3216 | }; |
| 3216 | } | 3217 | } |
| 3217 | 3218 | ||
| 3219 | const codegen_prog_node = zcu.codegen_prog_node.start((try decl.fullyQualifiedName(zcu)).toSlice(ip), 0); | ||
| 3220 | defer codegen_prog_node.end(); | ||
| 3221 | |||
| 3218 | if (comp.bin_file) |lf| { | 3222 | if (comp.bin_file) |lf| { |
| 3219 | lf.updateFunc(zcu, func_index, air, liveness) catch |err| switch (err) { | 3223 | lf.updateFunc(zcu, func_index, air, liveness) catch |err| switch (err) { |
| 3220 | error.OutOfMemory => return error.OutOfMemory, | 3224 | error.OutOfMemory => return error.OutOfMemory, |
| ... | @@ -4500,6 +4504,9 @@ pub fn analyzeFnBody(mod: *Module, func_index: InternPool.Index, arena: Allocato | ... | @@ -4500,6 +4504,9 @@ pub fn analyzeFnBody(mod: *Module, func_index: InternPool.Index, arena: Allocato |
| 4500 | log.debug("finish func name '{}'", .{(decl.fullyQualifiedName(mod) catch break :blk).fmt(ip)}); | 4504 | log.debug("finish func name '{}'", .{(decl.fullyQualifiedName(mod) catch break :blk).fmt(ip)}); |
| 4501 | } | 4505 | } |
| 4502 | 4506 | ||
| 4507 | const decl_prog_node = mod.sema_prog_node.start((try decl.fullyQualifiedName(mod)).toSlice(ip), 0); | ||
| 4508 | defer decl_prog_node.end(); | ||
| 4509 | |||
| 4503 | mod.intern_pool.removeDependenciesForDepender(gpa, InternPool.Depender.wrap(.{ .func = func_index })); | 4510 | mod.intern_pool.removeDependenciesForDepender(gpa, InternPool.Depender.wrap(.{ .func = func_index })); |
| 4504 | 4511 | ||
| 4505 | var comptime_err_ret_trace = std.ArrayList(SrcLoc).init(gpa); | 4512 | var comptime_err_ret_trace = std.ArrayList(SrcLoc).init(gpa); |
| ... | @@ -5316,7 +5323,7 @@ fn handleUpdateExports( | ... | @@ -5316,7 +5323,7 @@ fn handleUpdateExports( |
| 5316 | 5323 | ||
| 5317 | pub fn populateTestFunctions( | 5324 | pub fn populateTestFunctions( |
| 5318 | mod: *Module, | 5325 | mod: *Module, |
| 5319 | main_progress_node: *std.Progress.Node, | 5326 | main_progress_node: std.Progress.Node, |
| 5320 | ) !void { | 5327 | ) !void { |
| 5321 | const gpa = mod.gpa; | 5328 | const gpa = mod.gpa; |
| 5322 | const ip = &mod.intern_pool; | 5329 | const ip = &mod.intern_pool; |
| ... | @@ -5333,13 +5340,13 @@ pub fn populateTestFunctions( | ... | @@ -5333,13 +5340,13 @@ pub fn populateTestFunctions( |
| 5333 | // We have to call `ensureDeclAnalyzed` here in case `builtin.test_functions` | 5340 | // We have to call `ensureDeclAnalyzed` here in case `builtin.test_functions` |
| 5334 | // was not referenced by start code. | 5341 | // was not referenced by start code. |
| 5335 | mod.sema_prog_node = main_progress_node.start("Semantic Analysis", 0); | 5342 | mod.sema_prog_node = main_progress_node.start("Semantic Analysis", 0); |
| 5336 | mod.sema_prog_node.activate(); | ||
| 5337 | defer { | 5343 | defer { |
| 5338 | mod.sema_prog_node.end(); | 5344 | mod.sema_prog_node.end(); |
| 5339 | mod.sema_prog_node = undefined; | 5345 | mod.sema_prog_node = undefined; |
| 5340 | } | 5346 | } |
| 5341 | try mod.ensureDeclAnalyzed(decl_index); | 5347 | try mod.ensureDeclAnalyzed(decl_index); |
| 5342 | } | 5348 | } |
| 5349 | |||
| 5343 | const decl = mod.declPtr(decl_index); | 5350 | const decl = mod.declPtr(decl_index); |
| 5344 | const test_fn_ty = decl.typeOf(mod).slicePtrFieldType(mod).childType(mod); | 5351 | const test_fn_ty = decl.typeOf(mod).slicePtrFieldType(mod).childType(mod); |
| 5345 | 5352 | ||
| ... | @@ -5440,21 +5447,32 @@ pub fn populateTestFunctions( | ... | @@ -5440,21 +5447,32 @@ pub fn populateTestFunctions( |
| 5440 | decl.val = new_val; | 5447 | decl.val = new_val; |
| 5441 | decl.has_tv = true; | 5448 | decl.has_tv = true; |
| 5442 | } | 5449 | } |
| 5443 | try mod.linkerUpdateDecl(decl_index); | 5450 | { |
| 5451 | mod.codegen_prog_node = main_progress_node.start("Code Generation", 0); | ||
| 5452 | defer { | ||
| 5453 | mod.codegen_prog_node.end(); | ||
| 5454 | mod.codegen_prog_node = undefined; | ||
| 5455 | } | ||
| 5456 | |||
| 5457 | try mod.linkerUpdateDecl(decl_index); | ||
| 5458 | } | ||
| 5444 | } | 5459 | } |
| 5445 | 5460 | ||
| 5446 | pub fn linkerUpdateDecl(zcu: *Zcu, decl_index: Decl.Index) !void { | 5461 | pub fn linkerUpdateDecl(zcu: *Zcu, decl_index: Decl.Index) !void { |
| 5447 | const comp = zcu.comp; | 5462 | const comp = zcu.comp; |
| 5448 | 5463 | ||
| 5464 | const decl = zcu.declPtr(decl_index); | ||
| 5465 | |||
| 5466 | const codegen_prog_node = zcu.codegen_prog_node.start((try decl.fullyQualifiedName(zcu)).toSlice(&zcu.intern_pool), 0); | ||
| 5467 | defer codegen_prog_node.end(); | ||
| 5468 | |||
| 5449 | if (comp.bin_file) |lf| { | 5469 | if (comp.bin_file) |lf| { |
| 5450 | lf.updateDecl(zcu, decl_index) catch |err| switch (err) { | 5470 | lf.updateDecl(zcu, decl_index) catch |err| switch (err) { |
| 5451 | error.OutOfMemory => return error.OutOfMemory, | 5471 | error.OutOfMemory => return error.OutOfMemory, |
| 5452 | error.AnalysisFail => { | 5472 | error.AnalysisFail => { |
| 5453 | const decl = zcu.declPtr(decl_index); | ||
| 5454 | decl.analysis = .codegen_failure; | 5473 | decl.analysis = .codegen_failure; |
| 5455 | }, | 5474 | }, |
| 5456 | else => { | 5475 | else => { |
| 5457 | const decl = zcu.declPtr(decl_index); | ||
| 5458 | const gpa = zcu.gpa; | 5476 | const gpa = zcu.gpa; |
| 5459 | try zcu.failed_decls.ensureUnusedCapacity(gpa, 1); | 5477 | try zcu.failed_decls.ensureUnusedCapacity(gpa, 1); |
| 5460 | zcu.failed_decls.putAssumeCapacityNoClobber(decl_index, try ErrorMsg.create( | 5478 | zcu.failed_decls.putAssumeCapacityNoClobber(decl_index, try ErrorMsg.create( |
| ... | @@ -5472,7 +5490,6 @@ pub fn linkerUpdateDecl(zcu: *Zcu, decl_index: Decl.Index) !void { | ... | @@ -5472,7 +5490,6 @@ pub fn linkerUpdateDecl(zcu: *Zcu, decl_index: Decl.Index) !void { |
| 5472 | llvm_object.updateDecl(zcu, decl_index) catch |err| switch (err) { | 5490 | llvm_object.updateDecl(zcu, decl_index) catch |err| switch (err) { |
| 5473 | error.OutOfMemory => return error.OutOfMemory, | 5491 | error.OutOfMemory => return error.OutOfMemory, |
| 5474 | error.AnalysisFail => { | 5492 | error.AnalysisFail => { |
| 5475 | const decl = zcu.declPtr(decl_index); | ||
| 5476 | decl.analysis = .codegen_failure; | 5493 | decl.analysis = .codegen_failure; |
| 5477 | }, | 5494 | }, |
| 5478 | }; | 5495 | }; |
src/Package/Fetch.zig+5-9| ... | @@ -35,7 +35,7 @@ name_tok: std.zig.Ast.TokenIndex, | ... | @@ -35,7 +35,7 @@ name_tok: std.zig.Ast.TokenIndex, |
| 35 | lazy_status: LazyStatus, | 35 | lazy_status: LazyStatus, |
| 36 | parent_package_root: Cache.Path, | 36 | parent_package_root: Cache.Path, |
| 37 | parent_manifest_ast: ?*const std.zig.Ast, | 37 | parent_manifest_ast: ?*const std.zig.Ast, |
| 38 | prog_node: *std.Progress.Node, | 38 | prog_node: std.Progress.Node, |
| 39 | job_queue: *JobQueue, | 39 | job_queue: *JobQueue, |
| 40 | /// If true, don't add an error for a missing hash. This flag is not passed | 40 | /// If true, don't add an error for a missing hash. This flag is not passed |
| 41 | /// down to recursive dependencies. It's intended to be used only be the CLI. | 41 | /// down to recursive dependencies. It's intended to be used only be the CLI. |
| ... | @@ -720,8 +720,7 @@ fn queueJobsForDeps(f: *Fetch) RunError!void { | ... | @@ -720,8 +720,7 @@ fn queueJobsForDeps(f: *Fetch) RunError!void { |
| 720 | }; | 720 | }; |
| 721 | } | 721 | } |
| 722 | 722 | ||
| 723 | // job_queue mutex is locked so this is OK. | 723 | f.prog_node.increaseEstimatedTotalItems(new_fetch_index); |
| 724 | f.prog_node.unprotected_estimated_total_items += new_fetch_index; | ||
| 725 | 724 | ||
| 726 | break :nf .{ new_fetches[0..new_fetch_index], prog_names[0..new_fetch_index] }; | 725 | break :nf .{ new_fetches[0..new_fetch_index], prog_names[0..new_fetch_index] }; |
| 727 | }; | 726 | }; |
| ... | @@ -751,9 +750,8 @@ pub fn relativePathDigest( | ... | @@ -751,9 +750,8 @@ pub fn relativePathDigest( |
| 751 | } | 750 | } |
| 752 | 751 | ||
| 753 | pub fn workerRun(f: *Fetch, prog_name: []const u8) void { | 752 | pub fn workerRun(f: *Fetch, prog_name: []const u8) void { |
| 754 | var prog_node = f.prog_node.start(prog_name, 0); | 753 | const prog_node = f.prog_node.start(prog_name, 0); |
| 755 | defer prog_node.end(); | 754 | defer prog_node.end(); |
| 756 | prog_node.activate(); | ||
| 757 | 755 | ||
| 758 | run(f) catch |err| switch (err) { | 756 | run(f) catch |err| switch (err) { |
| 759 | error.OutOfMemory => f.oom_flag = true, | 757 | error.OutOfMemory => f.oom_flag = true, |
| ... | @@ -1311,9 +1309,8 @@ fn unpackGitPack(f: *Fetch, out_dir: fs.Dir, resource: *Resource) anyerror!Unpac | ... | @@ -1311,9 +1309,8 @@ fn unpackGitPack(f: *Fetch, out_dir: fs.Dir, resource: *Resource) anyerror!Unpac |
| 1311 | var index_file = try pack_dir.createFile("pkg.idx", .{ .read = true }); | 1309 | var index_file = try pack_dir.createFile("pkg.idx", .{ .read = true }); |
| 1312 | defer index_file.close(); | 1310 | defer index_file.close(); |
| 1313 | { | 1311 | { |
| 1314 | var index_prog_node = f.prog_node.start("Index pack", 0); | 1312 | const index_prog_node = f.prog_node.start("Index pack", 0); |
| 1315 | defer index_prog_node.end(); | 1313 | defer index_prog_node.end(); |
| 1316 | index_prog_node.activate(); | ||
| 1317 | var index_buffered_writer = std.io.bufferedWriter(index_file.writer()); | 1314 | var index_buffered_writer = std.io.bufferedWriter(index_file.writer()); |
| 1318 | try git.indexPack(gpa, pack_file, index_buffered_writer.writer()); | 1315 | try git.indexPack(gpa, pack_file, index_buffered_writer.writer()); |
| 1319 | try index_buffered_writer.flush(); | 1316 | try index_buffered_writer.flush(); |
| ... | @@ -1321,9 +1318,8 @@ fn unpackGitPack(f: *Fetch, out_dir: fs.Dir, resource: *Resource) anyerror!Unpac | ... | @@ -1321,9 +1318,8 @@ fn unpackGitPack(f: *Fetch, out_dir: fs.Dir, resource: *Resource) anyerror!Unpac |
| 1321 | } | 1318 | } |
| 1322 | 1319 | ||
| 1323 | { | 1320 | { |
| 1324 | var checkout_prog_node = f.prog_node.start("Checkout", 0); | 1321 | const checkout_prog_node = f.prog_node.start("Checkout", 0); |
| 1325 | defer checkout_prog_node.end(); | 1322 | defer checkout_prog_node.end(); |
| 1326 | checkout_prog_node.activate(); | ||
| 1327 | var repository = try git.Repository.init(gpa, pack_file, index_file); | 1323 | var repository = try git.Repository.init(gpa, pack_file, index_file); |
| 1328 | defer repository.deinit(); | 1324 | defer repository.deinit(); |
| 1329 | var diagnostics: git.Diagnostics = .{ .allocator = arena }; | 1325 | var diagnostics: git.Diagnostics = .{ .allocator = arena }; |
src/glibc.zig+3-3| ... | @@ -160,7 +160,7 @@ pub const CRTFile = enum { | ... | @@ -160,7 +160,7 @@ pub const CRTFile = enum { |
| 160 | libc_nonshared_a, | 160 | libc_nonshared_a, |
| 161 | }; | 161 | }; |
| 162 | 162 | ||
| 163 | pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile, prog_node: *std.Progress.Node) !void { | 163 | pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile, prog_node: std.Progress.Node) !void { |
| 164 | if (!build_options.have_llvm) { | 164 | if (!build_options.have_llvm) { |
| 165 | return error.ZigCompilerNotBuiltWithLLVMExtensions; | 165 | return error.ZigCompilerNotBuiltWithLLVMExtensions; |
| 166 | } | 166 | } |
| ... | @@ -658,7 +658,7 @@ pub const BuiltSharedObjects = struct { | ... | @@ -658,7 +658,7 @@ pub const BuiltSharedObjects = struct { |
| 658 | 658 | ||
| 659 | const all_map_basename = "all.map"; | 659 | const all_map_basename = "all.map"; |
| 660 | 660 | ||
| 661 | pub fn buildSharedObjects(comp: *Compilation, prog_node: *std.Progress.Node) !void { | 661 | pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) !void { |
| 662 | const tracy = trace(@src()); | 662 | const tracy = trace(@src()); |
| 663 | defer tracy.end(); | 663 | defer tracy.end(); |
| 664 | 664 | ||
| ... | @@ -1065,7 +1065,7 @@ fn buildSharedLib( | ... | @@ -1065,7 +1065,7 @@ fn buildSharedLib( |
| 1065 | bin_directory: Compilation.Directory, | 1065 | bin_directory: Compilation.Directory, |
| 1066 | asm_file_basename: []const u8, | 1066 | asm_file_basename: []const u8, |
| 1067 | lib: Lib, | 1067 | lib: Lib, |
| 1068 | prog_node: *std.Progress.Node, | 1068 | prog_node: std.Progress.Node, |
| 1069 | ) !void { | 1069 | ) !void { |
| 1070 | const tracy = trace(@src()); | 1070 | const tracy = trace(@src()); |
| 1071 | defer tracy.end(); | 1071 | defer tracy.end(); |
src/libcxx.zig+2-2| ... | @@ -113,7 +113,7 @@ pub const BuildError = error{ | ... | @@ -113,7 +113,7 @@ pub const BuildError = error{ |
| 113 | ZigCompilerNotBuiltWithLLVMExtensions, | 113 | ZigCompilerNotBuiltWithLLVMExtensions, |
| 114 | }; | 114 | }; |
| 115 | 115 | ||
| 116 | pub fn buildLibCXX(comp: *Compilation, prog_node: *std.Progress.Node) BuildError!void { | 116 | pub fn buildLibCXX(comp: *Compilation, prog_node: std.Progress.Node) BuildError!void { |
| 117 | if (!build_options.have_llvm) { | 117 | if (!build_options.have_llvm) { |
| 118 | return error.ZigCompilerNotBuiltWithLLVMExtensions; | 118 | return error.ZigCompilerNotBuiltWithLLVMExtensions; |
| 119 | } | 119 | } |
| ... | @@ -357,7 +357,7 @@ pub fn buildLibCXX(comp: *Compilation, prog_node: *std.Progress.Node) BuildError | ... | @@ -357,7 +357,7 @@ pub fn buildLibCXX(comp: *Compilation, prog_node: *std.Progress.Node) BuildError |
| 357 | comp.libcxx_static_lib = try sub_compilation.toCrtFile(); | 357 | comp.libcxx_static_lib = try sub_compilation.toCrtFile(); |
| 358 | } | 358 | } |
| 359 | 359 | ||
| 360 | pub fn buildLibCXXABI(comp: *Compilation, prog_node: *std.Progress.Node) BuildError!void { | 360 | pub fn buildLibCXXABI(comp: *Compilation, prog_node: std.Progress.Node) BuildError!void { |
| 361 | if (!build_options.have_llvm) { | 361 | if (!build_options.have_llvm) { |
| 362 | return error.ZigCompilerNotBuiltWithLLVMExtensions; | 362 | return error.ZigCompilerNotBuiltWithLLVMExtensions; |
| 363 | } | 363 | } |
src/libtsan.zig+1-1| ... | @@ -13,7 +13,7 @@ pub const BuildError = error{ | ... | @@ -13,7 +13,7 @@ pub const BuildError = error{ |
| 13 | TSANUnsupportedCPUArchitecture, | 13 | TSANUnsupportedCPUArchitecture, |
| 14 | }; | 14 | }; |
| 15 | 15 | ||
| 16 | pub fn buildTsan(comp: *Compilation, prog_node: *std.Progress.Node) BuildError!void { | 16 | pub fn buildTsan(comp: *Compilation, prog_node: std.Progress.Node) BuildError!void { |
| 17 | if (!build_options.have_llvm) { | 17 | if (!build_options.have_llvm) { |
| 18 | return error.ZigCompilerNotBuiltWithLLVMExtensions; | 18 | return error.ZigCompilerNotBuiltWithLLVMExtensions; |
| 19 | } | 19 | } |
src/libunwind.zig+1-1| ... | @@ -14,7 +14,7 @@ pub const BuildError = error{ | ... | @@ -14,7 +14,7 @@ pub const BuildError = error{ |
| 14 | ZigCompilerNotBuiltWithLLVMExtensions, | 14 | ZigCompilerNotBuiltWithLLVMExtensions, |
| 15 | }; | 15 | }; |
| 16 | 16 | ||
| 17 | pub fn buildStaticLib(comp: *Compilation, prog_node: *std.Progress.Node) BuildError!void { | 17 | pub fn buildStaticLib(comp: *Compilation, prog_node: std.Progress.Node) BuildError!void { |
| 18 | if (!build_options.have_llvm) { | 18 | if (!build_options.have_llvm) { |
| 19 | return error.ZigCompilerNotBuiltWithLLVMExtensions; | 19 | return error.ZigCompilerNotBuiltWithLLVMExtensions; |
| 20 | } | 20 | } |
src/link.zig+4-4| ... | @@ -535,7 +535,7 @@ pub const File = struct { | ... | @@ -535,7 +535,7 @@ pub const File = struct { |
| 535 | /// Commit pending changes and write headers. Takes into account final output mode | 535 | /// Commit pending changes and write headers. Takes into account final output mode |
| 536 | /// and `use_lld`, not only `effectiveOutputMode`. | 536 | /// and `use_lld`, not only `effectiveOutputMode`. |
| 537 | /// `arena` has the lifetime of the call to `Compilation.update`. | 537 | /// `arena` has the lifetime of the call to `Compilation.update`. |
| 538 | pub fn flush(base: *File, arena: Allocator, prog_node: *std.Progress.Node) FlushError!void { | 538 | pub fn flush(base: *File, arena: Allocator, prog_node: std.Progress.Node) FlushError!void { |
| 539 | if (build_options.only_c) { | 539 | if (build_options.only_c) { |
| 540 | assert(base.tag == .c); | 540 | assert(base.tag == .c); |
| 541 | return @as(*C, @fieldParentPtr("base", base)).flush(arena, prog_node); | 541 | return @as(*C, @fieldParentPtr("base", base)).flush(arena, prog_node); |
| ... | @@ -572,7 +572,7 @@ pub const File = struct { | ... | @@ -572,7 +572,7 @@ pub const File = struct { |
| 572 | 572 | ||
| 573 | /// Commit pending changes and write headers. Works based on `effectiveOutputMode` | 573 | /// Commit pending changes and write headers. Works based on `effectiveOutputMode` |
| 574 | /// rather than final output mode. | 574 | /// rather than final output mode. |
| 575 | pub fn flushModule(base: *File, arena: Allocator, prog_node: *std.Progress.Node) FlushError!void { | 575 | pub fn flushModule(base: *File, arena: Allocator, prog_node: std.Progress.Node) FlushError!void { |
| 576 | switch (base.tag) { | 576 | switch (base.tag) { |
| 577 | inline else => |tag| { | 577 | inline else => |tag| { |
| 578 | if (tag != .c and build_options.only_c) unreachable; | 578 | if (tag != .c and build_options.only_c) unreachable; |
| ... | @@ -688,7 +688,7 @@ pub const File = struct { | ... | @@ -688,7 +688,7 @@ pub const File = struct { |
| 688 | } | 688 | } |
| 689 | } | 689 | } |
| 690 | 690 | ||
| 691 | pub fn linkAsArchive(base: *File, arena: Allocator, prog_node: *std.Progress.Node) FlushError!void { | 691 | pub fn linkAsArchive(base: *File, arena: Allocator, prog_node: std.Progress.Node) FlushError!void { |
| 692 | const tracy = trace(@src()); | 692 | const tracy = trace(@src()); |
| 693 | defer tracy.end(); | 693 | defer tracy.end(); |
| 694 | 694 | ||
| ... | @@ -966,7 +966,7 @@ pub const File = struct { | ... | @@ -966,7 +966,7 @@ pub const File = struct { |
| 966 | base: File, | 966 | base: File, |
| 967 | arena: Allocator, | 967 | arena: Allocator, |
| 968 | llvm_object: *LlvmObject, | 968 | llvm_object: *LlvmObject, |
| 969 | prog_node: *std.Progress.Node, | 969 | prog_node: std.Progress.Node, |
| 970 | ) !void { | 970 | ) !void { |
| 971 | return base.comp.emitLlvmObject(arena, base.emit, .{ | 971 | return base.comp.emitLlvmObject(arena, base.emit, .{ |
| 972 | .directory = null, | 972 | .directory = null, |
src/link/C.zig+3-4| ... | @@ -370,7 +370,7 @@ pub fn updateDeclLineNumber(self: *C, zcu: *Zcu, decl_index: InternPool.DeclInde | ... | @@ -370,7 +370,7 @@ pub fn updateDeclLineNumber(self: *C, zcu: *Zcu, decl_index: InternPool.DeclInde |
| 370 | _ = decl_index; | 370 | _ = decl_index; |
| 371 | } | 371 | } |
| 372 | 372 | ||
| 373 | pub fn flush(self: *C, arena: Allocator, prog_node: *std.Progress.Node) !void { | 373 | pub fn flush(self: *C, arena: Allocator, prog_node: std.Progress.Node) !void { |
| 374 | return self.flushModule(arena, prog_node); | 374 | return self.flushModule(arena, prog_node); |
| 375 | } | 375 | } |
| 376 | 376 | ||
| ... | @@ -389,14 +389,13 @@ fn abiDefines(self: *C, target: std.Target) !std.ArrayList(u8) { | ... | @@ -389,14 +389,13 @@ fn abiDefines(self: *C, target: std.Target) !std.ArrayList(u8) { |
| 389 | return defines; | 389 | return defines; |
| 390 | } | 390 | } |
| 391 | 391 | ||
| 392 | pub fn flushModule(self: *C, arena: Allocator, prog_node: *std.Progress.Node) !void { | 392 | pub fn flushModule(self: *C, arena: Allocator, prog_node: std.Progress.Node) !void { |
| 393 | _ = arena; // Has the same lifetime as the call to Compilation.update. | 393 | _ = arena; // Has the same lifetime as the call to Compilation.update. |
| 394 | 394 | ||
| 395 | const tracy = trace(@src()); | 395 | const tracy = trace(@src()); |
| 396 | defer tracy.end(); | 396 | defer tracy.end(); |
| 397 | 397 | ||
| 398 | var sub_prog_node = prog_node.start("Flush Module", 0); | 398 | const sub_prog_node = prog_node.start("Flush Module", 0); |
| 399 | sub_prog_node.activate(); | ||
| 400 | defer sub_prog_node.end(); | 399 | defer sub_prog_node.end(); |
| 401 | 400 | ||
| 402 | const comp = self.base.comp; | 401 | const comp = self.base.comp; |
src/link/Coff.zig+3-4| ... | @@ -1702,7 +1702,7 @@ fn resolveGlobalSymbol(self: *Coff, current: SymbolWithLoc) !void { | ... | @@ -1702,7 +1702,7 @@ fn resolveGlobalSymbol(self: *Coff, current: SymbolWithLoc) !void { |
| 1702 | gop.value_ptr.* = current; | 1702 | gop.value_ptr.* = current; |
| 1703 | } | 1703 | } |
| 1704 | 1704 | ||
| 1705 | pub fn flush(self: *Coff, arena: Allocator, prog_node: *std.Progress.Node) link.File.FlushError!void { | 1705 | pub fn flush(self: *Coff, arena: Allocator, prog_node: std.Progress.Node) link.File.FlushError!void { |
| 1706 | const comp = self.base.comp; | 1706 | const comp = self.base.comp; |
| 1707 | const use_lld = build_options.have_llvm and comp.config.use_lld; | 1707 | const use_lld = build_options.have_llvm and comp.config.use_lld; |
| 1708 | if (use_lld) { | 1708 | if (use_lld) { |
| ... | @@ -1714,7 +1714,7 @@ pub fn flush(self: *Coff, arena: Allocator, prog_node: *std.Progress.Node) link. | ... | @@ -1714,7 +1714,7 @@ pub fn flush(self: *Coff, arena: Allocator, prog_node: *std.Progress.Node) link. |
| 1714 | } | 1714 | } |
| 1715 | } | 1715 | } |
| 1716 | 1716 | ||
| 1717 | pub fn flushModule(self: *Coff, arena: Allocator, prog_node: *std.Progress.Node) link.File.FlushError!void { | 1717 | pub fn flushModule(self: *Coff, arena: Allocator, prog_node: std.Progress.Node) link.File.FlushError!void { |
| 1718 | const tracy = trace(@src()); | 1718 | const tracy = trace(@src()); |
| 1719 | defer tracy.end(); | 1719 | defer tracy.end(); |
| 1720 | 1720 | ||
| ... | @@ -1726,8 +1726,7 @@ pub fn flushModule(self: *Coff, arena: Allocator, prog_node: *std.Progress.Node) | ... | @@ -1726,8 +1726,7 @@ pub fn flushModule(self: *Coff, arena: Allocator, prog_node: *std.Progress.Node) |
| 1726 | return; | 1726 | return; |
| 1727 | } | 1727 | } |
| 1728 | 1728 | ||
| 1729 | var sub_prog_node = prog_node.start("COFF Flush", 0); | 1729 | const sub_prog_node = prog_node.start("COFF Flush", 0); |
| 1730 | sub_prog_node.activate(); | ||
| 1731 | defer sub_prog_node.end(); | 1730 | defer sub_prog_node.end(); |
| 1732 | 1731 | ||
| 1733 | const module = comp.module orelse return error.LinkingWithoutZigSourceUnimplemented; | 1732 | const module = comp.module orelse return error.LinkingWithoutZigSourceUnimplemented; |
src/link/Coff/lld.zig+2-4| ... | @@ -16,7 +16,7 @@ const Allocator = mem.Allocator; | ... | @@ -16,7 +16,7 @@ const Allocator = mem.Allocator; |
| 16 | const Coff = @import("../Coff.zig"); | 16 | const Coff = @import("../Coff.zig"); |
| 17 | const Compilation = @import("../../Compilation.zig"); | 17 | const Compilation = @import("../../Compilation.zig"); |
| 18 | 18 | ||
| 19 | pub fn linkWithLLD(self: *Coff, arena: Allocator, prog_node: *std.Progress.Node) !void { | 19 | pub fn linkWithLLD(self: *Coff, arena: Allocator, prog_node: std.Progress.Node) !void { |
| 20 | const tracy = trace(@src()); | 20 | const tracy = trace(@src()); |
| 21 | defer tracy.end(); | 21 | defer tracy.end(); |
| 22 | 22 | ||
| ... | @@ -38,9 +38,7 @@ pub fn linkWithLLD(self: *Coff, arena: Allocator, prog_node: *std.Progress.Node) | ... | @@ -38,9 +38,7 @@ pub fn linkWithLLD(self: *Coff, arena: Allocator, prog_node: *std.Progress.Node) |
| 38 | } | 38 | } |
| 39 | } else null; | 39 | } else null; |
| 40 | 40 | ||
| 41 | var sub_prog_node = prog_node.start("LLD Link", 0); | 41 | const sub_prog_node = prog_node.start("LLD Link", 0); |
| 42 | sub_prog_node.activate(); | ||
| 43 | sub_prog_node.context.refresh(); | ||
| 44 | defer sub_prog_node.end(); | 42 | defer sub_prog_node.end(); |
| 45 | 43 | ||
| 46 | const is_lib = comp.config.output_mode == .Lib; | 44 | const is_lib = comp.config.output_mode == .Lib; |
src/link/Elf.zig+5-8| ... | @@ -1064,7 +1064,7 @@ pub fn markDirty(self: *Elf, shdr_index: u32) void { | ... | @@ -1064,7 +1064,7 @@ pub fn markDirty(self: *Elf, shdr_index: u32) void { |
| 1064 | } | 1064 | } |
| 1065 | } | 1065 | } |
| 1066 | 1066 | ||
| 1067 | pub fn flush(self: *Elf, arena: Allocator, prog_node: *std.Progress.Node) link.File.FlushError!void { | 1067 | pub fn flush(self: *Elf, arena: Allocator, prog_node: std.Progress.Node) link.File.FlushError!void { |
| 1068 | const use_lld = build_options.have_llvm and self.base.comp.config.use_lld; | 1068 | const use_lld = build_options.have_llvm and self.base.comp.config.use_lld; |
| 1069 | if (use_lld) { | 1069 | if (use_lld) { |
| 1070 | return self.linkWithLLD(arena, prog_node); | 1070 | return self.linkWithLLD(arena, prog_node); |
| ... | @@ -1072,7 +1072,7 @@ pub fn flush(self: *Elf, arena: Allocator, prog_node: *std.Progress.Node) link.F | ... | @@ -1072,7 +1072,7 @@ pub fn flush(self: *Elf, arena: Allocator, prog_node: *std.Progress.Node) link.F |
| 1072 | try self.flushModule(arena, prog_node); | 1072 | try self.flushModule(arena, prog_node); |
| 1073 | } | 1073 | } |
| 1074 | 1074 | ||
| 1075 | pub fn flushModule(self: *Elf, arena: Allocator, prog_node: *std.Progress.Node) link.File.FlushError!void { | 1075 | pub fn flushModule(self: *Elf, arena: Allocator, prog_node: std.Progress.Node) link.File.FlushError!void { |
| 1076 | const tracy = trace(@src()); | 1076 | const tracy = trace(@src()); |
| 1077 | defer tracy.end(); | 1077 | defer tracy.end(); |
| 1078 | 1078 | ||
| ... | @@ -1085,8 +1085,7 @@ pub fn flushModule(self: *Elf, arena: Allocator, prog_node: *std.Progress.Node) | ... | @@ -1085,8 +1085,7 @@ pub fn flushModule(self: *Elf, arena: Allocator, prog_node: *std.Progress.Node) |
| 1085 | if (use_lld) return; | 1085 | if (use_lld) return; |
| 1086 | } | 1086 | } |
| 1087 | 1087 | ||
| 1088 | var sub_prog_node = prog_node.start("ELF Flush", 0); | 1088 | const sub_prog_node = prog_node.start("ELF Flush", 0); |
| 1089 | sub_prog_node.activate(); | ||
| 1090 | defer sub_prog_node.end(); | 1089 | defer sub_prog_node.end(); |
| 1091 | 1090 | ||
| 1092 | const target = comp.root_mod.resolved_target.result; | 1091 | const target = comp.root_mod.resolved_target.result; |
| ... | @@ -2147,7 +2146,7 @@ fn scanRelocs(self: *Elf) !void { | ... | @@ -2147,7 +2146,7 @@ fn scanRelocs(self: *Elf) !void { |
| 2147 | } | 2146 | } |
| 2148 | } | 2147 | } |
| 2149 | 2148 | ||
| 2150 | fn linkWithLLD(self: *Elf, arena: Allocator, prog_node: *std.Progress.Node) !void { | 2149 | fn linkWithLLD(self: *Elf, arena: Allocator, prog_node: std.Progress.Node) !void { |
| 2151 | const tracy = trace(@src()); | 2150 | const tracy = trace(@src()); |
| 2152 | defer tracy.end(); | 2151 | defer tracy.end(); |
| 2153 | 2152 | ||
| ... | @@ -2169,9 +2168,7 @@ fn linkWithLLD(self: *Elf, arena: Allocator, prog_node: *std.Progress.Node) !voi | ... | @@ -2169,9 +2168,7 @@ fn linkWithLLD(self: *Elf, arena: Allocator, prog_node: *std.Progress.Node) !voi |
| 2169 | } | 2168 | } |
| 2170 | } else null; | 2169 | } else null; |
| 2171 | 2170 | ||
| 2172 | var sub_prog_node = prog_node.start("LLD Link", 0); | 2171 | const sub_prog_node = prog_node.start("LLD Link", 0); |
| 2173 | sub_prog_node.activate(); | ||
| 2174 | sub_prog_node.context.refresh(); | ||
| 2175 | defer sub_prog_node.end(); | 2172 | defer sub_prog_node.end(); |
| 2176 | 2173 | ||
| 2177 | const output_mode = comp.config.output_mode; | 2174 | const output_mode = comp.config.output_mode; |
src/link/MachO.zig+3-4| ... | @@ -360,11 +360,11 @@ pub fn deinit(self: *MachO) void { | ... | @@ -360,11 +360,11 @@ pub fn deinit(self: *MachO) void { |
| 360 | self.unwind_records.deinit(gpa); | 360 | self.unwind_records.deinit(gpa); |
| 361 | } | 361 | } |
| 362 | 362 | ||
| 363 | pub fn flush(self: *MachO, arena: Allocator, prog_node: *std.Progress.Node) link.File.FlushError!void { | 363 | pub fn flush(self: *MachO, arena: Allocator, prog_node: std.Progress.Node) link.File.FlushError!void { |
| 364 | try self.flushModule(arena, prog_node); | 364 | try self.flushModule(arena, prog_node); |
| 365 | } | 365 | } |
| 366 | 366 | ||
| 367 | pub fn flushModule(self: *MachO, arena: Allocator, prog_node: *std.Progress.Node) link.File.FlushError!void { | 367 | pub fn flushModule(self: *MachO, arena: Allocator, prog_node: std.Progress.Node) link.File.FlushError!void { |
| 368 | const tracy = trace(@src()); | 368 | const tracy = trace(@src()); |
| 369 | defer tracy.end(); | 369 | defer tracy.end(); |
| 370 | 370 | ||
| ... | @@ -375,8 +375,7 @@ pub fn flushModule(self: *MachO, arena: Allocator, prog_node: *std.Progress.Node | ... | @@ -375,8 +375,7 @@ pub fn flushModule(self: *MachO, arena: Allocator, prog_node: *std.Progress.Node |
| 375 | try self.base.emitLlvmObject(arena, llvm_object, prog_node); | 375 | try self.base.emitLlvmObject(arena, llvm_object, prog_node); |
| 376 | } | 376 | } |
| 377 | 377 | ||
| 378 | var sub_prog_node = prog_node.start("MachO Flush", 0); | 378 | const sub_prog_node = prog_node.start("MachO Flush", 0); |
| 379 | sub_prog_node.activate(); | ||
| 380 | defer sub_prog_node.end(); | 379 | defer sub_prog_node.end(); |
| 381 | 380 | ||
| 382 | const directory = self.base.emit.directory; | 381 | const directory = self.base.emit.directory; |
src/link/NvPtx.zig+2-2| ... | @@ -106,11 +106,11 @@ pub fn freeDecl(self: *NvPtx, decl_index: InternPool.DeclIndex) void { | ... | @@ -106,11 +106,11 @@ pub fn freeDecl(self: *NvPtx, decl_index: InternPool.DeclIndex) void { |
| 106 | return self.llvm_object.freeDecl(decl_index); | 106 | return self.llvm_object.freeDecl(decl_index); |
| 107 | } | 107 | } |
| 108 | 108 | ||
| 109 | pub fn flush(self: *NvPtx, arena: Allocator, prog_node: *std.Progress.Node) link.File.FlushError!void { | 109 | pub fn flush(self: *NvPtx, arena: Allocator, prog_node: std.Progress.Node) link.File.FlushError!void { |
| 110 | return self.flushModule(arena, prog_node); | 110 | return self.flushModule(arena, prog_node); |
| 111 | } | 111 | } |
| 112 | 112 | ||
| 113 | pub fn flushModule(self: *NvPtx, arena: Allocator, prog_node: *std.Progress.Node) link.File.FlushError!void { | 113 | pub fn flushModule(self: *NvPtx, arena: Allocator, prog_node: std.Progress.Node) link.File.FlushError!void { |
| 114 | if (build_options.skip_non_native) | 114 | if (build_options.skip_non_native) |
| 115 | @panic("Attempted to compile for architecture that was disabled by build configuration"); | 115 | @panic("Attempted to compile for architecture that was disabled by build configuration"); |
| 116 | 116 |
src/link/Plan9.zig+3-4| ... | @@ -604,7 +604,7 @@ fn allocateGotIndex(self: *Plan9) usize { | ... | @@ -604,7 +604,7 @@ fn allocateGotIndex(self: *Plan9) usize { |
| 604 | } | 604 | } |
| 605 | } | 605 | } |
| 606 | 606 | ||
| 607 | pub fn flush(self: *Plan9, arena: Allocator, prog_node: *std.Progress.Node) link.File.FlushError!void { | 607 | pub fn flush(self: *Plan9, arena: Allocator, prog_node: std.Progress.Node) link.File.FlushError!void { |
| 608 | const comp = self.base.comp; | 608 | const comp = self.base.comp; |
| 609 | const use_lld = build_options.have_llvm and comp.config.use_lld; | 609 | const use_lld = build_options.have_llvm and comp.config.use_lld; |
| 610 | assert(!use_lld); | 610 | assert(!use_lld); |
| ... | @@ -663,7 +663,7 @@ fn atomCount(self: *Plan9) usize { | ... | @@ -663,7 +663,7 @@ fn atomCount(self: *Plan9) usize { |
| 663 | return data_decl_count + fn_decl_count + unnamed_const_count + lazy_atom_count + extern_atom_count + anon_atom_count; | 663 | return data_decl_count + fn_decl_count + unnamed_const_count + lazy_atom_count + extern_atom_count + anon_atom_count; |
| 664 | } | 664 | } |
| 665 | 665 | ||
| 666 | pub fn flushModule(self: *Plan9, arena: Allocator, prog_node: *std.Progress.Node) link.File.FlushError!void { | 666 | pub fn flushModule(self: *Plan9, arena: Allocator, prog_node: std.Progress.Node) link.File.FlushError!void { |
| 667 | if (build_options.skip_non_native and builtin.object_format != .plan9) { | 667 | if (build_options.skip_non_native and builtin.object_format != .plan9) { |
| 668 | @panic("Attempted to compile for object format that was disabled by build configuration"); | 668 | @panic("Attempted to compile for object format that was disabled by build configuration"); |
| 669 | } | 669 | } |
| ... | @@ -677,8 +677,7 @@ pub fn flushModule(self: *Plan9, arena: Allocator, prog_node: *std.Progress.Node | ... | @@ -677,8 +677,7 @@ pub fn flushModule(self: *Plan9, arena: Allocator, prog_node: *std.Progress.Node |
| 677 | const tracy = trace(@src()); | 677 | const tracy = trace(@src()); |
| 678 | defer tracy.end(); | 678 | defer tracy.end(); |
| 679 | 679 | ||
| 680 | var sub_prog_node = prog_node.start("Flush Module", 0); | 680 | const sub_prog_node = prog_node.start("Flush Module", 0); |
| 681 | sub_prog_node.activate(); | ||
| 682 | defer sub_prog_node.end(); | 681 | defer sub_prog_node.end(); |
| 683 | 682 | ||
| 684 | log.debug("flushModule", .{}); | 683 | log.debug("flushModule", .{}); |
src/link/SpirV.zig+5-6| ... | @@ -193,11 +193,11 @@ pub fn freeDecl(self: *SpirV, decl_index: InternPool.DeclIndex) void { | ... | @@ -193,11 +193,11 @@ pub fn freeDecl(self: *SpirV, decl_index: InternPool.DeclIndex) void { |
| 193 | _ = decl_index; | 193 | _ = decl_index; |
| 194 | } | 194 | } |
| 195 | 195 | ||
| 196 | pub fn flush(self: *SpirV, arena: Allocator, prog_node: *std.Progress.Node) link.File.FlushError!void { | 196 | pub fn flush(self: *SpirV, arena: Allocator, prog_node: std.Progress.Node) link.File.FlushError!void { |
| 197 | return self.flushModule(arena, prog_node); | 197 | return self.flushModule(arena, prog_node); |
| 198 | } | 198 | } |
| 199 | 199 | ||
| 200 | pub fn flushModule(self: *SpirV, arena: Allocator, prog_node: *std.Progress.Node) link.File.FlushError!void { | 200 | pub fn flushModule(self: *SpirV, arena: Allocator, prog_node: std.Progress.Node) link.File.FlushError!void { |
| 201 | if (build_options.skip_non_native) { | 201 | if (build_options.skip_non_native) { |
| 202 | @panic("Attempted to compile for architecture that was disabled by build configuration"); | 202 | @panic("Attempted to compile for architecture that was disabled by build configuration"); |
| 203 | } | 203 | } |
| ... | @@ -205,8 +205,7 @@ pub fn flushModule(self: *SpirV, arena: Allocator, prog_node: *std.Progress.Node | ... | @@ -205,8 +205,7 @@ pub fn flushModule(self: *SpirV, arena: Allocator, prog_node: *std.Progress.Node |
| 205 | const tracy = trace(@src()); | 205 | const tracy = trace(@src()); |
| 206 | defer tracy.end(); | 206 | defer tracy.end(); |
| 207 | 207 | ||
| 208 | var sub_prog_node = prog_node.start("Flush Module", 0); | 208 | const sub_prog_node = prog_node.start("Flush Module", 0); |
| 209 | sub_prog_node.activate(); | ||
| 210 | defer sub_prog_node.end(); | 209 | defer sub_prog_node.end(); |
| 211 | 210 | ||
| 212 | const spv = &self.object.spv; | 211 | const spv = &self.object.spv; |
| ... | @@ -253,7 +252,7 @@ pub fn flushModule(self: *SpirV, arena: Allocator, prog_node: *std.Progress.Node | ... | @@ -253,7 +252,7 @@ pub fn flushModule(self: *SpirV, arena: Allocator, prog_node: *std.Progress.Node |
| 253 | const module = try spv.finalize(arena, target); | 252 | const module = try spv.finalize(arena, target); |
| 254 | errdefer arena.free(module); | 253 | errdefer arena.free(module); |
| 255 | 254 | ||
| 256 | const linked_module = self.linkModule(arena, module, &sub_prog_node) catch |err| switch (err) { | 255 | const linked_module = self.linkModule(arena, module, sub_prog_node) catch |err| switch (err) { |
| 257 | error.OutOfMemory => return error.OutOfMemory, | 256 | error.OutOfMemory => return error.OutOfMemory, |
| 258 | else => |other| { | 257 | else => |other| { |
| 259 | log.err("error while linking: {s}\n", .{@errorName(other)}); | 258 | log.err("error while linking: {s}\n", .{@errorName(other)}); |
| ... | @@ -264,7 +263,7 @@ pub fn flushModule(self: *SpirV, arena: Allocator, prog_node: *std.Progress.Node | ... | @@ -264,7 +263,7 @@ pub fn flushModule(self: *SpirV, arena: Allocator, prog_node: *std.Progress.Node |
| 264 | try self.base.file.?.writeAll(std.mem.sliceAsBytes(linked_module)); | 263 | try self.base.file.?.writeAll(std.mem.sliceAsBytes(linked_module)); |
| 265 | } | 264 | } |
| 266 | 265 | ||
| 267 | fn linkModule(self: *SpirV, a: Allocator, module: []Word, progress: *std.Progress.Node) ![]Word { | 266 | fn linkModule(self: *SpirV, a: Allocator, module: []Word, progress: std.Progress.Node) ![]Word { |
| 268 | _ = self; | 267 | _ = self; |
| 269 | 268 | ||
| 270 | const lower_invocation_globals = @import("SpirV/lower_invocation_globals.zig"); | 269 | const lower_invocation_globals = @import("SpirV/lower_invocation_globals.zig"); |
src/link/SpirV/deduplicate.zig+2-3| ... | @@ -418,9 +418,8 @@ const EntityHashContext = struct { | ... | @@ -418,9 +418,8 @@ const EntityHashContext = struct { |
| 418 | } | 418 | } |
| 419 | }; | 419 | }; |
| 420 | 420 | ||
| 421 | pub fn run(parser: *BinaryModule.Parser, binary: *BinaryModule, progress: *std.Progress.Node) !void { | 421 | pub fn run(parser: *BinaryModule.Parser, binary: *BinaryModule, progress: std.Progress.Node) !void { |
| 422 | var sub_node = progress.start("deduplicate", 0); | 422 | const sub_node = progress.start("deduplicate", 0); |
| 423 | sub_node.activate(); | ||
| 424 | defer sub_node.end(); | 423 | defer sub_node.end(); |
| 425 | 424 | ||
| 426 | var arena = std.heap.ArenaAllocator.init(parser.a); | 425 | var arena = std.heap.ArenaAllocator.init(parser.a); |
src/link/SpirV/lower_invocation_globals.zig+2-3| ... | @@ -682,9 +682,8 @@ const ModuleBuilder = struct { | ... | @@ -682,9 +682,8 @@ const ModuleBuilder = struct { |
| 682 | } | 682 | } |
| 683 | }; | 683 | }; |
| 684 | 684 | ||
| 685 | pub fn run(parser: *BinaryModule.Parser, binary: *BinaryModule, progress: *std.Progress.Node) !void { | 685 | pub fn run(parser: *BinaryModule.Parser, binary: *BinaryModule, progress: std.Progress.Node) !void { |
| 686 | var sub_node = progress.start("Lower invocation globals", 6); | 686 | const sub_node = progress.start("Lower invocation globals", 6); |
| 687 | sub_node.activate(); | ||
| 688 | defer sub_node.end(); | 687 | defer sub_node.end(); |
| 689 | 688 | ||
| 690 | var arena = std.heap.ArenaAllocator.init(parser.a); | 689 | var arena = std.heap.ArenaAllocator.init(parser.a); |
src/link/SpirV/prune_unused.zig+2-3| ... | @@ -255,9 +255,8 @@ fn removeIdsFromMap(a: Allocator, map: anytype, info: ModuleInfo, alive_marker: | ... | @@ -255,9 +255,8 @@ fn removeIdsFromMap(a: Allocator, map: anytype, info: ModuleInfo, alive_marker: |
| 255 | } | 255 | } |
| 256 | } | 256 | } |
| 257 | 257 | ||
| 258 | pub fn run(parser: *BinaryModule.Parser, binary: *BinaryModule, progress: *std.Progress.Node) !void { | 258 | pub fn run(parser: *BinaryModule.Parser, binary: *BinaryModule, progress: std.Progress.Node) !void { |
| 259 | var sub_node = progress.start("Prune unused IDs", 0); | 259 | const sub_node = progress.start("Prune unused IDs", 0); |
| 260 | sub_node.activate(); | ||
| 261 | defer sub_node.end(); | 260 | defer sub_node.end(); |
| 262 | 261 | ||
| 263 | var arena = std.heap.ArenaAllocator.init(parser.a); | 262 | var arena = std.heap.ArenaAllocator.init(parser.a); |
src/link/Wasm.zig+5-8| ... | @@ -2464,7 +2464,7 @@ fn appendDummySegment(wasm: *Wasm) !void { | ... | @@ -2464,7 +2464,7 @@ fn appendDummySegment(wasm: *Wasm) !void { |
| 2464 | }); | 2464 | }); |
| 2465 | } | 2465 | } |
| 2466 | 2466 | ||
| 2467 | pub fn flush(wasm: *Wasm, arena: Allocator, prog_node: *std.Progress.Node) link.File.FlushError!void { | 2467 | pub fn flush(wasm: *Wasm, arena: Allocator, prog_node: std.Progress.Node) link.File.FlushError!void { |
| 2468 | const comp = wasm.base.comp; | 2468 | const comp = wasm.base.comp; |
| 2469 | const use_lld = build_options.have_llvm and comp.config.use_lld; | 2469 | const use_lld = build_options.have_llvm and comp.config.use_lld; |
| 2470 | 2470 | ||
| ... | @@ -2475,7 +2475,7 @@ pub fn flush(wasm: *Wasm, arena: Allocator, prog_node: *std.Progress.Node) link. | ... | @@ -2475,7 +2475,7 @@ pub fn flush(wasm: *Wasm, arena: Allocator, prog_node: *std.Progress.Node) link. |
| 2475 | } | 2475 | } |
| 2476 | 2476 | ||
| 2477 | /// Uses the in-house linker to link one or multiple object -and archive files into a WebAssembly binary. | 2477 | /// Uses the in-house linker to link one or multiple object -and archive files into a WebAssembly binary. |
| 2478 | pub fn flushModule(wasm: *Wasm, arena: Allocator, prog_node: *std.Progress.Node) link.File.FlushError!void { | 2478 | pub fn flushModule(wasm: *Wasm, arena: Allocator, prog_node: std.Progress.Node) link.File.FlushError!void { |
| 2479 | const tracy = trace(@src()); | 2479 | const tracy = trace(@src()); |
| 2480 | defer tracy.end(); | 2480 | defer tracy.end(); |
| 2481 | 2481 | ||
| ... | @@ -2486,8 +2486,7 @@ pub fn flushModule(wasm: *Wasm, arena: Allocator, prog_node: *std.Progress.Node) | ... | @@ -2486,8 +2486,7 @@ pub fn flushModule(wasm: *Wasm, arena: Allocator, prog_node: *std.Progress.Node) |
| 2486 | if (use_lld) return; | 2486 | if (use_lld) return; |
| 2487 | } | 2487 | } |
| 2488 | 2488 | ||
| 2489 | var sub_prog_node = prog_node.start("Wasm Flush", 0); | 2489 | const sub_prog_node = prog_node.start("Wasm Flush", 0); |
| 2490 | sub_prog_node.activate(); | ||
| 2491 | defer sub_prog_node.end(); | 2490 | defer sub_prog_node.end(); |
| 2492 | 2491 | ||
| 2493 | const directory = wasm.base.emit.directory; // Just an alias to make it shorter to type. | 2492 | const directory = wasm.base.emit.directory; // Just an alias to make it shorter to type. |
| ... | @@ -3323,7 +3322,7 @@ fn emitImport(wasm: *Wasm, writer: anytype, import: types.Import) !void { | ... | @@ -3323,7 +3322,7 @@ fn emitImport(wasm: *Wasm, writer: anytype, import: types.Import) !void { |
| 3323 | } | 3322 | } |
| 3324 | } | 3323 | } |
| 3325 | 3324 | ||
| 3326 | fn linkWithLLD(wasm: *Wasm, arena: Allocator, prog_node: *std.Progress.Node) !void { | 3325 | fn linkWithLLD(wasm: *Wasm, arena: Allocator, prog_node: std.Progress.Node) !void { |
| 3327 | const tracy = trace(@src()); | 3326 | const tracy = trace(@src()); |
| 3328 | defer tracy.end(); | 3327 | defer tracy.end(); |
| 3329 | 3328 | ||
| ... | @@ -3350,9 +3349,7 @@ fn linkWithLLD(wasm: *Wasm, arena: Allocator, prog_node: *std.Progress.Node) !vo | ... | @@ -3350,9 +3349,7 @@ fn linkWithLLD(wasm: *Wasm, arena: Allocator, prog_node: *std.Progress.Node) !vo |
| 3350 | } | 3349 | } |
| 3351 | } else null; | 3350 | } else null; |
| 3352 | 3351 | ||
| 3353 | var sub_prog_node = prog_node.start("LLD Link", 0); | 3352 | const sub_prog_node = prog_node.start("LLD Link", 0); |
| 3354 | sub_prog_node.activate(); | ||
| 3355 | sub_prog_node.context.refresh(); | ||
| 3356 | defer sub_prog_node.end(); | 3353 | defer sub_prog_node.end(); |
| 3357 | 3354 | ||
| 3358 | const is_obj = comp.config.output_mode == .Obj; | 3355 | const is_obj = comp.config.output_mode == .Obj; |
src/main.zig+57-154| ... | @@ -3404,11 +3404,16 @@ fn buildOutputType( | ... | @@ -3404,11 +3404,16 @@ fn buildOutputType( |
| 3404 | }, | 3404 | }, |
| 3405 | } | 3405 | } |
| 3406 | 3406 | ||
| 3407 | const root_prog_node = std.Progress.start(.{ | ||
| 3408 | .disable_printing = (color == .off), | ||
| 3409 | }); | ||
| 3410 | defer root_prog_node.end(); | ||
| 3411 | |||
| 3407 | if (arg_mode == .translate_c) { | 3412 | if (arg_mode == .translate_c) { |
| 3408 | return cmdTranslateC(comp, arena, null); | 3413 | return cmdTranslateC(comp, arena, null, root_prog_node); |
| 3409 | } | 3414 | } |
| 3410 | 3415 | ||
| 3411 | updateModule(comp, color) catch |err| switch (err) { | 3416 | updateModule(comp, color, root_prog_node) catch |err| switch (err) { |
| 3412 | error.SemanticAnalyzeFail => { | 3417 | error.SemanticAnalyzeFail => { |
| 3413 | assert(listen == .none); | 3418 | assert(listen == .none); |
| 3414 | saveState(comp, debug_incremental); | 3419 | saveState(comp, debug_incremental); |
| ... | @@ -4028,22 +4033,7 @@ fn serve( | ... | @@ -4028,22 +4033,7 @@ fn serve( |
| 4028 | 4033 | ||
| 4029 | var child_pid: ?std.process.Child.Id = null; | 4034 | var child_pid: ?std.process.Child.Id = null; |
| 4030 | 4035 | ||
| 4031 | var progress: std.Progress = .{ | 4036 | const main_progress_node = std.Progress.start(.{}); |
| 4032 | .terminal = null, | ||
| 4033 | .root = .{ | ||
| 4034 | .context = undefined, | ||
| 4035 | .parent = null, | ||
| 4036 | .name = "", | ||
| 4037 | .unprotected_estimated_total_items = 0, | ||
| 4038 | .unprotected_completed_items = 0, | ||
| 4039 | }, | ||
| 4040 | .columns_written = 0, | ||
| 4041 | .prev_refresh_timestamp = 0, | ||
| 4042 | .timer = null, | ||
| 4043 | .done = false, | ||
| 4044 | }; | ||
| 4045 | const main_progress_node = &progress.root; | ||
| 4046 | main_progress_node.context = &progress; | ||
| 4047 | 4037 | ||
| 4048 | while (true) { | 4038 | while (true) { |
| 4049 | const hdr = try server.receiveMessage(); | 4039 | const hdr = try server.receiveMessage(); |
| ... | @@ -4051,7 +4041,6 @@ fn serve( | ... | @@ -4051,7 +4041,6 @@ fn serve( |
| 4051 | switch (hdr.tag) { | 4041 | switch (hdr.tag) { |
| 4052 | .exit => return cleanExit(), | 4042 | .exit => return cleanExit(), |
| 4053 | .update => { | 4043 | .update => { |
| 4054 | assert(main_progress_node.recently_updated_child == null); | ||
| 4055 | tracy.frameMark(); | 4044 | tracy.frameMark(); |
| 4056 | 4045 | ||
| 4057 | if (arg_mode == .translate_c) { | 4046 | if (arg_mode == .translate_c) { |
| ... | @@ -4059,7 +4048,7 @@ fn serve( | ... | @@ -4059,7 +4048,7 @@ fn serve( |
| 4059 | defer arena_instance.deinit(); | 4048 | defer arena_instance.deinit(); |
| 4060 | const arena = arena_instance.allocator(); | 4049 | const arena = arena_instance.allocator(); |
| 4061 | var output: Compilation.CImportResult = undefined; | 4050 | var output: Compilation.CImportResult = undefined; |
| 4062 | try cmdTranslateC(comp, arena, &output); | 4051 | try cmdTranslateC(comp, arena, &output, main_progress_node); |
| 4063 | defer output.deinit(gpa); | 4052 | defer output.deinit(gpa); |
| 4064 | if (output.errors.errorMessageCount() != 0) { | 4053 | if (output.errors.errorMessageCount() != 0) { |
| 4065 | try server.serveErrorBundle(output.errors); | 4054 | try server.serveErrorBundle(output.errors); |
| ... | @@ -4075,21 +4064,7 @@ fn serve( | ... | @@ -4075,21 +4064,7 @@ fn serve( |
| 4075 | try comp.makeBinFileWritable(); | 4064 | try comp.makeBinFileWritable(); |
| 4076 | } | 4065 | } |
| 4077 | 4066 | ||
| 4078 | if (builtin.single_threaded) { | 4067 | try comp.update(main_progress_node); |
| 4079 | try comp.update(main_progress_node); | ||
| 4080 | } else { | ||
| 4081 | var reset: std.Thread.ResetEvent = .{}; | ||
| 4082 | |||
| 4083 | var progress_thread = try std.Thread.spawn(.{}, progressThread, .{ | ||
| 4084 | &progress, &server, &reset, | ||
| 4085 | }); | ||
| 4086 | defer { | ||
| 4087 | reset.set(); | ||
| 4088 | progress_thread.join(); | ||
| 4089 | } | ||
| 4090 | |||
| 4091 | try comp.update(main_progress_node); | ||
| 4092 | } | ||
| 4093 | 4068 | ||
| 4094 | try comp.makeBinFileExecutable(); | 4069 | try comp.makeBinFileExecutable(); |
| 4095 | try serveUpdateResults(&server, comp); | 4070 | try serveUpdateResults(&server, comp); |
| ... | @@ -4116,7 +4091,6 @@ fn serve( | ... | @@ -4116,7 +4091,6 @@ fn serve( |
| 4116 | }, | 4091 | }, |
| 4117 | .hot_update => { | 4092 | .hot_update => { |
| 4118 | tracy.frameMark(); | 4093 | tracy.frameMark(); |
| 4119 | assert(main_progress_node.recently_updated_child == null); | ||
| 4120 | if (child_pid) |pid| { | 4094 | if (child_pid) |pid| { |
| 4121 | try comp.hotCodeSwap(main_progress_node, pid); | 4095 | try comp.hotCodeSwap(main_progress_node, pid); |
| 4122 | try serveUpdateResults(&server, comp); | 4096 | try serveUpdateResults(&server, comp); |
| ... | @@ -4146,63 +4120,6 @@ fn serve( | ... | @@ -4146,63 +4120,6 @@ fn serve( |
| 4146 | } | 4120 | } |
| 4147 | } | 4121 | } |
| 4148 | 4122 | ||
| 4149 | fn progressThread(progress: *std.Progress, server: *const Server, reset: *std.Thread.ResetEvent) void { | ||
| 4150 | while (true) { | ||
| 4151 | if (reset.timedWait(500 * std.time.ns_per_ms)) |_| { | ||
| 4152 | // The Compilation update has completed. | ||
| 4153 | return; | ||
| 4154 | } else |err| switch (err) { | ||
| 4155 | error.Timeout => {}, | ||
| 4156 | } | ||
| 4157 | |||
| 4158 | var buf: std.BoundedArray(u8, 160) = .{}; | ||
| 4159 | |||
| 4160 | { | ||
| 4161 | progress.update_mutex.lock(); | ||
| 4162 | defer progress.update_mutex.unlock(); | ||
| 4163 | |||
| 4164 | var need_ellipse = false; | ||
| 4165 | var maybe_node: ?*std.Progress.Node = &progress.root; | ||
| 4166 | while (maybe_node) |node| { | ||
| 4167 | if (need_ellipse) { | ||
| 4168 | buf.appendSlice("... ") catch {}; | ||
| 4169 | } | ||
| 4170 | need_ellipse = false; | ||
| 4171 | const eti = @atomicLoad(usize, &node.unprotected_estimated_total_items, .monotonic); | ||
| 4172 | const completed_items = @atomicLoad(usize, &node.unprotected_completed_items, .monotonic); | ||
| 4173 | const current_item = completed_items + 1; | ||
| 4174 | if (node.name.len != 0 or eti > 0) { | ||
| 4175 | if (node.name.len != 0) { | ||
| 4176 | buf.appendSlice(node.name) catch {}; | ||
| 4177 | need_ellipse = true; | ||
| 4178 | } | ||
| 4179 | if (eti > 0) { | ||
| 4180 | if (need_ellipse) buf.appendSlice(" ") catch {}; | ||
| 4181 | buf.writer().print("[{d}/{d}] ", .{ current_item, eti }) catch {}; | ||
| 4182 | need_ellipse = false; | ||
| 4183 | } else if (completed_items != 0) { | ||
| 4184 | if (need_ellipse) buf.appendSlice(" ") catch {}; | ||
| 4185 | buf.writer().print("[{d}] ", .{current_item}) catch {}; | ||
| 4186 | need_ellipse = false; | ||
| 4187 | } | ||
| 4188 | } | ||
| 4189 | maybe_node = @atomicLoad(?*std.Progress.Node, &node.recently_updated_child, .acquire); | ||
| 4190 | } | ||
| 4191 | } | ||
| 4192 | |||
| 4193 | const progress_string = buf.slice(); | ||
| 4194 | |||
| 4195 | server.serveMessage(.{ | ||
| 4196 | .tag = .progress, | ||
| 4197 | .bytes_len = @as(u32, @intCast(progress_string.len)), | ||
| 4198 | }, &.{ | ||
| 4199 | progress_string, | ||
| 4200 | }) catch |err| { | ||
| 4201 | fatal("unable to write to client: {s}", .{@errorName(err)}); | ||
| 4202 | }; | ||
| 4203 | } | ||
| 4204 | } | ||
| 4205 | |||
| 4206 | fn serveUpdateResults(s: *Server, comp: *Compilation) !void { | 4123 | fn serveUpdateResults(s: *Server, comp: *Compilation) !void { |
| 4207 | const gpa = comp.gpa; | 4124 | const gpa = comp.gpa; |
| 4208 | var error_bundle = try comp.getAllErrorsAlloc(); | 4125 | var error_bundle = try comp.getAllErrorsAlloc(); |
| ... | @@ -4469,25 +4386,8 @@ fn runOrTestHotSwap( | ... | @@ -4469,25 +4386,8 @@ fn runOrTestHotSwap( |
| 4469 | } | 4386 | } |
| 4470 | } | 4387 | } |
| 4471 | 4388 | ||
| 4472 | fn updateModule(comp: *Compilation, color: Color) !void { | 4389 | fn updateModule(comp: *Compilation, color: Color, prog_node: std.Progress.Node) !void { |
| 4473 | { | 4390 | try comp.update(prog_node); |
| 4474 | // If the terminal is dumb, we dont want to show the user all the output. | ||
| 4475 | var progress: std.Progress = .{ .dont_print_on_dumb = true }; | ||
| 4476 | const main_progress_node = progress.start("", 0); | ||
| 4477 | defer main_progress_node.end(); | ||
| 4478 | switch (color) { | ||
| 4479 | .off => { | ||
| 4480 | progress.terminal = null; | ||
| 4481 | }, | ||
| 4482 | .on => { | ||
| 4483 | progress.terminal = std.io.getStdErr(); | ||
| 4484 | progress.supports_ansi_escape_codes = true; | ||
| 4485 | }, | ||
| 4486 | .auto => {}, | ||
| 4487 | } | ||
| 4488 | |||
| 4489 | try comp.update(main_progress_node); | ||
| 4490 | } | ||
| 4491 | 4391 | ||
| 4492 | var errors = try comp.getAllErrorsAlloc(); | 4392 | var errors = try comp.getAllErrorsAlloc(); |
| 4493 | defer errors.deinit(comp.gpa); | 4393 | defer errors.deinit(comp.gpa); |
| ... | @@ -4498,7 +4398,12 @@ fn updateModule(comp: *Compilation, color: Color) !void { | ... | @@ -4498,7 +4398,12 @@ fn updateModule(comp: *Compilation, color: Color) !void { |
| 4498 | } | 4398 | } |
| 4499 | } | 4399 | } |
| 4500 | 4400 | ||
| 4501 | fn cmdTranslateC(comp: *Compilation, arena: Allocator, fancy_output: ?*Compilation.CImportResult) !void { | 4401 | fn cmdTranslateC( |
| 4402 | comp: *Compilation, | ||
| 4403 | arena: Allocator, | ||
| 4404 | fancy_output: ?*Compilation.CImportResult, | ||
| 4405 | prog_node: std.Progress.Node, | ||
| 4406 | ) !void { | ||
| 4502 | if (build_options.only_core_functionality) @panic("@translate-c is not available in a zig2.c build"); | 4407 | if (build_options.only_core_functionality) @panic("@translate-c is not available in a zig2.c build"); |
| 4503 | const color: Color = .auto; | 4408 | const color: Color = .auto; |
| 4504 | assert(comp.c_source_files.len == 1); | 4409 | assert(comp.c_source_files.len == 1); |
| ... | @@ -4559,6 +4464,7 @@ fn cmdTranslateC(comp: *Compilation, arena: Allocator, fancy_output: ?*Compilati | ... | @@ -4559,6 +4464,7 @@ fn cmdTranslateC(comp: *Compilation, arena: Allocator, fancy_output: ?*Compilati |
| 4559 | .root_src_path = "aro_translate_c.zig", | 4464 | .root_src_path = "aro_translate_c.zig", |
| 4560 | .depend_on_aro = true, | 4465 | .depend_on_aro = true, |
| 4561 | .capture = &stdout, | 4466 | .capture = &stdout, |
| 4467 | .progress_node = prog_node, | ||
| 4562 | }); | 4468 | }); |
| 4563 | break :f stdout; | 4469 | break :f stdout; |
| 4564 | }, | 4470 | }, |
| ... | @@ -4736,8 +4642,6 @@ const usage_build = | ... | @@ -4736,8 +4642,6 @@ const usage_build = |
| 4736 | ; | 4642 | ; |
| 4737 | 4643 | ||
| 4738 | fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void { | 4644 | fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void { |
| 4739 | var progress: std.Progress = .{ .dont_print_on_dumb = true }; | ||
| 4740 | |||
| 4741 | var build_file: ?[]const u8 = null; | 4645 | var build_file: ?[]const u8 = null; |
| 4742 | var override_lib_dir: ?[]const u8 = try EnvVar.ZIG_LIB_DIR.get(arena); | 4646 | var override_lib_dir: ?[]const u8 = try EnvVar.ZIG_LIB_DIR.get(arena); |
| 4743 | var override_global_cache_dir: ?[]const u8 = try EnvVar.ZIG_GLOBAL_CACHE_DIR.get(arena); | 4647 | var override_global_cache_dir: ?[]const u8 = try EnvVar.ZIG_GLOBAL_CACHE_DIR.get(arena); |
| ... | @@ -4798,6 +4702,8 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void { | ... | @@ -4798,6 +4702,8 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void { |
| 4798 | const results_tmp_file_nonce = Package.Manifest.hex64(std.crypto.random.int(u64)); | 4702 | const results_tmp_file_nonce = Package.Manifest.hex64(std.crypto.random.int(u64)); |
| 4799 | try child_argv.append("-Z" ++ results_tmp_file_nonce); | 4703 | try child_argv.append("-Z" ++ results_tmp_file_nonce); |
| 4800 | 4704 | ||
| 4705 | var color: Color = .auto; | ||
| 4706 | |||
| 4801 | { | 4707 | { |
| 4802 | var i: usize = 0; | 4708 | var i: usize = 0; |
| 4803 | while (i < args.len) : (i += 1) { | 4709 | while (i < args.len) : (i += 1) { |
| ... | @@ -4882,6 +4788,14 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void { | ... | @@ -4882,6 +4788,14 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void { |
| 4882 | verbose_cimport = true; | 4788 | verbose_cimport = true; |
| 4883 | } else if (mem.eql(u8, arg, "--verbose-llvm-cpu-features")) { | 4789 | } else if (mem.eql(u8, arg, "--verbose-llvm-cpu-features")) { |
| 4884 | verbose_llvm_cpu_features = true; | 4790 | verbose_llvm_cpu_features = true; |
| 4791 | } else if (mem.eql(u8, arg, "--color")) { | ||
| 4792 | if (i + 1 >= args.len) fatal("expected [auto|on|off] after {s}", .{arg}); | ||
| 4793 | i += 1; | ||
| 4794 | color = std.meta.stringToEnum(Color, args[i]) orelse { | ||
| 4795 | fatal("expected [auto|on|off] after {s}, found '{s}'", .{ arg, args[i] }); | ||
| 4796 | }; | ||
| 4797 | try child_argv.appendSlice(&.{ arg, args[i] }); | ||
| 4798 | continue; | ||
| 4885 | } else if (mem.eql(u8, arg, "--seed")) { | 4799 | } else if (mem.eql(u8, arg, "--seed")) { |
| 4886 | if (i + 1 >= args.len) fatal("expected argument after '{s}'", .{arg}); | 4800 | if (i + 1 >= args.len) fatal("expected argument after '{s}'", .{arg}); |
| 4887 | i += 1; | 4801 | i += 1; |
| ... | @@ -4895,7 +4809,11 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void { | ... | @@ -4895,7 +4809,11 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void { |
| 4895 | 4809 | ||
| 4896 | const work_around_btrfs_bug = native_os == .linux and | 4810 | const work_around_btrfs_bug = native_os == .linux and |
| 4897 | EnvVar.ZIG_BTRFS_WORKAROUND.isSet(); | 4811 | EnvVar.ZIG_BTRFS_WORKAROUND.isSet(); |
| 4898 | const color: Color = .auto; | 4812 | const root_prog_node = std.Progress.start(.{ |
| 4813 | .disable_printing = (color == .off), | ||
| 4814 | .root_name = "Compile Build Script", | ||
| 4815 | }); | ||
| 4816 | defer root_prog_node.end(); | ||
| 4899 | 4817 | ||
| 4900 | const target_query: std.Target.Query = .{}; | 4818 | const target_query: std.Target.Query = .{}; |
| 4901 | const resolved_target: Package.Module.ResolvedTarget = .{ | 4819 | const resolved_target: Package.Module.ResolvedTarget = .{ |
| ... | @@ -5051,8 +4969,8 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void { | ... | @@ -5051,8 +4969,8 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void { |
| 5051 | config, | 4969 | config, |
| 5052 | ); | 4970 | ); |
| 5053 | } else { | 4971 | } else { |
| 5054 | const root_prog_node = progress.start("Fetch Packages", 0); | 4972 | const fetch_prog_node = root_prog_node.start("Fetch Packages", 0); |
| 5055 | defer root_prog_node.end(); | 4973 | defer fetch_prog_node.end(); |
| 5056 | 4974 | ||
| 5057 | var job_queue: Package.Fetch.JobQueue = .{ | 4975 | var job_queue: Package.Fetch.JobQueue = .{ |
| 5058 | .http_client = &http_client, | 4976 | .http_client = &http_client, |
| ... | @@ -5093,7 +5011,7 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void { | ... | @@ -5093,7 +5011,7 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void { |
| 5093 | .lazy_status = .eager, | 5011 | .lazy_status = .eager, |
| 5094 | .parent_package_root = build_mod.root, | 5012 | .parent_package_root = build_mod.root, |
| 5095 | .parent_manifest_ast = null, | 5013 | .parent_manifest_ast = null, |
| 5096 | .prog_node = root_prog_node, | 5014 | .prog_node = fetch_prog_node, |
| 5097 | .job_queue = &job_queue, | 5015 | .job_queue = &job_queue, |
| 5098 | .omit_missing_hash_error = true, | 5016 | .omit_missing_hash_error = true, |
| 5099 | .allow_missing_paths_field = false, | 5017 | .allow_missing_paths_field = false, |
| ... | @@ -5232,7 +5150,7 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void { | ... | @@ -5232,7 +5150,7 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void { |
| 5232 | }; | 5150 | }; |
| 5233 | defer comp.destroy(); | 5151 | defer comp.destroy(); |
| 5234 | 5152 | ||
| 5235 | updateModule(comp, color) catch |err| switch (err) { | 5153 | updateModule(comp, color, root_prog_node) catch |err| switch (err) { |
| 5236 | error.SemanticAnalyzeFail => process.exit(2), | 5154 | error.SemanticAnalyzeFail => process.exit(2), |
| 5237 | else => |e| return e, | 5155 | else => |e| return e, |
| 5238 | }; | 5156 | }; |
| ... | @@ -5250,7 +5168,12 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void { | ... | @@ -5250,7 +5168,12 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void { |
| 5250 | child.stdout_behavior = .Inherit; | 5168 | child.stdout_behavior = .Inherit; |
| 5251 | child.stderr_behavior = .Inherit; | 5169 | child.stderr_behavior = .Inherit; |
| 5252 | 5170 | ||
| 5253 | const term = try child.spawnAndWait(); | 5171 | const term = t: { |
| 5172 | std.debug.lockStdErr(); | ||
| 5173 | defer std.debug.unlockStdErr(); | ||
| 5174 | break :t try child.spawnAndWait(); | ||
| 5175 | }; | ||
| 5176 | |||
| 5254 | switch (term) { | 5177 | switch (term) { |
| 5255 | .Exited => |code| { | 5178 | .Exited => |code| { |
| 5256 | if (code == 0) return cleanExit(); | 5179 | if (code == 0) return cleanExit(); |
| ... | @@ -5326,8 +5249,9 @@ const JitCmdOptions = struct { | ... | @@ -5326,8 +5249,9 @@ const JitCmdOptions = struct { |
| 5326 | prepend_zig_exe_path: bool = false, | 5249 | prepend_zig_exe_path: bool = false, |
| 5327 | depend_on_aro: bool = false, | 5250 | depend_on_aro: bool = false, |
| 5328 | capture: ?*[]u8 = null, | 5251 | capture: ?*[]u8 = null, |
| 5329 | /// Send progress and error bundles via std.zig.Server over stdout | 5252 | /// Send error bundles via std.zig.Server over stdout |
| 5330 | server: bool = false, | 5253 | server: bool = false, |
| 5254 | progress_node: ?std.Progress.Node = null, | ||
| 5331 | }; | 5255 | }; |
| 5332 | 5256 | ||
| 5333 | fn jitCmd( | 5257 | fn jitCmd( |
| ... | @@ -5337,6 +5261,9 @@ fn jitCmd( | ... | @@ -5337,6 +5261,9 @@ fn jitCmd( |
| 5337 | options: JitCmdOptions, | 5261 | options: JitCmdOptions, |
| 5338 | ) !void { | 5262 | ) !void { |
| 5339 | const color: Color = .auto; | 5263 | const color: Color = .auto; |
| 5264 | const root_prog_node = if (options.progress_node) |node| node else std.Progress.start(.{ | ||
| 5265 | .disable_printing = (color == .off), | ||
| 5266 | }); | ||
| 5340 | 5267 | ||
| 5341 | const target_query: std.Target.Query = .{}; | 5268 | const target_query: std.Target.Query = .{}; |
| 5342 | const resolved_target: Package.Module.ResolvedTarget = .{ | 5269 | const resolved_target: Package.Module.ResolvedTarget = .{ |
| ... | @@ -5473,39 +5400,14 @@ fn jitCmd( | ... | @@ -5473,39 +5400,14 @@ fn jitCmd( |
| 5473 | }; | 5400 | }; |
| 5474 | defer comp.destroy(); | 5401 | defer comp.destroy(); |
| 5475 | 5402 | ||
| 5476 | if (options.server and !builtin.single_threaded) { | 5403 | if (options.server) { |
| 5477 | var reset: std.Thread.ResetEvent = .{}; | ||
| 5478 | var progress: std.Progress = .{ | ||
| 5479 | .terminal = null, | ||
| 5480 | .root = .{ | ||
| 5481 | .context = undefined, | ||
| 5482 | .parent = null, | ||
| 5483 | .name = "", | ||
| 5484 | .unprotected_estimated_total_items = 0, | ||
| 5485 | .unprotected_completed_items = 0, | ||
| 5486 | }, | ||
| 5487 | .columns_written = 0, | ||
| 5488 | .prev_refresh_timestamp = 0, | ||
| 5489 | .timer = null, | ||
| 5490 | .done = false, | ||
| 5491 | }; | ||
| 5492 | const main_progress_node = &progress.root; | ||
| 5493 | main_progress_node.context = &progress; | ||
| 5494 | var server = std.zig.Server{ | 5404 | var server = std.zig.Server{ |
| 5495 | .out = std.io.getStdOut(), | 5405 | .out = std.io.getStdOut(), |
| 5496 | .in = undefined, // won't be receiving messages | 5406 | .in = undefined, // won't be receiving messages |
| 5497 | .receive_fifo = undefined, // won't be receiving messages | 5407 | .receive_fifo = undefined, // won't be receiving messages |
| 5498 | }; | 5408 | }; |
| 5499 | 5409 | ||
| 5500 | var progress_thread = try std.Thread.spawn(.{}, progressThread, .{ | 5410 | try comp.update(root_prog_node); |
| 5501 | &progress, &server, &reset, | ||
| 5502 | }); | ||
| 5503 | defer { | ||
| 5504 | reset.set(); | ||
| 5505 | progress_thread.join(); | ||
| 5506 | } | ||
| 5507 | |||
| 5508 | try comp.update(main_progress_node); | ||
| 5509 | 5411 | ||
| 5510 | var error_bundle = try comp.getAllErrorsAlloc(); | 5412 | var error_bundle = try comp.getAllErrorsAlloc(); |
| 5511 | defer error_bundle.deinit(comp.gpa); | 5413 | defer error_bundle.deinit(comp.gpa); |
| ... | @@ -5514,7 +5416,7 @@ fn jitCmd( | ... | @@ -5514,7 +5416,7 @@ fn jitCmd( |
| 5514 | process.exit(2); | 5416 | process.exit(2); |
| 5515 | } | 5417 | } |
| 5516 | } else { | 5418 | } else { |
| 5517 | updateModule(comp, color) catch |err| switch (err) { | 5419 | updateModule(comp, color, root_prog_node) catch |err| switch (err) { |
| 5518 | error.SemanticAnalyzeFail => process.exit(2), | 5420 | error.SemanticAnalyzeFail => process.exit(2), |
| 5519 | else => |e| return e, | 5421 | else => |e| return e, |
| 5520 | }; | 5422 | }; |
| ... | @@ -6963,8 +6865,9 @@ fn cmdFetch( | ... | @@ -6963,8 +6865,9 @@ fn cmdFetch( |
| 6963 | 6865 | ||
| 6964 | try http_client.initDefaultProxies(arena); | 6866 | try http_client.initDefaultProxies(arena); |
| 6965 | 6867 | ||
| 6966 | var progress: std.Progress = .{ .dont_print_on_dumb = true }; | 6868 | var root_prog_node = std.Progress.start(.{ |
| 6967 | const root_prog_node = progress.start("Fetch", 0); | 6869 | .root_name = "Fetch", |
| 6870 | }); | ||
| 6968 | defer root_prog_node.end(); | 6871 | defer root_prog_node.end(); |
| 6969 | 6872 | ||
| 6970 | var global_cache_directory: Compilation.Directory = l: { | 6873 | var global_cache_directory: Compilation.Directory = l: { |
| ... | @@ -7028,8 +6931,8 @@ fn cmdFetch( | ... | @@ -7028,8 +6931,8 @@ fn cmdFetch( |
| 7028 | 6931 | ||
| 7029 | const hex_digest = Package.Manifest.hexDigest(fetch.actual_hash); | 6932 | const hex_digest = Package.Manifest.hexDigest(fetch.actual_hash); |
| 7030 | 6933 | ||
| 7031 | progress.done = true; | 6934 | root_prog_node.end(); |
| 7032 | progress.refresh(); | 6935 | root_prog_node = .{ .index = .none }; |
| 7033 | 6936 | ||
| 7034 | const name = switch (save) { | 6937 | const name = switch (save) { |
| 7035 | .no => { | 6938 | .no => { |
src/mingw.zig+3-3| ... | @@ -16,7 +16,7 @@ pub const CRTFile = enum { | ... | @@ -16,7 +16,7 @@ pub const CRTFile = enum { |
| 16 | mingw32_lib, | 16 | mingw32_lib, |
| 17 | }; | 17 | }; |
| 18 | 18 | ||
| 19 | pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile, prog_node: *std.Progress.Node) !void { | 19 | pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile, prog_node: std.Progress.Node) !void { |
| 20 | if (!build_options.have_llvm) { | 20 | if (!build_options.have_llvm) { |
| 21 | return error.ZigCompilerNotBuiltWithLLVMExtensions; | 21 | return error.ZigCompilerNotBuiltWithLLVMExtensions; |
| 22 | } | 22 | } |
| ... | @@ -234,8 +234,8 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void { | ... | @@ -234,8 +234,8 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void { |
| 234 | const include_dir = try comp.zig_lib_directory.join(arena, &[_][]const u8{ "libc", "mingw", "def-include" }); | 234 | const include_dir = try comp.zig_lib_directory.join(arena, &[_][]const u8{ "libc", "mingw", "def-include" }); |
| 235 | 235 | ||
| 236 | if (comp.verbose_cc) print: { | 236 | if (comp.verbose_cc) print: { |
| 237 | std.debug.getStderrMutex().lock(); | 237 | std.debug.lockStdErr(); |
| 238 | defer std.debug.getStderrMutex().unlock(); | 238 | defer std.debug.unlockStdErr(); |
| 239 | const stderr = std.io.getStdErr().writer(); | 239 | const stderr = std.io.getStdErr().writer(); |
| 240 | nosuspend stderr.print("def file: {s}\n", .{def_file_path}) catch break :print; | 240 | nosuspend stderr.print("def file: {s}\n", .{def_file_path}) catch break :print; |
| 241 | nosuspend stderr.print("include dir: {s}\n", .{include_dir}) catch break :print; | 241 | nosuspend stderr.print("include dir: {s}\n", .{include_dir}) catch break :print; |
src/musl.zig+1-1| ... | @@ -19,7 +19,7 @@ pub const CRTFile = enum { | ... | @@ -19,7 +19,7 @@ pub const CRTFile = enum { |
| 19 | libc_so, | 19 | libc_so, |
| 20 | }; | 20 | }; |
| 21 | 21 | ||
| 22 | pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile, prog_node: *std.Progress.Node) !void { | 22 | pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile, prog_node: std.Progress.Node) !void { |
| 23 | if (!build_options.have_llvm) { | 23 | if (!build_options.have_llvm) { |
| 24 | return error.ZigCompilerNotBuiltWithLLVMExtensions; | 24 | return error.ZigCompilerNotBuiltWithLLVMExtensions; |
| 25 | } | 25 | } |
src/wasi_libc.zig+1-1| ... | @@ -57,7 +57,7 @@ pub fn execModelCrtFileFullName(wasi_exec_model: std.builtin.WasiExecModel) []co | ... | @@ -57,7 +57,7 @@ pub fn execModelCrtFileFullName(wasi_exec_model: std.builtin.WasiExecModel) []co |
| 57 | }; | 57 | }; |
| 58 | } | 58 | } |
| 59 | 59 | ||
| 60 | pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile, prog_node: *std.Progress.Node) !void { | 60 | pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile, prog_node: std.Progress.Node) !void { |
| 61 | if (!build_options.have_llvm) { | 61 | if (!build_options.have_llvm) { |
| 62 | return error.ZigCompilerNotBuiltWithLLVMExtensions; | 62 | return error.ZigCompilerNotBuiltWithLLVMExtensions; |
| 63 | } | 63 | } |
test/src/Cases.zig+1-1| ... | @@ -561,7 +561,7 @@ pub fn lowerToTranslateCSteps( | ... | @@ -561,7 +561,7 @@ pub fn lowerToTranslateCSteps( |
| 561 | for (self.translate.items) |case| switch (case.kind) { | 561 | for (self.translate.items) |case| switch (case.kind) { |
| 562 | .run => |output| { | 562 | .run => |output| { |
| 563 | if (translate_c_options.skip_run_translated_c) continue; | 563 | if (translate_c_options.skip_run_translated_c) continue; |
| 564 | const annotated_case_name = b.fmt("run-translated-c {s}", .{case.name}); | 564 | const annotated_case_name = b.fmt("run-translated-c {s}", .{case.name}); |
| 565 | for (test_filters) |test_filter| { | 565 | for (test_filters) |test_filter| { |
| 566 | if (std.mem.indexOf(u8, annotated_case_name, test_filter)) |_| break; | 566 | if (std.mem.indexOf(u8, annotated_case_name, test_filter)) |_| break; |
| 567 | } else if (test_filters.len > 0) continue; | 567 | } else if (test_filters.len > 0) continue; |
test/src/RunTranslatedC.zig+1| ... | @@ -91,6 +91,7 @@ pub fn addCase(self: *RunTranslatedCContext, case: *const TestCase) void { | ... | @@ -91,6 +91,7 @@ pub fn addCase(self: *RunTranslatedCContext, case: *const TestCase) void { |
| 91 | run.expectStdErrEqual(""); | 91 | run.expectStdErrEqual(""); |
| 92 | } | 92 | } |
| 93 | run.expectStdOutEqual(case.expected_stdout); | 93 | run.expectStdOutEqual(case.expected_stdout); |
| 94 | run.skip_foreign_checks = true; | ||
| 94 | 95 | ||
| 95 | self.step.dependOn(&run.step); | 96 | self.step.dependOn(&run.step); |
| 96 | } | 97 | } |
test/standalone/cmakedefine/build.zig+1-1| ... | @@ -80,7 +80,7 @@ pub fn build(b: *std.Build) void { | ... | @@ -80,7 +80,7 @@ pub fn build(b: *std.Build) void { |
| 80 | test_step.dependOn(&wrapper_header.step); | 80 | test_step.dependOn(&wrapper_header.step); |
| 81 | } | 81 | } |
| 82 | 82 | ||
| 83 | fn compare_headers(step: *std.Build.Step, prog_node: *std.Progress.Node) !void { | 83 | fn compare_headers(step: *std.Build.Step, prog_node: std.Progress.Node) !void { |
| 84 | _ = prog_node; | 84 | _ = prog_node; |
| 85 | const allocator = step.owner.allocator; | 85 | const allocator = step.owner.allocator; |
| 86 | const expected_fmt = "expected_{s}"; | 86 | const expected_fmt = "expected_{s}"; |
test/standalone/empty_env/build.zig+1| ... | @@ -21,6 +21,7 @@ pub fn build(b: *std.Build) void { | ... | @@ -21,6 +21,7 @@ pub fn build(b: *std.Build) void { |
| 21 | 21 | ||
| 22 | const run = b.addRunArtifact(main); | 22 | const run = b.addRunArtifact(main); |
| 23 | run.clearEnvironment(); | 23 | run.clearEnvironment(); |
| 24 | run.disable_zig_progress = true; | ||
| 24 | 25 | ||
| 25 | test_step.dependOn(&run.step); | 26 | test_step.dependOn(&run.step); |
| 26 | } | 27 | } |