authorgravatar for mail@isaacfreund.comIsaac Freund <mail@isaacfreund.com> 2020-12-17 19:32:40+01:00
committergravatar for mail@isaacfreund.comIsaac Freund <mail@isaacfreund.com> 2020-12-17 19:32:40+01:00
logc102eb83e6ab4c3a6cbcecf87964150c0b3df463
tree15eef1193ace606d4a4b2178ccbf2d4c19c9eb78
parent8591f30b0d53a597682bebdfcd570f5f44339b26
signature Commit is signed but in an unrecognized format.

stage2: free Package resources

Without this commit we leak file descriptors and memory

2 files changed, 60 insertions(+), 58 deletions(-)

src/Package.zig+34-22
......@@ -1,3 +1,12 @@
1const Package = @This();
2
3const std = @import("std");
4const fs = std.fs;
5const mem = std.mem;
6const Allocator = mem.Allocator;
7
8const Compilation = @import("Compilation.zig");
9
110pub const Table = std.StringHashMapUnmanaged(*Package);
211
312root_src_directory: Compilation.Directory,
......@@ -6,57 +15,60 @@ root_src_path: []const u8,
615table: Table = .{},
716parent: ?*Package = null,
817
9const std = @import("std");
10const mem = std.mem;
11const Allocator = std.mem.Allocator;
12const assert = std.debug.assert;
13const Package = @This();
14const Compilation = @import("Compilation.zig");
15
16/// No references to `root_src_dir` and `root_src_path` are kept.
18/// Allocate a Package. No references to the slices passed are kept.
1719pub fn create(
1820 gpa: *Allocator,
19 base_directory: Compilation.Directory,
20 /// Relative to `base_directory`.
21 root_src_dir: []const u8,
22 /// Relative to `root_src_dir`.
21 /// Null indicates the current working directory
22 root_src_dir_path: ?[]const u8,
23 /// Relative to root_src_dir_path
2324 root_src_path: []const u8,
2425) !*Package {
2526 const ptr = try gpa.create(Package);
2627 errdefer gpa.destroy(ptr);
2728
28 const root_src_dir_path = try base_directory.join(gpa, &[_][]const u8{root_src_dir});
29 errdefer gpa.free(root_src_dir_path);
29 const owned_dir_path = if (root_src_dir_path) |p| try gpa.dupe(u8, p) else null;
30 errdefer if (owned_dir_path) |p| gpa.free(p);
3031
31 const root_src_path_dupe = try mem.dupe(gpa, u8, root_src_path);
32 errdefer gpa.free(root_src_path_dupe);
32 const owned_src_path = try gpa.dupe(u8, root_src_path);
33 errdefer gpa.free(owned_src_path);
3334
3435 ptr.* = .{
3536 .root_src_directory = .{
36 .path = root_src_dir_path,
37 .handle = try base_directory.handle.openDir(root_src_dir, .{}),
37 .path = owned_dir_path,
38 .handle = if (owned_dir_path) |p| try fs.cwd().openDir(p, .{}) else fs.cwd(),
3839 },
39 .root_src_path = root_src_path_dupe,
40 .root_src_path = owned_src_path,
4041 };
42
4143 return ptr;
4244}
4345
46/// Free all memory associated with this package and recursively call destroy
47/// on all packages in its table
4448pub fn destroy(pkg: *Package, gpa: *Allocator) void {
45 pkg.root_src_directory.handle.close();
4649 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
4858 {
4959 var it = pkg.table.iterator();
5060 while (it.next()) |kv| {
61 kv.value.destroy(gpa);
5162 gpa.free(kv.key);
5263 }
5364 }
65
5466 pkg.table.deinit(gpa);
5567 gpa.destroy(pkg);
5668}
5769
5870pub 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);
6072 const name_dupe = try mem.dupe(gpa, u8, name);
6173 pkg.table.putAssumeCapacityNoClobber(name_dupe, package);
6274}
src/main.zig+26-36
......@@ -560,12 +560,15 @@ fn buildOutputType(
560560 var test_exec_args = std.ArrayList(?[]const u8).init(gpa);
561561 defer test_exec_args.deinit();
562562
563 var root_pkg_memory: Package = .{
564 .root_src_directory = undefined,
565 .root_src_path = undefined,
563 const pkg_tree_root = try gpa.create(Package);
564 // This package only exists to clean up the code parsing --pkg-begin and
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{},
566569 };
567 defer root_pkg_memory.table.deinit(gpa);
568 var cur_pkg: *Package = &root_pkg_memory;
570 defer pkg_tree_root.destroy(gpa);
571 var cur_pkg: *Package = pkg_tree_root;
569572
570573 switch (arg_mode) {
571574 .build, .translate_c, .zig_test, .run => {
......@@ -619,22 +622,13 @@ fn buildOutputType(
619622 i += 1;
620623 const pkg_path = args[i];
621624
622 const new_cur_pkg = try arena.create(Package);
623 new_cur_pkg.* = .{
624 .root_src_directory = if (fs.path.dirname(pkg_path)) |dirname|
625 .{
626 .path = dirname,
627 .handle = try fs.cwd().openDir(dirname, .{}), // TODO close this fd
628 }
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);
625 const new_cur_pkg = try Package.create(
626 gpa,
627 fs.path.dirname(pkg_path),
628 fs.path.basename(pkg_path),
629 );
630 new_cur_pkg.parent = cur_pkg;
631 try cur_pkg.add(gpa, pkg_name, new_cur_pkg);
638632 cur_pkg = new_cur_pkg;
639633 } else if (mem.eql(u8, arg, "--pkg-end")) {
640634 cur_pkg = cur_pkg.parent orelse
......@@ -1583,26 +1577,22 @@ fn buildOutputType(
15831577 .yes => |p| p,
15841578 };
15851579
1586 var cleanup_root_dir: ?fs.Dir = null;
1587 defer if (cleanup_root_dir) |*dir| dir.close();
1588
15891580 const root_pkg: ?*Package = if (root_src_file) |src_path| blk: {
15901581 if (main_pkg_path) |p| {
1591 const dir = try fs.cwd().openDir(p, .{});
1592 cleanup_root_dir = dir;
1593 root_pkg_memory.root_src_directory = .{ .path = p, .handle = dir };
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);
1582 const rel_src_path = try fs.path.relative(gpa, p, src_path);
1583 defer gpa.free(rel_src_path);
1584 break :blk try Package.create(gpa, p, rel_src_path);
16001585 } else {
1601 root_pkg_memory.root_src_directory = .{ .path = null, .handle = fs.cwd() };
1602 root_pkg_memory.root_src_path = src_path;
1586 break :blk try Package.create(gpa, fs.path.dirname(src_path), fs.path.basename(src_path));
16031587 }
1604 break :blk &root_pkg_memory;
16051588 } 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 }
16061596
16071597 const self_exe_path = try fs.selfExePathAlloc(arena);
16081598 var zig_lib_directory: Compilation.Directory = if (override_lib_dir) |lib_dir|