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
signaturelock-open 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 @@...@@ -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
1pub const Table = std.StringHashMapUnmanaged(*Package);10pub const Table = std.StringHashMapUnmanaged(*Package);
211
3root_src_directory: Compilation.Directory,12root_src_directory: Compilation.Directory,
...@@ -6,57 +15,60 @@ root_src_path: []const u8,...@@ -6,57 +15,60 @@ root_src_path: []const u8,
6table: Table = .{},15table: Table = .{},
7parent: ?*Package = null,16parent: ?*Package = null,
817
9const std = @import("std");18/// Allocate a Package. No references to the slices passed are kept.
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.
17pub fn create(19pub 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);
2728
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);
3031
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);
3334
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}
4345
46/// Free all memory associated with this package and recursively call destroy
47/// on all packages in its table
44pub fn destroy(pkg: *Package, gpa: *Allocator) void {48pub 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}
5769
58pub fn add(pkg: *Package, gpa: *Allocator, name: []const u8, package: *Package) !void {70pub 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();
562562
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;
569572
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];
621624
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 fd630 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 orelse634 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 };
15851579
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 }
16061596
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|