| author | |
| committer | |
| log | e5aef96293336fa25e6f094bf82d189176e8d1a7 |
| tree | 197612b613650d003c226b7e772cd470d5953f8e |
| parent | 97ea5da18d0a26d55447082d37f6a0945da42d1f |
4 files changed, 42 insertions(+), 25 deletions(-)
src-self-hosted/Compilation.zig+14-3| ... | ... | @@ -70,13 +70,24 @@ libc_static_lib: ?[]const u8 = null, |
| 70 | 70 | /// For example `Scrt1.o` and `libc.so.6`. These are populated after building libc from source, |
| 71 | 71 | /// The set of needed CRT (C runtime) files differs depending on the target and compilation settings. |
| 72 | 72 | /// The key is the basename, and the value is the absolute path to the completed build artifact. |
| 73 | crt_files: std.StringHashMapUnmanaged([]const u8) = .{}, | |
| 73 | crt_files: std.StringHashMapUnmanaged(CRTFile) = .{}, | |
| 74 | 74 | |
| 75 | 75 | /// Keeping track of this possibly open resource so we can close it later. |
| 76 | 76 | owned_link_dir: ?std.fs.Dir, |
| 77 | 77 | |
| 78 | 78 | pub const InnerError = Module.InnerError; |
| 79 | 79 | |
| 80 | pub const CRTFile = struct { | |
| 81 | lock: std.cache_hash.Lock, | |
| 82 | full_object_path: []const u8, | |
| 83 | ||
| 84 | fn deinit(self: *CRTFile, gpa: *Allocator) void { | |
| 85 | self.lock.release(); | |
| 86 | gpa.free(self.full_object_path); | |
| 87 | self.* = undefined; | |
| 88 | } | |
| 89 | }; | |
| 90 | ||
| 80 | 91 | /// For passing to a C compiler. |
| 81 | 92 | pub const CSourceFile = struct { |
| 82 | 93 | src_path: []const u8, |
| ... | ... | @@ -625,7 +636,7 @@ pub fn destroy(self: *Compilation) void { |
| 625 | 636 | var it = self.crt_files.iterator(); |
| 626 | 637 | while (it.next()) |entry| { |
| 627 | 638 | gpa.free(entry.key); |
| 628 | gpa.free(entry.value); | |
| 639 | entry.value.deinit(gpa); | |
| 629 | 640 | } |
| 630 | 641 | self.crt_files.deinit(gpa); |
| 631 | 642 | } |
| ... | ... | @@ -1512,7 +1523,7 @@ fn detectLibCFromLibCInstallation(arena: *Allocator, target: Target, lci: *const |
| 1512 | 1523 | |
| 1513 | 1524 | pub fn get_libc_crt_file(comp: *Compilation, arena: *Allocator, basename: []const u8) ![]const u8 { |
| 1514 | 1525 | if (comp.wantBuildGLibCFromSource()) { |
| 1515 | return comp.crt_files.get(basename).?; | |
| 1526 | return comp.crt_files.get(basename).?.full_object_path; | |
| 1516 | 1527 | } |
| 1517 | 1528 | const lci = comp.bin_file.options.libc_installation orelse return error.LibCInstallationNotAvailable; |
| 1518 | 1529 | const crt_dir_path = lci.crt_dir orelse return error.LibCInstallationMissingCRTDir; |
src-self-hosted/glibc.zig+4-1| ... | ... | @@ -648,5 +648,8 @@ fn build_libc_object(comp: *Compilation, basename: []const u8, c_source_file: Co |
| 648 | 648 | try comp.gpa.dupe(u8, basename); |
| 649 | 649 | |
| 650 | 650 | // TODO obtain a lock on the artifact and put that in crt_files as well. |
| 651 | comp.crt_files.putAssumeCapacityNoClobber(basename, artifact_path); | |
| 651 | comp.crt_files.putAssumeCapacityNoClobber(basename, .{ | |
| 652 | .full_object_path = artifact_path, | |
| 653 | .lock = sub_compilation.bin_file.toOwnedLock(), | |
| 654 | }); | |
| 652 | 655 | } |
src-self-hosted/link.zig+18| ... | ... | @@ -90,6 +90,10 @@ pub const File = struct { |
| 90 | 90 | /// this location, and then this path can be placed on the LLD linker line. |
| 91 | 91 | intermediary_basename: ?[]const u8 = null, |
| 92 | 92 | |
| 93 | /// Prevents other processes from clobbering files in the output directory | |
| 94 | /// of this linking operation. | |
| 95 | lock: ?std.cache_hash.Lock = null, | |
| 96 | ||
| 93 | 97 | pub const LinkBlock = union { |
| 94 | 98 | elf: Elf.TextBlock, |
| 95 | 99 | coff: Coff.TextBlock, |
| ... | ... | @@ -228,7 +232,21 @@ pub const File = struct { |
| 228 | 232 | } |
| 229 | 233 | } |
| 230 | 234 | |
| 235 | pub fn releaseLock(self: *File) void { | |
| 236 | if (self.lock) |*lock| { | |
| 237 | lock.release(); | |
| 238 | self.lock = null; | |
| 239 | } | |
| 240 | } | |
| 241 | ||
| 242 | pub fn toOwnedLock(self: *File) std.cache_hash.Lock { | |
| 243 | const lock = self.lock.?; | |
| 244 | self.lock = null; | |
| 245 | return lock; | |
| 246 | } | |
| 247 | ||
| 231 | 248 | pub fn destroy(base: *File) void { |
| 249 | base.releaseLock(); | |
| 232 | 250 | if (base.file) |f| f.close(); |
| 233 | 251 | if (base.intermediary_basename) |sub_path| base.allocator.free(sub_path); |
| 234 | 252 | switch (base.tag) { |
src-self-hosted/link/Elf.zig+6-21| ... | ... | @@ -123,9 +123,6 @@ dbg_info_decl_free_list: std.AutoHashMapUnmanaged(*TextBlock, void) = .{}, |
| 123 | 123 | dbg_info_decl_first: ?*TextBlock = null, |
| 124 | 124 | dbg_info_decl_last: ?*TextBlock = null, |
| 125 | 125 | |
| 126 | /// Prevents other processes from clobbering the output file this is linking. | |
| 127 | lock: ?std.cache_hash.Lock = null, | |
| 128 | ||
| 129 | 126 | /// `alloc_num / alloc_den` is the factor of padding when allocating. |
| 130 | 127 | const alloc_num = 4; |
| 131 | 128 | const alloc_den = 3; |
| ... | ... | @@ -290,21 +287,7 @@ pub fn createEmpty(gpa: *Allocator, options: link.Options) !*Elf { |
| 290 | 287 | return self; |
| 291 | 288 | } |
| 292 | 289 | |
| 293 | pub fn releaseLock(self: *Elf) void { | |
| 294 | if (self.lock) |*lock| { | |
| 295 | lock.release(); | |
| 296 | self.lock = null; | |
| 297 | } | |
| 298 | } | |
| 299 | ||
| 300 | pub fn toOwnedLock(self: *Elf) std.cache_hash.Lock { | |
| 301 | const lock = self.lock.?; | |
| 302 | self.lock = null; | |
| 303 | return lock; | |
| 304 | } | |
| 305 | ||
| 306 | 290 | pub fn deinit(self: *Elf) void { |
| 307 | self.releaseLock(); | |
| 308 | 291 | self.sections.deinit(self.base.allocator); |
| 309 | 292 | self.program_headers.deinit(self.base.allocator); |
| 310 | 293 | self.shstrtab.deinit(self.base.allocator); |
| ... | ... | @@ -1253,7 +1236,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void { |
| 1253 | 1236 | const id_symlink_basename = "id.txt"; |
| 1254 | 1237 | |
| 1255 | 1238 | // We are about to obtain this lock, so here we give other processes a chance first. |
| 1256 | self.releaseLock(); | |
| 1239 | self.base.releaseLock(); | |
| 1257 | 1240 | |
| 1258 | 1241 | var ch = comp.cache_parent.obtain(); |
| 1259 | 1242 | defer ch.deinit(); |
| ... | ... | @@ -1302,14 +1285,16 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void { |
| 1302 | 1285 | const digest = ch.final(); |
| 1303 | 1286 | |
| 1304 | 1287 | var prev_digest_buf: [digest.len]u8 = undefined; |
| 1305 | const prev_digest: []u8 = directory.handle.readLink(id_symlink_basename, &prev_digest_buf) catch blk: { | |
| 1288 | const prev_digest: []u8 = directory.handle.readLink(id_symlink_basename, &prev_digest_buf) catch |err| blk: { | |
| 1289 | log.debug("ELF LLD new_digest={} readlink error: {}", .{digest, @errorName(err)}); | |
| 1306 | 1290 | // Handle this as a cache miss. |
| 1307 | 1291 | mem.set(u8, &prev_digest_buf, 0); |
| 1308 | 1292 | break :blk &prev_digest_buf; |
| 1309 | 1293 | }; |
| 1294 | log.debug("ELF LLD prev_digest={} new_digest={}", .{prev_digest, digest}); | |
| 1310 | 1295 | if (mem.eql(u8, prev_digest, &digest)) { |
| 1311 | 1296 | // Hot diggity dog! The output binary is already there. |
| 1312 | self.lock = ch.toOwnedLock(); | |
| 1297 | self.base.lock = ch.toOwnedLock(); | |
| 1313 | 1298 | return; |
| 1314 | 1299 | } |
| 1315 | 1300 | |
| ... | ... | @@ -1611,7 +1596,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void { |
| 1611 | 1596 | }; |
| 1612 | 1597 | // We hang on to this lock so that the output file path can be used without |
| 1613 | 1598 | // other processes clobbering it. |
| 1614 | self.lock = ch.toOwnedLock(); | |
| 1599 | self.base.lock = ch.toOwnedLock(); | |
| 1615 | 1600 | } |
| 1616 | 1601 | |
| 1617 | 1602 | fn append_diagnostic(context: usize, ptr: [*]const u8, len: usize) callconv(.C) void { |