| author | |
| committer | |
| log | c102eb83e6ab4c3a6cbcecf87964150c0b3df463 |
| tree | 15eef1193ace606d4a4b2178ccbf2d4c19c9eb78 |
| parent | 8591f30b0d53a597682bebdfcd570f5f44339b26 |
| signature |
Without this commit we leak file descriptors and memory2 files changed, 60 insertions(+), 58 deletions(-)
src/Package.zig+34-22| ... | @@ -1,3 +1,12 @@ | ... | @@ -1,3 +1,12 @@ |
| 1 | const Package = @This(); | ||
| 2 | |||
| 3 | const std = @import("std"); | ||
| 4 | const fs = std.fs; | ||
| 5 | const mem = std.mem; | ||
| 6 | const Allocator = mem.Allocator; | ||
| 7 | |||
| 8 | const Compilation = @import("Compilation.zig"); | ||
| 9 | |||
| 1 | pub const Table = std.StringHashMapUnmanaged(*Package); | 10 | pub const Table = std.StringHashMapUnmanaged(*Package); |
| 2 | 11 | ||
| 3 | root_src_directory: Compilation.Directory, | 12 | root_src_directory: Compilation.Directory, |
| ... | @@ -6,57 +15,60 @@ root_src_path: []const u8, | ... | @@ -6,57 +15,60 @@ root_src_path: []const u8, |
| 6 | table: Table = .{}, | 15 | table: Table = .{}, |
| 7 | parent: ?*Package = null, | 16 | parent: ?*Package = null, |
| 8 | 17 | ||
| 9 | const std = @import("std"); | 18 | /// Allocate a Package. No references to the slices passed are kept. |
| 10 | const mem = std.mem; | ||
| 11 | const Allocator = std.mem.Allocator; | ||
| 12 | const assert = std.debug.assert; | ||
| 13 | const Package = @This(); | ||
| 14 | const Compilation = @import("Compilation.zig"); | ||
| 15 | |||
| 16 | /// No references to `root_src_dir` and `root_src_path` are kept. | ||
| 17 | pub fn create( | 19 | pub fn create( |
| 18 | gpa: *Allocator, | 20 | gpa: *Allocator, |
| 19 | base_directory: Compilation.Directory, | 21 | /// Null indicates the current working directory |
| 20 | /// Relative to `base_directory`. | 22 | root_src_dir_path: ?[]const u8, |
| 21 | root_src_dir: []const u8, | 23 | /// Relative to root_src_dir_path |
| 22 | /// Relative to `root_src_dir`. | ||
| 23 | root_src_path: []const u8, | 24 | root_src_path: []const u8, |
| 24 | ) !*Package { | 25 | ) !*Package { |
| 25 | const ptr = try gpa.create(Package); | 26 | const ptr = try gpa.create(Package); |
| 26 | errdefer gpa.destroy(ptr); | 27 | errdefer gpa.destroy(ptr); |
| 27 | 28 | ||
| 28 | const root_src_dir_path = try base_directory.join(gpa, &[_][]const u8{root_src_dir}); | 29 | const owned_dir_path = if (root_src_dir_path) |p| try gpa.dupe(u8, p) else null; |
| 29 | errdefer gpa.free(root_src_dir_path); | 30 | errdefer if (owned_dir_path) |p| gpa.free(p); |
| 30 | 31 | ||
| 31 | const root_src_path_dupe = try mem.dupe(gpa, u8, root_src_path); | 32 | const owned_src_path = try gpa.dupe(u8, root_src_path); |
| 32 | errdefer gpa.free(root_src_path_dupe); | 33 | errdefer gpa.free(owned_src_path); |
| 33 | 34 | ||
| 34 | ptr.* = .{ | 35 | ptr.* = .{ |
| 35 | .root_src_directory = .{ | 36 | .root_src_directory = .{ |
| 36 | .path = root_src_dir_path, | 37 | .path = owned_dir_path, |
| 37 | .handle = try base_directory.handle.openDir(root_src_dir, .{}), | 38 | .handle = if (owned_dir_path) |p| try fs.cwd().openDir(p, .{}) else fs.cwd(), |
| 38 | }, | 39 | }, |
| 39 | .root_src_path = root_src_path_dupe, | 40 | .root_src_path = owned_src_path, |
| 40 | }; | 41 | }; |
| 42 | |||
| 41 | return ptr; | 43 | return ptr; |
| 42 | } | 44 | } |
| 43 | 45 | ||
| 46 | /// Free all memory associated with this package and recursively call destroy | ||
| 47 | /// on all packages in its table | ||
| 44 | pub fn destroy(pkg: *Package, gpa: *Allocator) void { | 48 | pub fn destroy(pkg: *Package, gpa: *Allocator) void { |
| 45 | pkg.root_src_directory.handle.close(); | ||
| 46 | gpa.free(pkg.root_src_path); | 49 | gpa.free(pkg.root_src_path); |
| 47 | if (pkg.root_src_directory.path) |p| gpa.free(p); | 50 | |
| 51 | // If root_src_directory.path is null then the handle is the cwd() | ||
| 52 | // which shouldn't be closed. | ||
| 53 | if (pkg.root_src_directory.path) |p| { | ||
| 54 | gpa.free(p); | ||
| 55 | pkg.root_src_directory.handle.close(); | ||
| 56 | } | ||
| 57 | |||
| 48 | { | 58 | { |
| 49 | var it = pkg.table.iterator(); | 59 | var it = pkg.table.iterator(); |
| 50 | while (it.next()) |kv| { | 60 | while (it.next()) |kv| { |
| 61 | kv.value.destroy(gpa); | ||
| 51 | gpa.free(kv.key); | 62 | gpa.free(kv.key); |
| 52 | } | 63 | } |
| 53 | } | 64 | } |
| 65 | |||
| 54 | pkg.table.deinit(gpa); | 66 | pkg.table.deinit(gpa); |
| 55 | gpa.destroy(pkg); | 67 | gpa.destroy(pkg); |
| 56 | } | 68 | } |
| 57 | 69 | ||
| 58 | pub fn add(pkg: *Package, gpa: *Allocator, name: []const u8, package: *Package) !void { | 70 | pub fn add(pkg: *Package, gpa: *Allocator, name: []const u8, package: *Package) !void { |
| 59 | try pkg.table.ensureCapacity(gpa, pkg.table.items().len + 1); | 71 | try pkg.table.ensureCapacity(gpa, pkg.table.count() + 1); |
| 60 | const name_dupe = try mem.dupe(gpa, u8, name); | 72 | const name_dupe = try mem.dupe(gpa, u8, name); |
| 61 | pkg.table.putAssumeCapacityNoClobber(name_dupe, package); | 73 | pkg.table.putAssumeCapacityNoClobber(name_dupe, package); |
| 62 | } | 74 | } |
src/main.zig+26-36| ... | @@ -560,12 +560,15 @@ fn buildOutputType( | ... | @@ -560,12 +560,15 @@ fn buildOutputType( |
| 560 | var test_exec_args = std.ArrayList(?[]const u8).init(gpa); | 560 | var test_exec_args = std.ArrayList(?[]const u8).init(gpa); |
| 561 | defer test_exec_args.deinit(); | 561 | defer test_exec_args.deinit(); |
| 562 | 562 | ||
| 563 | var root_pkg_memory: Package = .{ | 563 | const pkg_tree_root = try gpa.create(Package); |
| 564 | .root_src_directory = undefined, | 564 | // This package only exists to clean up the code parsing --pkg-begin and |
| 565 | .root_src_path = undefined, | 565 | // --pkg-end flags. Use dummy values that are safe for the destroy call. |
| 566 | pkg_tree_root.* = .{ | ||
| 567 | .root_src_directory = .{ .path = null, .handle = fs.cwd() }, | ||
| 568 | .root_src_path = &[0]u8{}, | ||
| 566 | }; | 569 | }; |
| 567 | defer root_pkg_memory.table.deinit(gpa); | 570 | defer pkg_tree_root.destroy(gpa); |
| 568 | var cur_pkg: *Package = &root_pkg_memory; | 571 | var cur_pkg: *Package = pkg_tree_root; |
| 569 | 572 | ||
| 570 | switch (arg_mode) { | 573 | switch (arg_mode) { |
| 571 | .build, .translate_c, .zig_test, .run => { | 574 | .build, .translate_c, .zig_test, .run => { |
| ... | @@ -619,22 +622,13 @@ fn buildOutputType( | ... | @@ -619,22 +622,13 @@ fn buildOutputType( |
| 619 | i += 1; | 622 | i += 1; |
| 620 | const pkg_path = args[i]; | 623 | const pkg_path = args[i]; |
| 621 | 624 | ||
| 622 | const new_cur_pkg = try arena.create(Package); | 625 | const new_cur_pkg = try Package.create( |
| 623 | new_cur_pkg.* = .{ | 626 | gpa, |
| 624 | .root_src_directory = if (fs.path.dirname(pkg_path)) |dirname| | 627 | fs.path.dirname(pkg_path), |
| 625 | .{ | 628 | fs.path.basename(pkg_path), |
| 626 | .path = dirname, | 629 | ); |
| 627 | .handle = try fs.cwd().openDir(dirname, .{}), // TODO close this fd | 630 | new_cur_pkg.parent = cur_pkg; |
| 628 | } | 631 | try cur_pkg.add(gpa, pkg_name, new_cur_pkg); |
| 629 | else | ||
| 630 | .{ | ||
| 631 | .path = null, | ||
| 632 | .handle = fs.cwd(), | ||
| 633 | }, | ||
| 634 | .root_src_path = fs.path.basename(pkg_path), | ||
| 635 | .parent = cur_pkg, | ||
| 636 | }; | ||
| 637 | try cur_pkg.table.put(gpa, pkg_name, new_cur_pkg); | ||
| 638 | cur_pkg = new_cur_pkg; | 632 | cur_pkg = new_cur_pkg; |
| 639 | } else if (mem.eql(u8, arg, "--pkg-end")) { | 633 | } else if (mem.eql(u8, arg, "--pkg-end")) { |
| 640 | cur_pkg = cur_pkg.parent orelse | 634 | cur_pkg = cur_pkg.parent orelse |
| ... | @@ -1583,26 +1577,22 @@ fn buildOutputType( | ... | @@ -1583,26 +1577,22 @@ fn buildOutputType( |
| 1583 | .yes => |p| p, | 1577 | .yes => |p| p, |
| 1584 | }; | 1578 | }; |
| 1585 | 1579 | ||
| 1586 | var cleanup_root_dir: ?fs.Dir = null; | ||
| 1587 | defer if (cleanup_root_dir) |*dir| dir.close(); | ||
| 1588 | |||
| 1589 | const root_pkg: ?*Package = if (root_src_file) |src_path| blk: { | 1580 | const root_pkg: ?*Package = if (root_src_file) |src_path| blk: { |
| 1590 | if (main_pkg_path) |p| { | 1581 | if (main_pkg_path) |p| { |
| 1591 | const dir = try fs.cwd().openDir(p, .{}); | 1582 | const rel_src_path = try fs.path.relative(gpa, p, src_path); |
| 1592 | cleanup_root_dir = dir; | 1583 | defer gpa.free(rel_src_path); |
| 1593 | root_pkg_memory.root_src_directory = .{ .path = p, .handle = dir }; | 1584 | break :blk try Package.create(gpa, p, rel_src_path); |
| 1594 | root_pkg_memory.root_src_path = try fs.path.relative(arena, p, src_path); | ||
| 1595 | } else if (fs.path.dirname(src_path)) |p| { | ||
| 1596 | const dir = try fs.cwd().openDir(p, .{}); | ||
| 1597 | cleanup_root_dir = dir; | ||
| 1598 | root_pkg_memory.root_src_directory = .{ .path = p, .handle = dir }; | ||
| 1599 | root_pkg_memory.root_src_path = fs.path.basename(src_path); | ||
| 1600 | } else { | 1585 | } else { |
| 1601 | root_pkg_memory.root_src_directory = .{ .path = null, .handle = fs.cwd() }; | 1586 | break :blk try Package.create(gpa, fs.path.dirname(src_path), fs.path.basename(src_path)); |
| 1602 | root_pkg_memory.root_src_path = src_path; | ||
| 1603 | } | 1587 | } |
| 1604 | break :blk &root_pkg_memory; | ||
| 1605 | } else null; | 1588 | } else null; |
| 1589 | defer if (root_pkg) |p| p.destroy(gpa); | ||
| 1590 | |||
| 1591 | // Transfer packages added with --pkg-begin/--pkg-end to the root package | ||
| 1592 | if (root_pkg) |pkg| { | ||
| 1593 | pkg.table = pkg_tree_root.table; | ||
| 1594 | pkg_tree_root.table = .{}; | ||
| 1595 | } | ||
| 1606 | 1596 | ||
| 1607 | const self_exe_path = try fs.selfExePathAlloc(arena); | 1597 | const self_exe_path = try fs.selfExePathAlloc(arena); |
| 1608 | var zig_lib_directory: Compilation.Directory = if (override_lib_dir) |lib_dir| | 1598 | var zig_lib_directory: Compilation.Directory = if (override_lib_dir) |lib_dir| |