| 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,13 +70,24 @@ libc_static_lib: ?[]const u8 = null, |
| 70 | /// For example `Scrt1.o` and `libc.so.6`. These are populated after building libc from source, | 70 | /// For example `Scrt1.o` and `libc.so.6`. These are populated after building libc from source, |
| 71 | /// The set of needed CRT (C runtime) files differs depending on the target and compilation settings. | 71 | /// The set of needed CRT (C runtime) files differs depending on the target and compilation settings. |
| 72 | /// The key is the basename, and the value is the absolute path to the completed build artifact. | 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 | /// Keeping track of this possibly open resource so we can close it later. | 75 | /// Keeping track of this possibly open resource so we can close it later. |
| 76 | owned_link_dir: ?std.fs.Dir, | 76 | owned_link_dir: ?std.fs.Dir, |
| 77 | 77 | ||
| 78 | pub const InnerError = Module.InnerError; | 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 | /// For passing to a C compiler. | 91 | /// For passing to a C compiler. |
| 81 | pub const CSourceFile = struct { | 92 | pub const CSourceFile = struct { |
| 82 | src_path: []const u8, | 93 | src_path: []const u8, |
| ... | @@ -625,7 +636,7 @@ pub fn destroy(self: *Compilation) void { | ... | @@ -625,7 +636,7 @@ pub fn destroy(self: *Compilation) void { |
| 625 | var it = self.crt_files.iterator(); | 636 | var it = self.crt_files.iterator(); |
| 626 | while (it.next()) |entry| { | 637 | while (it.next()) |entry| { |
| 627 | gpa.free(entry.key); | 638 | gpa.free(entry.key); |
| 628 | gpa.free(entry.value); | 639 | entry.value.deinit(gpa); |
| 629 | } | 640 | } |
| 630 | self.crt_files.deinit(gpa); | 641 | self.crt_files.deinit(gpa); |
| 631 | } | 642 | } |
| ... | @@ -1512,7 +1523,7 @@ fn detectLibCFromLibCInstallation(arena: *Allocator, target: Target, lci: *const | ... | @@ -1512,7 +1523,7 @@ fn detectLibCFromLibCInstallation(arena: *Allocator, target: Target, lci: *const |
| 1512 | 1523 | ||
| 1513 | pub fn get_libc_crt_file(comp: *Compilation, arena: *Allocator, basename: []const u8) ![]const u8 { | 1524 | pub fn get_libc_crt_file(comp: *Compilation, arena: *Allocator, basename: []const u8) ![]const u8 { |
| 1514 | if (comp.wantBuildGLibCFromSource()) { | 1525 | if (comp.wantBuildGLibCFromSource()) { |
| 1515 | return comp.crt_files.get(basename).?; | 1526 | return comp.crt_files.get(basename).?.full_object_path; |
| 1516 | } | 1527 | } |
| 1517 | const lci = comp.bin_file.options.libc_installation orelse return error.LibCInstallationNotAvailable; | 1528 | const lci = comp.bin_file.options.libc_installation orelse return error.LibCInstallationNotAvailable; |
| 1518 | const crt_dir_path = lci.crt_dir orelse return error.LibCInstallationMissingCRTDir; | 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,5 +648,8 @@ fn build_libc_object(comp: *Compilation, basename: []const u8, c_source_file: Co |
| 648 | try comp.gpa.dupe(u8, basename); | 648 | try comp.gpa.dupe(u8, basename); |
| 649 | 649 | ||
| 650 | // TODO obtain a lock on the artifact and put that in crt_files as well. | 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,6 +90,10 @@ pub const File = struct { |
| 90 | /// this location, and then this path can be placed on the LLD linker line. | 90 | /// this location, and then this path can be placed on the LLD linker line. |
| 91 | intermediary_basename: ?[]const u8 = null, | 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 | pub const LinkBlock = union { | 97 | pub const LinkBlock = union { |
| 94 | elf: Elf.TextBlock, | 98 | elf: Elf.TextBlock, |
| 95 | coff: Coff.TextBlock, | 99 | coff: Coff.TextBlock, |
| ... | @@ -228,7 +232,21 @@ pub const File = struct { | ... | @@ -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 | pub fn destroy(base: *File) void { | 248 | pub fn destroy(base: *File) void { |
| 249 | base.releaseLock(); | ||
| 232 | if (base.file) |f| f.close(); | 250 | if (base.file) |f| f.close(); |
| 233 | if (base.intermediary_basename) |sub_path| base.allocator.free(sub_path); | 251 | if (base.intermediary_basename) |sub_path| base.allocator.free(sub_path); |
| 234 | switch (base.tag) { | 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,9 +123,6 @@ dbg_info_decl_free_list: std.AutoHashMapUnmanaged(*TextBlock, void) = .{}, |
| 123 | dbg_info_decl_first: ?*TextBlock = null, | 123 | dbg_info_decl_first: ?*TextBlock = null, |
| 124 | dbg_info_decl_last: ?*TextBlock = null, | 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 | /// `alloc_num / alloc_den` is the factor of padding when allocating. | 126 | /// `alloc_num / alloc_den` is the factor of padding when allocating. |
| 130 | const alloc_num = 4; | 127 | const alloc_num = 4; |
| 131 | const alloc_den = 3; | 128 | const alloc_den = 3; |
| ... | @@ -290,21 +287,7 @@ pub fn createEmpty(gpa: *Allocator, options: link.Options) !*Elf { | ... | @@ -290,21 +287,7 @@ pub fn createEmpty(gpa: *Allocator, options: link.Options) !*Elf { |
| 290 | return self; | 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 | pub fn deinit(self: *Elf) void { | 290 | pub fn deinit(self: *Elf) void { |
| 307 | self.releaseLock(); | ||
| 308 | self.sections.deinit(self.base.allocator); | 291 | self.sections.deinit(self.base.allocator); |
| 309 | self.program_headers.deinit(self.base.allocator); | 292 | self.program_headers.deinit(self.base.allocator); |
| 310 | self.shstrtab.deinit(self.base.allocator); | 293 | self.shstrtab.deinit(self.base.allocator); |
| ... | @@ -1253,7 +1236,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void { | ... | @@ -1253,7 +1236,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void { |
| 1253 | const id_symlink_basename = "id.txt"; | 1236 | const id_symlink_basename = "id.txt"; |
| 1254 | 1237 | ||
| 1255 | // We are about to obtain this lock, so here we give other processes a chance first. | 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 | var ch = comp.cache_parent.obtain(); | 1241 | var ch = comp.cache_parent.obtain(); |
| 1259 | defer ch.deinit(); | 1242 | defer ch.deinit(); |
| ... | @@ -1302,14 +1285,16 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void { | ... | @@ -1302,14 +1285,16 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void { |
| 1302 | const digest = ch.final(); | 1285 | const digest = ch.final(); |
| 1303 | 1286 | ||
| 1304 | var prev_digest_buf: [digest.len]u8 = undefined; | 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 | // Handle this as a cache miss. | 1290 | // Handle this as a cache miss. |
| 1307 | mem.set(u8, &prev_digest_buf, 0); | 1291 | mem.set(u8, &prev_digest_buf, 0); |
| 1308 | break :blk &prev_digest_buf; | 1292 | break :blk &prev_digest_buf; |
| 1309 | }; | 1293 | }; |
| 1294 | log.debug("ELF LLD prev_digest={} new_digest={}", .{prev_digest, digest}); | ||
| 1310 | if (mem.eql(u8, prev_digest, &digest)) { | 1295 | if (mem.eql(u8, prev_digest, &digest)) { |
| 1311 | // Hot diggity dog! The output binary is already there. | 1296 | // Hot diggity dog! The output binary is already there. |
| 1312 | self.lock = ch.toOwnedLock(); | 1297 | self.base.lock = ch.toOwnedLock(); |
| 1313 | return; | 1298 | return; |
| 1314 | } | 1299 | } |
| 1315 | 1300 | ||
| ... | @@ -1611,7 +1596,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void { | ... | @@ -1611,7 +1596,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void { |
| 1611 | }; | 1596 | }; |
| 1612 | // We hang on to this lock so that the output file path can be used without | 1597 | // We hang on to this lock so that the output file path can be used without |
| 1613 | // other processes clobbering it. | 1598 | // other processes clobbering it. |
| 1614 | self.lock = ch.toOwnedLock(); | 1599 | self.base.lock = ch.toOwnedLock(); |
| 1615 | } | 1600 | } |
| 1616 | 1601 | ||
| 1617 | fn append_diagnostic(context: usize, ptr: [*]const u8, len: usize) callconv(.C) void { | 1602 | fn append_diagnostic(context: usize, ptr: [*]const u8, len: usize) callconv(.C) void { |