Commit e1811f72eb
lib/std/fs/file.zig
@@ -459,6 +459,7 @@ pub const File = struct {
return index;
}
+ /// See https://github.com/ziglang/zig/issues/7699
pub fn readv(self: File, iovecs: []const os.iovec) ReadError!usize {
if (is_windows) {
// TODO improve this to use ReadFileScatter
@@ -479,6 +480,7 @@ pub const File = struct {
/// is not an error condition.
/// The `iovecs` parameter is mutable because this function needs to mutate the fields in
/// order to handle partial reads from the underlying OS layer.
+ /// See https://github.com/ziglang/zig/issues/7699
pub fn readvAll(self: File, iovecs: []os.iovec) ReadError!usize {
if (iovecs.len == 0) return;
@@ -500,6 +502,7 @@ pub const File = struct {
}
}
+ /// See https://github.com/ziglang/zig/issues/7699
pub fn preadv(self: File, iovecs: []const os.iovec, offset: u64) PReadError!usize {
if (is_windows) {
// TODO improve this to use ReadFileScatter
@@ -520,6 +523,7 @@ pub const File = struct {
/// is not an error condition.
/// The `iovecs` parameter is mutable because this function needs to mutate the fields in
/// order to handle partial reads from the underlying OS layer.
+ /// See https://github.com/ziglang/zig/issues/7699
pub fn preadvAll(self: File, iovecs: []const os.iovec, offset: u64) PReadError!void {
if (iovecs.len == 0) return;
@@ -582,6 +586,7 @@ pub const File = struct {
}
}
+ /// See https://github.com/ziglang/zig/issues/7699
pub fn writev(self: File, iovecs: []const os.iovec_const) WriteError!usize {
if (is_windows) {
// TODO improve this to use WriteFileScatter
@@ -599,6 +604,7 @@ pub const File = struct {
/// The `iovecs` parameter is mutable because this function needs to mutate the fields in
/// order to handle partial writes from the underlying OS layer.
+ /// See https://github.com/ziglang/zig/issues/7699
pub fn writevAll(self: File, iovecs: []os.iovec_const) WriteError!void {
if (iovecs.len == 0) return;
@@ -615,6 +621,7 @@ pub const File = struct {
}
}
+ /// See https://github.com/ziglang/zig/issues/7699
pub fn pwritev(self: File, iovecs: []os.iovec_const, offset: u64) PWriteError!usize {
if (is_windows) {
// TODO improve this to use WriteFileScatter
@@ -632,6 +639,7 @@ pub const File = struct {
/// The `iovecs` parameter is mutable because this function needs to mutate the fields in
/// order to handle partial writes from the underlying OS layer.
+ /// See https://github.com/ziglang/zig/issues/7699
pub fn pwritevAll(self: File, iovecs: []os.iovec_const, offset: u64) PWriteError!void {
if (iovecs.len == 0) return;
src/link/C.zig
@@ -41,13 +41,12 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio
if (options.use_lld) return error.LLDHasNoCBackend;
const file = try options.emit.?.directory.handle.createFile(sub_path, .{
- .truncate = true,
+ // Truncation is done on `flush`.
+ .truncate = false,
.mode = link.determineMode(options),
});
errdefer file.close();
- try file.writeAll(zig_h);
-
var c_file = try allocator.create(C);
errdefer allocator.destroy(c_file);
@@ -133,40 +132,61 @@ pub fn flushModule(self: *C, comp: *Compilation) !void {
const tracy = trace(@src());
defer tracy.end();
- const file = self.base.file.?;
+ const module = self.base.options.module orelse
+ return error.LinkingWithoutZigSourceUnimplemented;
- // The header is written upon opening; here we truncate and seek to after the header.
- // TODO: use writev
- try file.seekTo(zig_h.len);
- try file.setEndPos(zig_h.len);
+ // We collect a list of buffers to write, and write them all at once with pwritev ๐
+ var all_buffers = std.ArrayList(std.os.iovec_const).init(comp.gpa);
+ defer all_buffers.deinit();
- var buffered_writer = std.io.bufferedWriter(file.writer());
- const writer = buffered_writer.writer();
+ // This is at least enough until we get to the function bodies without error handling.
+ try all_buffers.ensureCapacity(module.decl_table.count() + 1);
+
+ var file_size: u64 = zig_h.len;
+ all_buffers.appendAssumeCapacity(.{
+ .iov_base = zig_h,
+ .iov_len = zig_h.len,
+ });
- const module = self.base.options.module orelse return error.LinkingWithoutZigSourceUnimplemented;
+ var fn_count: usize = 0;
// Forward decls and non-functions first.
- // TODO: use writev
for (module.decl_table.items()) |kv| {
const decl = kv.value;
const decl_tv = decl.typed_value.most_recent.typed_value;
- if (decl_tv.val.castTag(.function)) |_| {
- try writer.writeAll(decl.fn_link.c.fwd_decl.items);
- } else {
- try writer.writeAll(decl.link.c.code.items);
- }
+ const buf = buf: {
+ if (decl_tv.val.castTag(.function)) |_| {
+ fn_count += 1;
+ break :buf decl.fn_link.c.fwd_decl.items;
+ } else {
+ break :buf decl.link.c.code.items;
+ }
+ };
+ all_buffers.appendAssumeCapacity(.{
+ .iov_base = buf.ptr,
+ .iov_len = buf.len,
+ });
+ file_size += buf.len;
}
// Now the function bodies.
+ try all_buffers.ensureCapacity(all_buffers.items.len + fn_count);
for (module.decl_table.items()) |kv| {
const decl = kv.value;
const decl_tv = decl.typed_value.most_recent.typed_value;
if (decl_tv.val.castTag(.function)) |_| {
- try writer.writeAll(decl.link.c.code.items);
+ const buf = decl.link.c.code.items;
+ all_buffers.appendAssumeCapacity(.{
+ .iov_base = buf.ptr,
+ .iov_len = buf.len,
+ });
+ file_size += buf.len;
}
}
- try buffered_writer.flush();
+ const file = self.base.file.?;
+ try file.setEndPos(file_size);
+ try file.pwritevAll(all_buffers.items, 0);
}
pub fn updateDeclExports(