authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2025-08-05 22:48:50+01:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2025-08-06 21:50:16+01:00
loge17a050bc695f7d117b89adb1d258813593ca111
treef281876485848c783fb9e2a10616b98cda0b2e09
parent3de8bbd3d4e262df11a582fb52401b8077b5f352

link: prevent deadlock when prelink tasks fail

If an error occured which prevented a prelink task from being queued, then `pending_prelink_tasks` would never be decremented, which could cause deadlocks in some cases. So, instead of calculating ahead of time the number of prelink tasks to expect, we use a simpler strategy which is much like a wait group: we add 1 to a value when we spawn a worker, and in the worker function, `defer` decrementing the value. The initial value is 1, and there's a decrement after all of the workers are spawned, so once it hits 0, prelink is done (be it with a failure or a success).

5 files changed, 90 insertions(+), 69 deletions(-)

src/Compilation.zig+45-36
...@@ -2384,7 +2384,6 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil...@@ -2384,7 +2384,6 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil
2384 };2384 };
2385 comp.c_object_table.putAssumeCapacityNoClobber(c_object, {});2385 comp.c_object_table.putAssumeCapacityNoClobber(c_object, {});
2386 }2386 }
2387 comp.link_task_queue.pending_prelink_tasks += @intCast(comp.c_object_table.count());
23882387
2389 // Add a `Win32Resource` for each `rc_source_files` and one for `manifest_file`.2388 // Add a `Win32Resource` for each `rc_source_files` and one for `manifest_file`.
2390 const win32_resource_count =2389 const win32_resource_count =
...@@ -2392,10 +2391,6 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil...@@ -2392,10 +2391,6 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil
2392 if (win32_resource_count > 0) {2391 if (win32_resource_count > 0) {
2393 dev.check(.win32_resource);2392 dev.check(.win32_resource);
2394 try comp.win32_resource_table.ensureTotalCapacity(gpa, win32_resource_count);2393 try comp.win32_resource_table.ensureTotalCapacity(gpa, win32_resource_count);
2395 // Add this after adding logic to updateWin32Resource to pass the
2396 // result into link.loadInput. loadInput integration is not implemented
2397 // for Windows linking logic yet.
2398 //comp.link_task_queue.pending_prelink_tasks += @intCast(win32_resource_count);
2399 for (options.rc_source_files) |rc_source_file| {2394 for (options.rc_source_files) |rc_source_file| {
2400 const win32_resource = try gpa.create(Win32Resource);2395 const win32_resource = try gpa.create(Win32Resource);
2401 errdefer gpa.destroy(win32_resource);2396 errdefer gpa.destroy(win32_resource);
...@@ -2454,58 +2449,47 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil...@@ -2454,58 +2449,47 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil
24542449
2455 if (musl.needsCrt0(comp.config.output_mode, comp.config.link_mode, comp.config.pie)) |f| {2450 if (musl.needsCrt0(comp.config.output_mode, comp.config.link_mode, comp.config.pie)) |f| {
2456 comp.queued_jobs.musl_crt_file[@intFromEnum(f)] = true;2451 comp.queued_jobs.musl_crt_file[@intFromEnum(f)] = true;
2457 comp.link_task_queue.pending_prelink_tasks += 1;
2458 }2452 }
2459 switch (comp.config.link_mode) {2453 switch (comp.config.link_mode) {
2460 .static => comp.queued_jobs.musl_crt_file[@intFromEnum(musl.CrtFile.libc_a)] = true,2454 .static => comp.queued_jobs.musl_crt_file[@intFromEnum(musl.CrtFile.libc_a)] = true,
2461 .dynamic => comp.queued_jobs.musl_crt_file[@intFromEnum(musl.CrtFile.libc_so)] = true,2455 .dynamic => comp.queued_jobs.musl_crt_file[@intFromEnum(musl.CrtFile.libc_so)] = true,
2462 }2456 }
2463 comp.link_task_queue.pending_prelink_tasks += 1;
2464 } else if (target.isGnuLibC()) {2457 } else if (target.isGnuLibC()) {
2465 if (!std.zig.target.canBuildLibC(target)) return error.LibCUnavailable;2458 if (!std.zig.target.canBuildLibC(target)) return error.LibCUnavailable;
24662459
2467 if (glibc.needsCrt0(comp.config.output_mode)) |f| {2460 if (glibc.needsCrt0(comp.config.output_mode)) |f| {
2468 comp.queued_jobs.glibc_crt_file[@intFromEnum(f)] = true;2461 comp.queued_jobs.glibc_crt_file[@intFromEnum(f)] = true;
2469 comp.link_task_queue.pending_prelink_tasks += 1;
2470 }2462 }
2471 comp.queued_jobs.glibc_shared_objects = true;2463 comp.queued_jobs.glibc_shared_objects = true;
2472 comp.link_task_queue.pending_prelink_tasks += glibc.sharedObjectsCount(target);
24732464
2474 comp.queued_jobs.glibc_crt_file[@intFromEnum(glibc.CrtFile.libc_nonshared_a)] = true;2465 comp.queued_jobs.glibc_crt_file[@intFromEnum(glibc.CrtFile.libc_nonshared_a)] = true;
2475 comp.link_task_queue.pending_prelink_tasks += 1;
2476 } else if (target.isFreeBSDLibC()) {2466 } else if (target.isFreeBSDLibC()) {
2477 if (!std.zig.target.canBuildLibC(target)) return error.LibCUnavailable;2467 if (!std.zig.target.canBuildLibC(target)) return error.LibCUnavailable;
24782468
2479 if (freebsd.needsCrt0(comp.config.output_mode)) |f| {2469 if (freebsd.needsCrt0(comp.config.output_mode)) |f| {
2480 comp.queued_jobs.freebsd_crt_file[@intFromEnum(f)] = true;2470 comp.queued_jobs.freebsd_crt_file[@intFromEnum(f)] = true;
2481 comp.link_task_queue.pending_prelink_tasks += 1;
2482 }2471 }
24832472
2484 comp.queued_jobs.freebsd_shared_objects = true;2473 comp.queued_jobs.freebsd_shared_objects = true;
2485 comp.link_task_queue.pending_prelink_tasks += freebsd.sharedObjectsCount();
2486 } else if (target.isNetBSDLibC()) {2474 } else if (target.isNetBSDLibC()) {
2487 if (!std.zig.target.canBuildLibC(target)) return error.LibCUnavailable;2475 if (!std.zig.target.canBuildLibC(target)) return error.LibCUnavailable;
24882476
2489 if (netbsd.needsCrt0(comp.config.output_mode)) |f| {2477 if (netbsd.needsCrt0(comp.config.output_mode)) |f| {
2490 comp.queued_jobs.netbsd_crt_file[@intFromEnum(f)] = true;2478 comp.queued_jobs.netbsd_crt_file[@intFromEnum(f)] = true;
2491 comp.link_task_queue.pending_prelink_tasks += 1;
2492 }2479 }
24932480
2494 comp.queued_jobs.netbsd_shared_objects = true;2481 comp.queued_jobs.netbsd_shared_objects = true;
2495 comp.link_task_queue.pending_prelink_tasks += netbsd.sharedObjectsCount();
2496 } else if (target.isWasiLibC()) {2482 } else if (target.isWasiLibC()) {
2497 if (!std.zig.target.canBuildLibC(target)) return error.LibCUnavailable;2483 if (!std.zig.target.canBuildLibC(target)) return error.LibCUnavailable;
24982484
2499 comp.queued_jobs.wasi_libc_crt_file[@intFromEnum(wasi_libc.execModelCrtFile(comp.config.wasi_exec_model))] = true;2485 comp.queued_jobs.wasi_libc_crt_file[@intFromEnum(wasi_libc.execModelCrtFile(comp.config.wasi_exec_model))] = true;
2500 comp.queued_jobs.wasi_libc_crt_file[@intFromEnum(wasi_libc.CrtFile.libc_a)] = true;2486 comp.queued_jobs.wasi_libc_crt_file[@intFromEnum(wasi_libc.CrtFile.libc_a)] = true;
2501 comp.link_task_queue.pending_prelink_tasks += 2;
2502 } else if (target.isMinGW()) {2487 } else if (target.isMinGW()) {
2503 if (!std.zig.target.canBuildLibC(target)) return error.LibCUnavailable;2488 if (!std.zig.target.canBuildLibC(target)) return error.LibCUnavailable;
25042489
2505 const main_crt_file: mingw.CrtFile = if (is_dyn_lib) .dllcrt2_o else .crt2_o;2490 const main_crt_file: mingw.CrtFile = if (is_dyn_lib) .dllcrt2_o else .crt2_o;
2506 comp.queued_jobs.mingw_crt_file[@intFromEnum(main_crt_file)] = true;2491 comp.queued_jobs.mingw_crt_file[@intFromEnum(main_crt_file)] = true;
2507 comp.queued_jobs.mingw_crt_file[@intFromEnum(mingw.CrtFile.libmingw32_lib)] = true;2492 comp.queued_jobs.mingw_crt_file[@intFromEnum(mingw.CrtFile.libmingw32_lib)] = true;
2508 comp.link_task_queue.pending_prelink_tasks += 2;
25092493
2510 // When linking mingw-w64 there are some import libs we always need.2494 // When linking mingw-w64 there are some import libs we always need.
2511 try comp.windows_libs.ensureUnusedCapacity(gpa, mingw.always_link_libs.len);2495 try comp.windows_libs.ensureUnusedCapacity(gpa, mingw.always_link_libs.len);
...@@ -2519,7 +2503,6 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil...@@ -2519,7 +2503,6 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil
2519 target.isMinGW())2503 target.isMinGW())
2520 {2504 {
2521 comp.queued_jobs.zigc_lib = true;2505 comp.queued_jobs.zigc_lib = true;
2522 comp.link_task_queue.pending_prelink_tasks += 1;
2523 }2506 }
2524 }2507 }
25252508
...@@ -2536,50 +2519,41 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil...@@ -2536,50 +2519,41 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil
2536 }2519 }
2537 if (comp.wantBuildLibUnwindFromSource()) {2520 if (comp.wantBuildLibUnwindFromSource()) {
2538 comp.queued_jobs.libunwind = true;2521 comp.queued_jobs.libunwind = true;
2539 comp.link_task_queue.pending_prelink_tasks += 1;
2540 }2522 }
2541 if (build_options.have_llvm and is_exe_or_dyn_lib and comp.config.link_libcpp) {2523 if (build_options.have_llvm and is_exe_or_dyn_lib and comp.config.link_libcpp) {
2542 comp.queued_jobs.libcxx = true;2524 comp.queued_jobs.libcxx = true;
2543 comp.queued_jobs.libcxxabi = true;2525 comp.queued_jobs.libcxxabi = true;
2544 comp.link_task_queue.pending_prelink_tasks += 2;
2545 }2526 }
2546 if (build_options.have_llvm and is_exe_or_dyn_lib and comp.config.any_sanitize_thread) {2527 if (build_options.have_llvm and is_exe_or_dyn_lib and comp.config.any_sanitize_thread) {
2547 comp.queued_jobs.libtsan = true;2528 comp.queued_jobs.libtsan = true;
2548 comp.link_task_queue.pending_prelink_tasks += 1;
2549 }2529 }
25502530
2551 if (can_build_compiler_rt) {2531 if (can_build_compiler_rt) {
2552 if (comp.compiler_rt_strat == .lib) {2532 if (comp.compiler_rt_strat == .lib) {
2553 log.debug("queuing a job to build compiler_rt_lib", .{});2533 log.debug("queuing a job to build compiler_rt_lib", .{});
2554 comp.queued_jobs.compiler_rt_lib = true;2534 comp.queued_jobs.compiler_rt_lib = true;
2555 comp.link_task_queue.pending_prelink_tasks += 1;
2556 } else if (comp.compiler_rt_strat == .obj) {2535 } else if (comp.compiler_rt_strat == .obj) {
2557 log.debug("queuing a job to build compiler_rt_obj", .{});2536 log.debug("queuing a job to build compiler_rt_obj", .{});
2558 // In this case we are making a static library, so we ask2537 // In this case we are making a static library, so we ask
2559 // for a compiler-rt object to put in it.2538 // for a compiler-rt object to put in it.
2560 comp.queued_jobs.compiler_rt_obj = true;2539 comp.queued_jobs.compiler_rt_obj = true;
2561 comp.link_task_queue.pending_prelink_tasks += 1;
2562 } else if (comp.compiler_rt_strat == .dyn_lib) {2540 } else if (comp.compiler_rt_strat == .dyn_lib) {
2563 // hack for stage2_x86_64 + coff2541 // hack for stage2_x86_64 + coff
2564 log.debug("queuing a job to build compiler_rt_dyn_lib", .{});2542 log.debug("queuing a job to build compiler_rt_dyn_lib", .{});
2565 comp.queued_jobs.compiler_rt_dyn_lib = true;2543 comp.queued_jobs.compiler_rt_dyn_lib = true;
2566 comp.link_task_queue.pending_prelink_tasks += 1;
2567 }2544 }
25682545
2569 if (comp.ubsan_rt_strat == .lib) {2546 if (comp.ubsan_rt_strat == .lib) {
2570 log.debug("queuing a job to build ubsan_rt_lib", .{});2547 log.debug("queuing a job to build ubsan_rt_lib", .{});
2571 comp.queued_jobs.ubsan_rt_lib = true;2548 comp.queued_jobs.ubsan_rt_lib = true;
2572 comp.link_task_queue.pending_prelink_tasks += 1;
2573 } else if (comp.ubsan_rt_strat == .obj) {2549 } else if (comp.ubsan_rt_strat == .obj) {
2574 log.debug("queuing a job to build ubsan_rt_obj", .{});2550 log.debug("queuing a job to build ubsan_rt_obj", .{});
2575 comp.queued_jobs.ubsan_rt_obj = true;2551 comp.queued_jobs.ubsan_rt_obj = true;
2576 comp.link_task_queue.pending_prelink_tasks += 1;
2577 }2552 }
25782553
2579 if (is_exe_or_dyn_lib and comp.config.any_fuzz) {2554 if (is_exe_or_dyn_lib and comp.config.any_fuzz) {
2580 log.debug("queuing a job to build libfuzzer", .{});2555 log.debug("queuing a job to build libfuzzer", .{});
2581 comp.queued_jobs.fuzzer_lib = true;2556 comp.queued_jobs.fuzzer_lib = true;
2582 comp.link_task_queue.pending_prelink_tasks += 1;
2583 }2557 }
2584 }2558 }
2585 }2559 }
...@@ -2587,8 +2561,6 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil...@@ -2587,8 +2561,6 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil
2587 try comp.link_task_queue.queued_prelink.append(gpa, .load_explicitly_provided);2561 try comp.link_task_queue.queued_prelink.append(gpa, .load_explicitly_provided);
2588 }2562 }
2589 log.debug("queued prelink tasks: {d}", .{comp.link_task_queue.queued_prelink.items.len});2563 log.debug("queued prelink tasks: {d}", .{comp.link_task_queue.queued_prelink.items.len});
2590 log.debug("pending prelink tasks: {d}", .{comp.link_task_queue.pending_prelink_tasks});
2591
2592 return comp;2564 return comp;
2593}2565}
25942566
...@@ -4408,10 +4380,8 @@ fn performAllTheWork(...@@ -4408,10 +4380,8 @@ fn performAllTheWork(
4408 comp.link_task_wait_group.reset();4380 comp.link_task_wait_group.reset();
4409 defer comp.link_task_wait_group.wait();4381 defer comp.link_task_wait_group.wait();
44104382
4411 comp.link_prog_node.increaseEstimatedTotalItems(4383 // Already-queued prelink tasks
4412 comp.link_task_queue.queued_prelink.items.len + // already queued prelink tasks4384 comp.link_prog_node.increaseEstimatedTotalItems(comp.link_task_queue.queued_prelink.items.len);
4413 comp.link_task_queue.pending_prelink_tasks, // prelink tasks which will be queued
4414 );
4415 comp.link_task_queue.start(comp);4385 comp.link_task_queue.start(comp);
44164386
4417 if (comp.emit_docs != null) {4387 if (comp.emit_docs != null) {
...@@ -4427,6 +4397,7 @@ fn performAllTheWork(...@@ -4427,6 +4397,7 @@ fn performAllTheWork(
4427 // compiler-rt due to LLD bugs as well, e.g.:4397 // compiler-rt due to LLD bugs as well, e.g.:
4428 //4398 //
4429 // https://github.com/llvm/llvm-project/issues/43698#issuecomment-25426606114399 // https://github.com/llvm/llvm-project/issues/43698#issuecomment-2542660611
4400 comp.link_task_queue.startPrelinkItem();
4430 comp.link_task_wait_group.spawnManager(buildRt, .{4401 comp.link_task_wait_group.spawnManager(buildRt, .{
4431 comp,4402 comp,
4432 "compiler_rt.zig",4403 "compiler_rt.zig",
...@@ -4444,6 +4415,7 @@ fn performAllTheWork(...@@ -4444,6 +4415,7 @@ fn performAllTheWork(
4444 }4415 }
44454416
4446 if (comp.queued_jobs.compiler_rt_obj and comp.compiler_rt_obj == null) {4417 if (comp.queued_jobs.compiler_rt_obj and comp.compiler_rt_obj == null) {
4418 comp.link_task_queue.startPrelinkItem();
4447 comp.link_task_wait_group.spawnManager(buildRt, .{4419 comp.link_task_wait_group.spawnManager(buildRt, .{
4448 comp,4420 comp,
4449 "compiler_rt.zig",4421 "compiler_rt.zig",
...@@ -4462,6 +4434,7 @@ fn performAllTheWork(...@@ -4462,6 +4434,7 @@ fn performAllTheWork(
44624434
4463 // hack for stage2_x86_64 + coff4435 // hack for stage2_x86_64 + coff
4464 if (comp.queued_jobs.compiler_rt_dyn_lib and comp.compiler_rt_dyn_lib == null) {4436 if (comp.queued_jobs.compiler_rt_dyn_lib and comp.compiler_rt_dyn_lib == null) {
4437 comp.link_task_queue.startPrelinkItem();
4465 comp.link_task_wait_group.spawnManager(buildRt, .{4438 comp.link_task_wait_group.spawnManager(buildRt, .{
4466 comp,4439 comp,
4467 "compiler_rt.zig",4440 "compiler_rt.zig",
...@@ -4479,6 +4452,7 @@ fn performAllTheWork(...@@ -4479,6 +4452,7 @@ fn performAllTheWork(
4479 }4452 }
44804453
4481 if (comp.queued_jobs.fuzzer_lib and comp.fuzzer_lib == null) {4454 if (comp.queued_jobs.fuzzer_lib and comp.fuzzer_lib == null) {
4455 comp.link_task_queue.startPrelinkItem();
4482 comp.link_task_wait_group.spawnManager(buildRt, .{4456 comp.link_task_wait_group.spawnManager(buildRt, .{
4483 comp,4457 comp,
4484 "fuzzer.zig",4458 "fuzzer.zig",
...@@ -4493,6 +4467,7 @@ fn performAllTheWork(...@@ -4493,6 +4467,7 @@ fn performAllTheWork(
4493 }4467 }
44944468
4495 if (comp.queued_jobs.ubsan_rt_lib and comp.ubsan_rt_lib == null) {4469 if (comp.queued_jobs.ubsan_rt_lib and comp.ubsan_rt_lib == null) {
4470 comp.link_task_queue.startPrelinkItem();
4496 comp.link_task_wait_group.spawnManager(buildRt, .{4471 comp.link_task_wait_group.spawnManager(buildRt, .{
4497 comp,4472 comp,
4498 "ubsan_rt.zig",4473 "ubsan_rt.zig",
...@@ -4509,6 +4484,7 @@ fn performAllTheWork(...@@ -4509,6 +4484,7 @@ fn performAllTheWork(
4509 }4484 }
45104485
4511 if (comp.queued_jobs.ubsan_rt_obj and comp.ubsan_rt_obj == null) {4486 if (comp.queued_jobs.ubsan_rt_obj and comp.ubsan_rt_obj == null) {
4487 comp.link_task_queue.startPrelinkItem();
4512 comp.link_task_wait_group.spawnManager(buildRt, .{4488 comp.link_task_wait_group.spawnManager(buildRt, .{
4513 comp,4489 comp,
4514 "ubsan_rt.zig",4490 "ubsan_rt.zig",
...@@ -4525,40 +4501,49 @@ fn performAllTheWork(...@@ -4525,40 +4501,49 @@ fn performAllTheWork(
4525 }4501 }
45264502
4527 if (comp.queued_jobs.glibc_shared_objects) {4503 if (comp.queued_jobs.glibc_shared_objects) {
4504 comp.link_task_queue.startPrelinkItem();
4528 comp.link_task_wait_group.spawnManager(buildGlibcSharedObjects, .{ comp, main_progress_node });4505 comp.link_task_wait_group.spawnManager(buildGlibcSharedObjects, .{ comp, main_progress_node });
4529 }4506 }
45304507
4531 if (comp.queued_jobs.freebsd_shared_objects) {4508 if (comp.queued_jobs.freebsd_shared_objects) {
4509 comp.link_task_queue.startPrelinkItem();
4532 comp.link_task_wait_group.spawnManager(buildFreeBSDSharedObjects, .{ comp, main_progress_node });4510 comp.link_task_wait_group.spawnManager(buildFreeBSDSharedObjects, .{ comp, main_progress_node });
4533 }4511 }
45344512
4535 if (comp.queued_jobs.netbsd_shared_objects) {4513 if (comp.queued_jobs.netbsd_shared_objects) {
4514 comp.link_task_queue.startPrelinkItem();
4536 comp.link_task_wait_group.spawnManager(buildNetBSDSharedObjects, .{ comp, main_progress_node });4515 comp.link_task_wait_group.spawnManager(buildNetBSDSharedObjects, .{ comp, main_progress_node });
4537 }4516 }
45384517
4539 if (comp.queued_jobs.libunwind) {4518 if (comp.queued_jobs.libunwind) {
4519 comp.link_task_queue.startPrelinkItem();
4540 comp.link_task_wait_group.spawnManager(buildLibUnwind, .{ comp, main_progress_node });4520 comp.link_task_wait_group.spawnManager(buildLibUnwind, .{ comp, main_progress_node });
4541 }4521 }
45424522
4543 if (comp.queued_jobs.libcxx) {4523 if (comp.queued_jobs.libcxx) {
4524 comp.link_task_queue.startPrelinkItem();
4544 comp.link_task_wait_group.spawnManager(buildLibCxx, .{ comp, main_progress_node });4525 comp.link_task_wait_group.spawnManager(buildLibCxx, .{ comp, main_progress_node });
4545 }4526 }
45464527
4547 if (comp.queued_jobs.libcxxabi) {4528 if (comp.queued_jobs.libcxxabi) {
4529 comp.link_task_queue.startPrelinkItem();
4548 comp.link_task_wait_group.spawnManager(buildLibCxxAbi, .{ comp, main_progress_node });4530 comp.link_task_wait_group.spawnManager(buildLibCxxAbi, .{ comp, main_progress_node });
4549 }4531 }
45504532
4551 if (comp.queued_jobs.libtsan) {4533 if (comp.queued_jobs.libtsan) {
4534 comp.link_task_queue.startPrelinkItem();
4552 comp.link_task_wait_group.spawnManager(buildLibTsan, .{ comp, main_progress_node });4535 comp.link_task_wait_group.spawnManager(buildLibTsan, .{ comp, main_progress_node });
4553 }4536 }
45544537
4555 if (comp.queued_jobs.zigc_lib and comp.zigc_static_lib == null) {4538 if (comp.queued_jobs.zigc_lib and comp.zigc_static_lib == null) {
4539 comp.link_task_queue.startPrelinkItem();
4556 comp.link_task_wait_group.spawnManager(buildLibZigC, .{ comp, main_progress_node });4540 comp.link_task_wait_group.spawnManager(buildLibZigC, .{ comp, main_progress_node });
4557 }4541 }
45584542
4559 for (0..@typeInfo(musl.CrtFile).@"enum".fields.len) |i| {4543 for (0..@typeInfo(musl.CrtFile).@"enum".fields.len) |i| {
4560 if (comp.queued_jobs.musl_crt_file[i]) {4544 if (comp.queued_jobs.musl_crt_file[i]) {
4561 const tag: musl.CrtFile = @enumFromInt(i);4545 const tag: musl.CrtFile = @enumFromInt(i);
4546 comp.link_task_queue.startPrelinkItem();
4562 comp.link_task_wait_group.spawnManager(buildMuslCrtFile, .{ comp, tag, main_progress_node });4547 comp.link_task_wait_group.spawnManager(buildMuslCrtFile, .{ comp, tag, main_progress_node });
4563 }4548 }
4564 }4549 }
...@@ -4566,6 +4551,7 @@ fn performAllTheWork(...@@ -4566,6 +4551,7 @@ fn performAllTheWork(
4566 for (0..@typeInfo(glibc.CrtFile).@"enum".fields.len) |i| {4551 for (0..@typeInfo(glibc.CrtFile).@"enum".fields.len) |i| {
4567 if (comp.queued_jobs.glibc_crt_file[i]) {4552 if (comp.queued_jobs.glibc_crt_file[i]) {
4568 const tag: glibc.CrtFile = @enumFromInt(i);4553 const tag: glibc.CrtFile = @enumFromInt(i);
4554 comp.link_task_queue.startPrelinkItem();
4569 comp.link_task_wait_group.spawnManager(buildGlibcCrtFile, .{ comp, tag, main_progress_node });4555 comp.link_task_wait_group.spawnManager(buildGlibcCrtFile, .{ comp, tag, main_progress_node });
4570 }4556 }
4571 }4557 }
...@@ -4573,6 +4559,7 @@ fn performAllTheWork(...@@ -4573,6 +4559,7 @@ fn performAllTheWork(
4573 for (0..@typeInfo(freebsd.CrtFile).@"enum".fields.len) |i| {4559 for (0..@typeInfo(freebsd.CrtFile).@"enum".fields.len) |i| {
4574 if (comp.queued_jobs.freebsd_crt_file[i]) {4560 if (comp.queued_jobs.freebsd_crt_file[i]) {
4575 const tag: freebsd.CrtFile = @enumFromInt(i);4561 const tag: freebsd.CrtFile = @enumFromInt(i);
4562 comp.link_task_queue.startPrelinkItem();
4576 comp.link_task_wait_group.spawnManager(buildFreeBSDCrtFile, .{ comp, tag, main_progress_node });4563 comp.link_task_wait_group.spawnManager(buildFreeBSDCrtFile, .{ comp, tag, main_progress_node });
4577 }4564 }
4578 }4565 }
...@@ -4580,6 +4567,7 @@ fn performAllTheWork(...@@ -4580,6 +4567,7 @@ fn performAllTheWork(
4580 for (0..@typeInfo(netbsd.CrtFile).@"enum".fields.len) |i| {4567 for (0..@typeInfo(netbsd.CrtFile).@"enum".fields.len) |i| {
4581 if (comp.queued_jobs.netbsd_crt_file[i]) {4568 if (comp.queued_jobs.netbsd_crt_file[i]) {
4582 const tag: netbsd.CrtFile = @enumFromInt(i);4569 const tag: netbsd.CrtFile = @enumFromInt(i);
4570 comp.link_task_queue.startPrelinkItem();
4583 comp.link_task_wait_group.spawnManager(buildNetBSDCrtFile, .{ comp, tag, main_progress_node });4571 comp.link_task_wait_group.spawnManager(buildNetBSDCrtFile, .{ comp, tag, main_progress_node });
4584 }4572 }
4585 }4573 }
...@@ -4587,6 +4575,7 @@ fn performAllTheWork(...@@ -4587,6 +4575,7 @@ fn performAllTheWork(
4587 for (0..@typeInfo(wasi_libc.CrtFile).@"enum".fields.len) |i| {4575 for (0..@typeInfo(wasi_libc.CrtFile).@"enum".fields.len) |i| {
4588 if (comp.queued_jobs.wasi_libc_crt_file[i]) {4576 if (comp.queued_jobs.wasi_libc_crt_file[i]) {
4589 const tag: wasi_libc.CrtFile = @enumFromInt(i);4577 const tag: wasi_libc.CrtFile = @enumFromInt(i);
4578 comp.link_task_queue.startPrelinkItem();
4590 comp.link_task_wait_group.spawnManager(buildWasiLibcCrtFile, .{ comp, tag, main_progress_node });4579 comp.link_task_wait_group.spawnManager(buildWasiLibcCrtFile, .{ comp, tag, main_progress_node });
4591 }4580 }
4592 }4581 }
...@@ -4594,6 +4583,7 @@ fn performAllTheWork(...@@ -4594,6 +4583,7 @@ fn performAllTheWork(
4594 for (0..@typeInfo(mingw.CrtFile).@"enum".fields.len) |i| {4583 for (0..@typeInfo(mingw.CrtFile).@"enum".fields.len) |i| {
4595 if (comp.queued_jobs.mingw_crt_file[i]) {4584 if (comp.queued_jobs.mingw_crt_file[i]) {
4596 const tag: mingw.CrtFile = @enumFromInt(i);4585 const tag: mingw.CrtFile = @enumFromInt(i);
4586 comp.link_task_queue.startPrelinkItem();
4597 comp.link_task_wait_group.spawnManager(buildMingwCrtFile, .{ comp, tag, main_progress_node });4587 comp.link_task_wait_group.spawnManager(buildMingwCrtFile, .{ comp, tag, main_progress_node });
4598 }4588 }
4599 }4589 }
...@@ -4665,12 +4655,14 @@ fn performAllTheWork(...@@ -4665,12 +4655,14 @@ fn performAllTheWork(
4665 }4655 }
46664656
4667 while (comp.c_object_work_queue.readItem()) |c_object| {4657 while (comp.c_object_work_queue.readItem()) |c_object| {
4658 comp.link_task_queue.startPrelinkItem();
4668 comp.thread_pool.spawnWg(&comp.link_task_wait_group, workerUpdateCObject, .{4659 comp.thread_pool.spawnWg(&comp.link_task_wait_group, workerUpdateCObject, .{
4669 comp, c_object, main_progress_node,4660 comp, c_object, main_progress_node,
4670 });4661 });
4671 }4662 }
46724663
4673 while (comp.win32_resource_work_queue.readItem()) |win32_resource| {4664 while (comp.win32_resource_work_queue.readItem()) |win32_resource| {
4665 comp.link_task_queue.startPrelinkItem();
4674 comp.thread_pool.spawnWg(&comp.link_task_wait_group, workerUpdateWin32Resource, .{4666 comp.thread_pool.spawnWg(&comp.link_task_wait_group, workerUpdateWin32Resource, .{
4675 comp, win32_resource, main_progress_node,4667 comp, win32_resource, main_progress_node,
4676 });4668 });
...@@ -4773,15 +4765,14 @@ fn performAllTheWork(...@@ -4773,15 +4765,14 @@ fn performAllTheWork(
4773 }4765 }
4774 };4766 };
47754767
4768 // We aren't going to queue any more prelink tasks.
4769 comp.link_task_queue.finishPrelinkItem(comp);
4770
4776 if (!comp.separateCodegenThreadOk()) {4771 if (!comp.separateCodegenThreadOk()) {
4777 // Waits until all input files have been parsed.4772 // Waits until all input files have been parsed.
4778 comp.link_task_wait_group.wait();4773 comp.link_task_wait_group.wait();
4779 comp.link_task_wait_group.reset();4774 comp.link_task_wait_group.reset();
4780 std.log.scoped(.link).debug("finished waiting for link_task_wait_group", .{});4775 std.log.scoped(.link).debug("finished waiting for link_task_wait_group", .{});
4781 if (comp.link_task_queue.pending_prelink_tasks > 0) {
4782 // Indicates an error occurred preventing prelink phase from completing.
4783 return;
4784 }
4785 }4776 }
47864777
4787 if (comp.zcu != null) {4778 if (comp.zcu != null) {
...@@ -5568,6 +5559,7 @@ fn workerUpdateCObject(...@@ -5568,6 +5559,7 @@ fn workerUpdateCObject(
5568 c_object: *CObject,5559 c_object: *CObject,
5569 progress_node: std.Progress.Node,5560 progress_node: std.Progress.Node,
5570) void {5561) void {
5562 defer comp.link_task_queue.finishPrelinkItem(comp);
5571 comp.updateCObject(c_object, progress_node) catch |err| switch (err) {5563 comp.updateCObject(c_object, progress_node) catch |err| switch (err) {
5572 error.AnalysisFail => return,5564 error.AnalysisFail => return,
5573 else => {5565 else => {
...@@ -5585,6 +5577,7 @@ fn workerUpdateWin32Resource(...@@ -5585,6 +5577,7 @@ fn workerUpdateWin32Resource(
5585 win32_resource: *Win32Resource,5577 win32_resource: *Win32Resource,
5586 progress_node: std.Progress.Node,5578 progress_node: std.Progress.Node,
5587) void {5579) void {
5580 defer comp.link_task_queue.finishPrelinkItem(comp);
5588 comp.updateWin32Resource(win32_resource, progress_node) catch |err| switch (err) {5581 comp.updateWin32Resource(win32_resource, progress_node) catch |err| switch (err) {
5589 error.AnalysisFail => return,5582 error.AnalysisFail => return,
5590 else => {5583 else => {
...@@ -5628,6 +5621,7 @@ fn buildRt(...@@ -5628,6 +5621,7 @@ fn buildRt(
5628 options: RtOptions,5621 options: RtOptions,
5629 out: *?CrtFile,5622 out: *?CrtFile,
5630) void {5623) void {
5624 defer comp.link_task_queue.finishPrelinkItem(comp);
5631 comp.buildOutputFromZig(5625 comp.buildOutputFromZig(
5632 root_source_name,5626 root_source_name,
5633 root_name,5627 root_name,
...@@ -5646,6 +5640,7 @@ fn buildRt(...@@ -5646,6 +5640,7 @@ fn buildRt(
5646}5640}
56475641
5648fn buildMuslCrtFile(comp: *Compilation, crt_file: musl.CrtFile, prog_node: std.Progress.Node) void {5642fn buildMuslCrtFile(comp: *Compilation, crt_file: musl.CrtFile, prog_node: std.Progress.Node) void {
5643 defer comp.link_task_queue.finishPrelinkItem(comp);
5649 if (musl.buildCrtFile(comp, crt_file, prog_node)) |_| {5644 if (musl.buildCrtFile(comp, crt_file, prog_node)) |_| {
5650 comp.queued_jobs.musl_crt_file[@intFromEnum(crt_file)] = false;5645 comp.queued_jobs.musl_crt_file[@intFromEnum(crt_file)] = false;
5651 } else |err| switch (err) {5646 } else |err| switch (err) {
...@@ -5657,6 +5652,7 @@ fn buildMuslCrtFile(comp: *Compilation, crt_file: musl.CrtFile, prog_node: std.P...@@ -5657,6 +5652,7 @@ fn buildMuslCrtFile(comp: *Compilation, crt_file: musl.CrtFile, prog_node: std.P
5657}5652}
56585653
5659fn buildGlibcCrtFile(comp: *Compilation, crt_file: glibc.CrtFile, prog_node: std.Progress.Node) void {5654fn buildGlibcCrtFile(comp: *Compilation, crt_file: glibc.CrtFile, prog_node: std.Progress.Node) void {
5655 defer comp.link_task_queue.finishPrelinkItem(comp);
5660 if (glibc.buildCrtFile(comp, crt_file, prog_node)) |_| {5656 if (glibc.buildCrtFile(comp, crt_file, prog_node)) |_| {
5661 comp.queued_jobs.glibc_crt_file[@intFromEnum(crt_file)] = false;5657 comp.queued_jobs.glibc_crt_file[@intFromEnum(crt_file)] = false;
5662 } else |err| switch (err) {5658 } else |err| switch (err) {
...@@ -5668,6 +5664,7 @@ fn buildGlibcCrtFile(comp: *Compilation, crt_file: glibc.CrtFile, prog_node: std...@@ -5668,6 +5664,7 @@ fn buildGlibcCrtFile(comp: *Compilation, crt_file: glibc.CrtFile, prog_node: std
5668}5664}
56695665
5670fn buildGlibcSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) void {5666fn buildGlibcSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) void {
5667 defer comp.link_task_queue.finishPrelinkItem(comp);
5671 if (glibc.buildSharedObjects(comp, prog_node)) |_| {5668 if (glibc.buildSharedObjects(comp, prog_node)) |_| {
5672 // The job should no longer be queued up since it succeeded.5669 // The job should no longer be queued up since it succeeded.
5673 comp.queued_jobs.glibc_shared_objects = false;5670 comp.queued_jobs.glibc_shared_objects = false;
...@@ -5680,6 +5677,7 @@ fn buildGlibcSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) voi...@@ -5680,6 +5677,7 @@ fn buildGlibcSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) voi
5680}5677}
56815678
5682fn buildFreeBSDCrtFile(comp: *Compilation, crt_file: freebsd.CrtFile, prog_node: std.Progress.Node) void {5679fn buildFreeBSDCrtFile(comp: *Compilation, crt_file: freebsd.CrtFile, prog_node: std.Progress.Node) void {
5680 defer comp.link_task_queue.finishPrelinkItem(comp);
5683 if (freebsd.buildCrtFile(comp, crt_file, prog_node)) |_| {5681 if (freebsd.buildCrtFile(comp, crt_file, prog_node)) |_| {
5684 comp.queued_jobs.freebsd_crt_file[@intFromEnum(crt_file)] = false;5682 comp.queued_jobs.freebsd_crt_file[@intFromEnum(crt_file)] = false;
5685 } else |err| switch (err) {5683 } else |err| switch (err) {
...@@ -5691,6 +5689,7 @@ fn buildFreeBSDCrtFile(comp: *Compilation, crt_file: freebsd.CrtFile, prog_node:...@@ -5691,6 +5689,7 @@ fn buildFreeBSDCrtFile(comp: *Compilation, crt_file: freebsd.CrtFile, prog_node:
5691}5689}
56925690
5693fn buildFreeBSDSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) void {5691fn buildFreeBSDSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) void {
5692 defer comp.link_task_queue.finishPrelinkItem(comp);
5694 if (freebsd.buildSharedObjects(comp, prog_node)) |_| {5693 if (freebsd.buildSharedObjects(comp, prog_node)) |_| {
5695 // The job should no longer be queued up since it succeeded.5694 // The job should no longer be queued up since it succeeded.
5696 comp.queued_jobs.freebsd_shared_objects = false;5695 comp.queued_jobs.freebsd_shared_objects = false;
...@@ -5703,6 +5702,7 @@ fn buildFreeBSDSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) v...@@ -5703,6 +5702,7 @@ fn buildFreeBSDSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) v
5703}5702}
57045703
5705fn buildNetBSDCrtFile(comp: *Compilation, crt_file: netbsd.CrtFile, prog_node: std.Progress.Node) void {5704fn buildNetBSDCrtFile(comp: *Compilation, crt_file: netbsd.CrtFile, prog_node: std.Progress.Node) void {
5705 defer comp.link_task_queue.finishPrelinkItem(comp);
5706 if (netbsd.buildCrtFile(comp, crt_file, prog_node)) |_| {5706 if (netbsd.buildCrtFile(comp, crt_file, prog_node)) |_| {
5707 comp.queued_jobs.netbsd_crt_file[@intFromEnum(crt_file)] = false;5707 comp.queued_jobs.netbsd_crt_file[@intFromEnum(crt_file)] = false;
5708 } else |err| switch (err) {5708 } else |err| switch (err) {
...@@ -5714,6 +5714,7 @@ fn buildNetBSDCrtFile(comp: *Compilation, crt_file: netbsd.CrtFile, prog_node: s...@@ -5714,6 +5714,7 @@ fn buildNetBSDCrtFile(comp: *Compilation, crt_file: netbsd.CrtFile, prog_node: s
5714}5714}
57155715
5716fn buildNetBSDSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) void {5716fn buildNetBSDSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) void {
5717 defer comp.link_task_queue.finishPrelinkItem(comp);
5717 if (netbsd.buildSharedObjects(comp, prog_node)) |_| {5718 if (netbsd.buildSharedObjects(comp, prog_node)) |_| {
5718 // The job should no longer be queued up since it succeeded.5719 // The job should no longer be queued up since it succeeded.
5719 comp.queued_jobs.netbsd_shared_objects = false;5720 comp.queued_jobs.netbsd_shared_objects = false;
...@@ -5726,6 +5727,7 @@ fn buildNetBSDSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) vo...@@ -5726,6 +5727,7 @@ fn buildNetBSDSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) vo
5726}5727}
57275728
5728fn buildMingwCrtFile(comp: *Compilation, crt_file: mingw.CrtFile, prog_node: std.Progress.Node) void {5729fn buildMingwCrtFile(comp: *Compilation, crt_file: mingw.CrtFile, prog_node: std.Progress.Node) void {
5730 defer comp.link_task_queue.finishPrelinkItem(comp);
5729 if (mingw.buildCrtFile(comp, crt_file, prog_node)) |_| {5731 if (mingw.buildCrtFile(comp, crt_file, prog_node)) |_| {
5730 comp.queued_jobs.mingw_crt_file[@intFromEnum(crt_file)] = false;5732 comp.queued_jobs.mingw_crt_file[@intFromEnum(crt_file)] = false;
5731 } else |err| switch (err) {5733 } else |err| switch (err) {
...@@ -5737,6 +5739,7 @@ fn buildMingwCrtFile(comp: *Compilation, crt_file: mingw.CrtFile, prog_node: std...@@ -5737,6 +5739,7 @@ fn buildMingwCrtFile(comp: *Compilation, crt_file: mingw.CrtFile, prog_node: std
5737}5739}
57385740
5739fn buildWasiLibcCrtFile(comp: *Compilation, crt_file: wasi_libc.CrtFile, prog_node: std.Progress.Node) void {5741fn buildWasiLibcCrtFile(comp: *Compilation, crt_file: wasi_libc.CrtFile, prog_node: std.Progress.Node) void {
5742 defer comp.link_task_queue.finishPrelinkItem(comp);
5740 if (wasi_libc.buildCrtFile(comp, crt_file, prog_node)) |_| {5743 if (wasi_libc.buildCrtFile(comp, crt_file, prog_node)) |_| {
5741 comp.queued_jobs.wasi_libc_crt_file[@intFromEnum(crt_file)] = false;5744 comp.queued_jobs.wasi_libc_crt_file[@intFromEnum(crt_file)] = false;
5742 } else |err| switch (err) {5745 } else |err| switch (err) {
...@@ -5748,6 +5751,7 @@ fn buildWasiLibcCrtFile(comp: *Compilation, crt_file: wasi_libc.CrtFile, prog_no...@@ -5748,6 +5751,7 @@ fn buildWasiLibcCrtFile(comp: *Compilation, crt_file: wasi_libc.CrtFile, prog_no
5748}5751}
57495752
5750fn buildLibUnwind(comp: *Compilation, prog_node: std.Progress.Node) void {5753fn buildLibUnwind(comp: *Compilation, prog_node: std.Progress.Node) void {
5754 defer comp.link_task_queue.finishPrelinkItem(comp);
5751 if (libunwind.buildStaticLib(comp, prog_node)) |_| {5755 if (libunwind.buildStaticLib(comp, prog_node)) |_| {
5752 comp.queued_jobs.libunwind = false;5756 comp.queued_jobs.libunwind = false;
5753 } else |err| switch (err) {5757 } else |err| switch (err) {
...@@ -5757,6 +5761,7 @@ fn buildLibUnwind(comp: *Compilation, prog_node: std.Progress.Node) void {...@@ -5757,6 +5761,7 @@ fn buildLibUnwind(comp: *Compilation, prog_node: std.Progress.Node) void {
5757}5761}
57585762
5759fn buildLibCxx(comp: *Compilation, prog_node: std.Progress.Node) void {5763fn buildLibCxx(comp: *Compilation, prog_node: std.Progress.Node) void {
5764 defer comp.link_task_queue.finishPrelinkItem(comp);
5760 if (libcxx.buildLibCxx(comp, prog_node)) |_| {5765 if (libcxx.buildLibCxx(comp, prog_node)) |_| {
5761 comp.queued_jobs.libcxx = false;5766 comp.queued_jobs.libcxx = false;
5762 } else |err| switch (err) {5767 } else |err| switch (err) {
...@@ -5766,6 +5771,7 @@ fn buildLibCxx(comp: *Compilation, prog_node: std.Progress.Node) void {...@@ -5766,6 +5771,7 @@ fn buildLibCxx(comp: *Compilation, prog_node: std.Progress.Node) void {
5766}5771}
57675772
5768fn buildLibCxxAbi(comp: *Compilation, prog_node: std.Progress.Node) void {5773fn buildLibCxxAbi(comp: *Compilation, prog_node: std.Progress.Node) void {
5774 defer comp.link_task_queue.finishPrelinkItem(comp);
5769 if (libcxx.buildLibCxxAbi(comp, prog_node)) |_| {5775 if (libcxx.buildLibCxxAbi(comp, prog_node)) |_| {
5770 comp.queued_jobs.libcxxabi = false;5776 comp.queued_jobs.libcxxabi = false;
5771 } else |err| switch (err) {5777 } else |err| switch (err) {
...@@ -5775,6 +5781,7 @@ fn buildLibCxxAbi(comp: *Compilation, prog_node: std.Progress.Node) void {...@@ -5775,6 +5781,7 @@ fn buildLibCxxAbi(comp: *Compilation, prog_node: std.Progress.Node) void {
5775}5781}
57765782
5777fn buildLibTsan(comp: *Compilation, prog_node: std.Progress.Node) void {5783fn buildLibTsan(comp: *Compilation, prog_node: std.Progress.Node) void {
5784 defer comp.link_task_queue.finishPrelinkItem(comp);
5778 if (libtsan.buildTsan(comp, prog_node)) |_| {5785 if (libtsan.buildTsan(comp, prog_node)) |_| {
5779 comp.queued_jobs.libtsan = false;5786 comp.queued_jobs.libtsan = false;
5780 } else |err| switch (err) {5787 } else |err| switch (err) {
...@@ -5784,6 +5791,7 @@ fn buildLibTsan(comp: *Compilation, prog_node: std.Progress.Node) void {...@@ -5784,6 +5791,7 @@ fn buildLibTsan(comp: *Compilation, prog_node: std.Progress.Node) void {
5784}5791}
57855792
5786fn buildLibZigC(comp: *Compilation, prog_node: std.Progress.Node) void {5793fn buildLibZigC(comp: *Compilation, prog_node: std.Progress.Node) void {
5794 defer comp.link_task_queue.finishPrelinkItem(comp);
5787 comp.buildOutputFromZig(5795 comp.buildOutputFromZig(
5788 "c.zig",5796 "c.zig",
5789 "zigc",5797 "zigc",
...@@ -7721,6 +7729,7 @@ pub fn queuePrelinkTaskMode(comp: *Compilation, path: Cache.Path, config: *const...@@ -7721,6 +7729,7 @@ pub fn queuePrelinkTaskMode(comp: *Compilation, path: Cache.Path, config: *const
7721/// Only valid to call during `update`. Automatically handles queuing up a7729/// Only valid to call during `update`. Automatically handles queuing up a
7722/// linker worker task if there is not already one.7730/// linker worker task if there is not already one.
7723pub fn queuePrelinkTasks(comp: *Compilation, tasks: []const link.PrelinkTask) void {7731pub fn queuePrelinkTasks(comp: *Compilation, tasks: []const link.PrelinkTask) void {
7732 comp.link_prog_node.increaseEstimatedTotalItems(tasks.len);
7724 comp.link_task_queue.enqueuePrelink(comp, tasks) catch |err| switch (err) {7733 comp.link_task_queue.enqueuePrelink(comp, tasks) catch |err| switch (err) {
7725 error.OutOfMemory => return comp.setAllocFailure(),7734 error.OutOfMemory => return comp.setAllocFailure(),
7726 };7735 };
src/libs/freebsd.zig-4
...@@ -977,10 +977,6 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye...@@ -977,10 +977,6 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye
977 });977 });
978}978}
979979
980pub fn sharedObjectsCount() u8 {
981 return libs.len;
982}
983
984fn queueSharedObjects(comp: *Compilation, so_files: BuiltSharedObjects) void {980fn queueSharedObjects(comp: *Compilation, so_files: BuiltSharedObjects) void {
985 assert(comp.freebsd_so_files == null);981 assert(comp.freebsd_so_files == null);
986 comp.freebsd_so_files = so_files;982 comp.freebsd_so_files = so_files;
src/libs/glibc.zig-12
...@@ -1130,18 +1130,6 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye...@@ -1130,18 +1130,6 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye
1130 });1130 });
1131}1131}
11321132
1133pub fn sharedObjectsCount(target: *const std.Target) u8 {
1134 const target_version = target.os.versionRange().gnuLibCVersion() orelse return 0;
1135 var count: u8 = 0;
1136 for (libs) |lib| {
1137 if (lib.removed_in) |rem_in| {
1138 if (target_version.order(rem_in) != .lt) continue;
1139 }
1140 count += 1;
1141 }
1142 return count;
1143}
1144
1145fn queueSharedObjects(comp: *Compilation, so_files: BuiltSharedObjects) void {1133fn queueSharedObjects(comp: *Compilation, so_files: BuiltSharedObjects) void {
1146 const target_version = comp.getTarget().os.versionRange().gnuLibCVersion().?;1134 const target_version = comp.getTarget().os.versionRange().gnuLibCVersion().?;
11471135
src/libs/netbsd.zig-4
...@@ -642,10 +642,6 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye...@@ -642,10 +642,6 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye
642 });642 });
643}643}
644644
645pub fn sharedObjectsCount() u8 {
646 return libs.len;
647}
648
649fn queueSharedObjects(comp: *Compilation, so_files: BuiltSharedObjects) void {645fn queueSharedObjects(comp: *Compilation, so_files: BuiltSharedObjects) void {
650 assert(comp.netbsd_so_files == null);646 assert(comp.netbsd_so_files == null);
651 comp.netbsd_so_files = so_files;647 comp.netbsd_so_files = so_files;
src/link/Queue.zig+45-13
...@@ -16,9 +16,9 @@ mutex: std.Thread.Mutex,...@@ -16,9 +16,9 @@ mutex: std.Thread.Mutex,
16/// Validates that only one `flushTaskQueue` thread is running at a time.16/// Validates that only one `flushTaskQueue` thread is running at a time.
17flush_safety: std.debug.SafetyLock,17flush_safety: std.debug.SafetyLock,
1818
19/// This is the number of prelink tasks which are expected but have not yet been enqueued.19/// This value is positive while there are still prelink tasks yet to be queued. Once they are
20/// Guarded by `mutex`.20/// all queued, this value becomes 0, and ZCU tasks can be run. Guarded by `mutex`.
21pending_prelink_tasks: u32,21prelink_wait_count: u32,
2222
23/// Prelink tasks which have been enqueued and are not yet owned by the worker thread.23/// Prelink tasks which have been enqueued and are not yet owned by the worker thread.
24/// Allocated into `gpa`, guarded by `mutex`.24/// Allocated into `gpa`, guarded by `mutex`.
...@@ -59,7 +59,7 @@ state: union(enum) {...@@ -59,7 +59,7 @@ state: union(enum) {
59 /// The link thread is currently running or queued to run.59 /// The link thread is currently running or queued to run.
60 running,60 running,
61 /// The link thread is not running or queued, because it has exhausted all immediately available61 /// The link thread is not running or queued, because it has exhausted all immediately available
62 /// tasks. It should be spawned when more tasks are enqueued. If `pending_prelink_tasks` is not62 /// tasks. It should be spawned when more tasks are enqueued. If `prelink_wait_count` is not
63 /// zero, we are specifically waiting for prelink tasks.63 /// zero, we are specifically waiting for prelink tasks.
64 finished,64 finished,
65 /// The link thread is not running or queued, because it is waiting for this MIR to be populated.65 /// The link thread is not running or queued, because it is waiting for this MIR to be populated.
...@@ -73,11 +73,11 @@ state: union(enum) {...@@ -73,11 +73,11 @@ state: union(enum) {
73const max_air_bytes_in_flight = 10 * 1024 * 1024;73const max_air_bytes_in_flight = 10 * 1024 * 1024;
7474
75/// The initial `Queue` state, containing no tasks, expecting no prelink tasks, and with no running worker thread.75/// The initial `Queue` state, containing no tasks, expecting no prelink tasks, and with no running worker thread.
76/// The `pending_prelink_tasks` and `queued_prelink` fields may be modified as needed before calling `start`.76/// The `queued_prelink` field may be appended to before calling `start`.
77pub const empty: Queue = .{77pub const empty: Queue = .{
78 .mutex = .{},78 .mutex = .{},
79 .flush_safety = .{},79 .flush_safety = .{},
80 .pending_prelink_tasks = 0,80 .prelink_wait_count = undefined, // set in `start`
81 .queued_prelink = .empty,81 .queued_prelink = .empty,
82 .wip_prelink = .empty,82 .wip_prelink = .empty,
83 .queued_zcu = .empty,83 .queued_zcu = .empty,
...@@ -100,17 +100,49 @@ pub fn deinit(q: *Queue, comp: *Compilation) void {...@@ -100,17 +100,49 @@ pub fn deinit(q: *Queue, comp: *Compilation) void {
100}100}
101101
102/// This is expected to be called exactly once, after which the caller must not directly access102/// This is expected to be called exactly once, after which the caller must not directly access
103/// `queued_prelink` or `pending_prelink_tasks` any longer. This will spawn the link thread if103/// `queued_prelink` any longer. This will spawn the link thread if necessary.
104/// necessary.
105pub fn start(q: *Queue, comp: *Compilation) void {104pub fn start(q: *Queue, comp: *Compilation) void {
106 assert(q.state == .finished);105 assert(q.state == .finished);
107 assert(q.queued_zcu.items.len == 0);106 assert(q.queued_zcu.items.len == 0);
107 // Reset this to 1. We can't init it to 1 in `empty`, because it would fall to 0 on successive
108 // incremental updates, but we still need the initial 1.
109 q.prelink_wait_count = 1;
108 if (q.queued_prelink.items.len != 0) {110 if (q.queued_prelink.items.len != 0) {
109 q.state = .running;111 q.state = .running;
110 comp.thread_pool.spawnWgId(&comp.link_task_wait_group, flushTaskQueue, .{ q, comp });112 comp.thread_pool.spawnWgId(&comp.link_task_wait_group, flushTaskQueue, .{ q, comp });
111 }113 }
112}114}
113115
116/// Every call to this must be paired with a call to `finishPrelinkItem`.
117pub fn startPrelinkItem(q: *Queue) void {
118 q.mutex.lock();
119 defer q.mutex.unlock();
120 assert(q.prelink_wait_count > 0); // must not have finished everything already
121 q.prelink_wait_count += 1;
122}
123/// This function must be called exactly one more time than `startPrelinkItem` is. The final call
124/// indicates that we have finished calling `startPrelinkItem`, so once all pending items finish,
125/// we are ready to move on to ZCU tasks.
126pub fn finishPrelinkItem(q: *Queue, comp: *Compilation) void {
127 {
128 q.mutex.lock();
129 defer q.mutex.unlock();
130 q.prelink_wait_count -= 1;
131 if (q.prelink_wait_count != 0) return;
132 // The prelink task count dropped to 0; restart the linker thread if necessary.
133 switch (q.state) {
134 .wait_for_mir => unreachable, // we've not started zcu tasks yet
135 .running => return,
136 .finished => {},
137 }
138 assert(q.queued_prelink.items.len == 0);
139 // Even if there are no ZCU tasks, we must restart the linker thread to make sure
140 // that `link.File.prelink()` is called.
141 q.state = .running;
142 }
143 comp.thread_pool.spawnWgId(&comp.link_task_wait_group, flushTaskQueue, .{ q, comp });
144}
145
114/// Called by codegen workers after they have populated a `ZcuTask.LinkFunc.SharedMir`. If the link146/// Called by codegen workers after they have populated a `ZcuTask.LinkFunc.SharedMir`. If the link
115/// thread was waiting for this MIR, it can resume.147/// thread was waiting for this MIR, it can resume.
116pub fn mirReady(q: *Queue, comp: *Compilation, func_index: InternPool.Index, mir: *ZcuTask.LinkFunc.SharedMir) void {148pub fn mirReady(q: *Queue, comp: *Compilation, func_index: InternPool.Index, mir: *ZcuTask.LinkFunc.SharedMir) void {
...@@ -130,14 +162,14 @@ pub fn mirReady(q: *Queue, comp: *Compilation, func_index: InternPool.Index, mir...@@ -130,14 +162,14 @@ pub fn mirReady(q: *Queue, comp: *Compilation, func_index: InternPool.Index, mir
130 comp.thread_pool.spawnWgId(&comp.link_task_wait_group, flushTaskQueue, .{ q, comp });162 comp.thread_pool.spawnWgId(&comp.link_task_wait_group, flushTaskQueue, .{ q, comp });
131}163}
132164
133/// Enqueues all prelink tasks in `tasks`. Asserts that they were expected, i.e. that `tasks.len` is165/// Enqueues all prelink tasks in `tasks`. Asserts that they were expected, i.e. that
134/// less than or equal to `q.pending_prelink_tasks`. Also asserts that `tasks.len` is not 0.166/// `prelink_wait_count` is not yet 0. Also asserts that `tasks.len` is not 0.
135pub fn enqueuePrelink(q: *Queue, comp: *Compilation, tasks: []const PrelinkTask) Allocator.Error!void {167pub fn enqueuePrelink(q: *Queue, comp: *Compilation, tasks: []const PrelinkTask) Allocator.Error!void {
136 {168 {
137 q.mutex.lock();169 q.mutex.lock();
138 defer q.mutex.unlock();170 defer q.mutex.unlock();
171 assert(q.prelink_wait_count > 0);
139 try q.queued_prelink.appendSlice(comp.gpa, tasks);172 try q.queued_prelink.appendSlice(comp.gpa, tasks);
140 q.pending_prelink_tasks -= @intCast(tasks.len);
141 switch (q.state) {173 switch (q.state) {
142 .wait_for_mir => unreachable, // we've not started zcu tasks yet174 .wait_for_mir => unreachable, // we've not started zcu tasks yet
143 .running => return,175 .running => return,
...@@ -167,7 +199,7 @@ pub fn enqueueZcu(q: *Queue, comp: *Compilation, task: ZcuTask) Allocator.Error!...@@ -167,7 +199,7 @@ pub fn enqueueZcu(q: *Queue, comp: *Compilation, task: ZcuTask) Allocator.Error!
167 try q.queued_zcu.append(comp.gpa, task);199 try q.queued_zcu.append(comp.gpa, task);
168 switch (q.state) {200 switch (q.state) {
169 .running, .wait_for_mir => return,201 .running, .wait_for_mir => return,
170 .finished => if (q.pending_prelink_tasks != 0) return,202 .finished => if (q.prelink_wait_count > 0) return,
171 }203 }
172 // Restart the linker thread, unless it would immediately be blocked204 // Restart the linker thread, unless it would immediately be blocked
173 if (task == .link_func and task.link_func.mir.status.load(.acquire) == .pending) {205 if (task == .link_func and task.link_func.mir.status.load(.acquire) == .pending) {
...@@ -194,7 +226,7 @@ fn flushTaskQueue(tid: usize, q: *Queue, comp: *Compilation) void {...@@ -194,7 +226,7 @@ fn flushTaskQueue(tid: usize, q: *Queue, comp: *Compilation) void {
194 defer q.mutex.unlock();226 defer q.mutex.unlock();
195 std.mem.swap(std.ArrayListUnmanaged(PrelinkTask), &q.queued_prelink, &q.wip_prelink);227 std.mem.swap(std.ArrayListUnmanaged(PrelinkTask), &q.queued_prelink, &q.wip_prelink);
196 if (q.wip_prelink.items.len == 0) {228 if (q.wip_prelink.items.len == 0) {
197 if (q.pending_prelink_tasks == 0) {229 if (q.prelink_wait_count == 0) {
198 break :prelink; // prelink is done230 break :prelink; // prelink is done
199 } else {231 } else {
200 // We're expecting more prelink tasks so can't move on to ZCU tasks.232 // We're expecting more prelink tasks so can't move on to ZCU tasks.