authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-12-31 16:34:14-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-12-31 16:34:14-05:00
log8186211404552a31eaf2a7bc182a46a7e40eacda
tree3e93cad370217a1a65fad5b3a91e91300f120123
parenta153a972adbe783bc8a0d08df0942a3bf0552188
signature Commit is signed but in an unrecognized format.

improvements to memfd_create

* move test from std/io/test.zig to std/os/test.zig * do glibc version check, and make direct system call if glibc is too old * disable test when not linking libc, to avoid not working with outdated qemu version on the CI server. see #4019

3 files changed, 34 insertions(+), 17 deletions(-)

lib/std/io/test.zig-14
......@@ -649,17 +649,3 @@ test "updateTimes" {
649649 std.testing.expect(stat_new.atime < stat_old.atime);
650650 std.testing.expect(stat_new.mtime < stat_old.mtime);
651651}
652
653test "memfd_create" {
654 if (builtin.os != .linux) return error.SkipZigTest;
655
656 const fd = try std.os.memfd_create("test", 0);
657 defer std.os.close(fd);
658 try std.os.write(fd, "test");
659 try std.os.lseek_SET(fd, 0);
660
661 var buf: [10]u8 = undefined;
662 const bytes_read = try std.os.read(fd, &buf);
663 expect(bytes_read == 4);
664 expect(mem.eql(u8, buf[0..4], "test"));
665}
lib/std/os.zig+13-3
......@@ -3282,9 +3282,19 @@ pub fn setsockopt(fd: fd_t, level: u32, optname: u32, opt: []const u8) SetSockOp
32823282 }
32833283}
32843284
3285pub const MemFdCreateError = error{
3286 SystemFdQuotaExceeded,
3287 ProcessFdQuotaExceeded,
3288 OutOfMemory,
3289} || UnexpectedError;
3290
32853291pub fn memfd_createC(name: [*:0]const u8, flags: u32) !fd_t {
3286 const rc = system.memfd_create(name, flags);
3287 switch (errno(rc)) {
3292 // memfd_create is available only in glibc versions starting with 2.27.
3293 const use_c = std.c.versionCheck(.{ .major = 2, .minor = 27, .patch = 0 }).ok;
3294 const sys = if (use_c) std.c else linux;
3295 const getErrno = if (use_c) std.c.getErrno else linux.getErrno;
3296 const rc = sys.memfd_create(name, flags);
3297 switch (getErrno(rc)) {
32883298 0 => return @intCast(fd_t, rc),
32893299 EFAULT => unreachable, // name has invalid memory
32903300 EINVAL => unreachable, // name/flags are faulty
......@@ -3308,5 +3318,5 @@ fn toMemFdPath(name: []const u8) ![MFD_MAX_NAME_LEN:0]u8 {
33083318
33093319pub fn memfd_create(name: []const u8, flags: u32) !fd_t {
33103320 const name_t = try toMemFdPath(name);
3311 return try memfd_createC(&name_t, flags);
3321 return memfd_createC(&name_t, flags);
33123322}
lib/std/os/test.zig+21
......@@ -237,3 +237,24 @@ test "argsAlloc" {
237237 var args = try std.process.argsAlloc(std.heap.page_allocator);
238238 std.process.argsFree(std.heap.page_allocator, args);
239239}
240
241test "memfd_create" {
242 // memfd_create is linux specific.
243 if (builtin.os != .linux) return error.SkipZigTest;
244 // Zig's CI testing infrastructure uses QEMU. Currently the version is
245 // qemu 2.11 from Ubuntu 18.04, which does not have memfd_create support.
246 // memfd_create support is introduced in qemu 4.2. To avoid
247 // "invalid syscall" errors from qemu, we disable the test when not linking libc.
248 // https://github.com/ziglang/zig/issues/4019
249 if (!builtin.link_libc) return error.SkipZigTest;
250
251 const fd = try std.os.memfd_create("test", 0);
252 defer std.os.close(fd);
253 try std.os.write(fd, "test");
254 try std.os.lseek_SET(fd, 0);
255
256 var buf: [10]u8 = undefined;
257 const bytes_read = try std.os.read(fd, &buf);
258 expect(bytes_read == 4);
259 expect(mem.eql(u8, buf[0..4], "test"));
260}