Commit 1392c24166

Isaac Freund <mail@isaacfreund.com>
2022-05-14 14:16:19
std.os: Add memfd_create for FreeBSD
This is minorly breaking as e.g. std.os.linux.MFD_CLOEXEC is now std.os.linux.MFD.CLOEXEC.
1 parent 5b03d55
Changed files (4)
lib/std/c/freebsd.zig
@@ -1640,3 +1640,12 @@ pub const POLL = struct {
 
     pub const STANDARD = IN | PRI | OUT | RDNORM | RDBAND | WRBAND | ERR | HUP | NVAL;
 };
+
+pub const NAME_MAX = 255;
+
+pub const MFD = struct {
+    pub const CLOEXEC = 0x0001;
+    pub const ALLOW_SEALING = 0x0002;
+};
+
+pub extern "c" fn memfd_create(name: [*:0]const u8, flags: c_uint) c_int;
lib/std/os/linux.zig
@@ -3972,11 +3972,6 @@ pub const POLL = struct {
     pub const RDBAND = 0x080;
 };
 
-pub const MFD_CLOEXEC = 0x0001;
-pub const MFD_ALLOW_SEALING = 0x0002;
-pub const MFD_HUGETLB = 0x0004;
-pub const MFD_ALL_FLAGS = MFD_CLOEXEC | MFD_ALLOW_SEALING | MFD_HUGETLB;
-
 pub const HUGETLB_FLAG_ENCODE_SHIFT = 26;
 pub const HUGETLB_FLAG_ENCODE_MASK = 0x3f;
 pub const HUGETLB_FLAG_ENCODE_64KB = 16 << HUGETLB_FLAG_ENCODE_SHIFT;
@@ -3992,20 +3987,27 @@ pub const HUGETLB_FLAG_ENCODE_1GB = 30 << HUGETLB_FLAG_ENCODE_SHIFT;
 pub const HUGETLB_FLAG_ENCODE_2GB = 31 << HUGETLB_FLAG_ENCODE_SHIFT;
 pub const HUGETLB_FLAG_ENCODE_16GB = 34 << HUGETLB_FLAG_ENCODE_SHIFT;
 
-pub const MFD_HUGE_SHIFT = HUGETLB_FLAG_ENCODE_SHIFT;
-pub const MFD_HUGE_MASK = HUGETLB_FLAG_ENCODE_MASK;
-pub const MFD_HUGE_64KB = HUGETLB_FLAG_ENCODE_64KB;
-pub const MFD_HUGE_512KB = HUGETLB_FLAG_ENCODE_512KB;
-pub const MFD_HUGE_1MB = HUGETLB_FLAG_ENCODE_1MB;
-pub const MFD_HUGE_2MB = HUGETLB_FLAG_ENCODE_2MB;
-pub const MFD_HUGE_8MB = HUGETLB_FLAG_ENCODE_8MB;
-pub const MFD_HUGE_16MB = HUGETLB_FLAG_ENCODE_16MB;
-pub const MFD_HUGE_32MB = HUGETLB_FLAG_ENCODE_32MB;
-pub const MFD_HUGE_256MB = HUGETLB_FLAG_ENCODE_256MB;
-pub const MFD_HUGE_512MB = HUGETLB_FLAG_ENCODE_512MB;
-pub const MFD_HUGE_1GB = HUGETLB_FLAG_ENCODE_1GB;
-pub const MFD_HUGE_2GB = HUGETLB_FLAG_ENCODE_2GB;
-pub const MFD_HUGE_16GB = HUGETLB_FLAG_ENCODE_16GB;
+pub const MFD = struct {
+    pub const CLOEXEC = 0x0001;
+    pub const ALLOW_SEALING = 0x0002;
+    pub const HUGETLB = 0x0004;
+    pub const ALL_FLAGS = CLOEXEC | ALLOW_SEALING | HUGETLB;
+
+    pub const HUGE_SHIFT = HUGETLB_FLAG_ENCODE_SHIFT;
+    pub const HUGE_MASK = HUGETLB_FLAG_ENCODE_MASK;
+    pub const HUGE_64KB = HUGETLB_FLAG_ENCODE_64KB;
+    pub const HUGE_512KB = HUGETLB_FLAG_ENCODE_512KB;
+    pub const HUGE_1MB = HUGETLB_FLAG_ENCODE_1MB;
+    pub const HUGE_2MB = HUGETLB_FLAG_ENCODE_2MB;
+    pub const HUGE_8MB = HUGETLB_FLAG_ENCODE_8MB;
+    pub const HUGE_16MB = HUGETLB_FLAG_ENCODE_16MB;
+    pub const HUGE_32MB = HUGETLB_FLAG_ENCODE_32MB;
+    pub const HUGE_256MB = HUGETLB_FLAG_ENCODE_256MB;
+    pub const HUGE_512MB = HUGETLB_FLAG_ENCODE_512MB;
+    pub const HUGE_1GB = HUGETLB_FLAG_ENCODE_1GB;
+    pub const HUGE_2GB = HUGETLB_FLAG_ENCODE_2GB;
+    pub const HUGE_16GB = HUGETLB_FLAG_ENCODE_16GB;
+};
 
 pub const rusage = extern struct {
     utime: timeval,
lib/std/os/test.zig
@@ -495,8 +495,9 @@ test "argsAlloc" {
 }
 
 test "memfd_create" {
-    // memfd_create is linux specific.
-    if (native_os != .linux) return error.SkipZigTest;
+    // memfd_create is only supported by linux and freebsd.
+    if (native_os != .linux and native_os != .freebsd) return error.SkipZigTest;
+
     const fd = std.os.memfd_create("test", 0) catch |err| switch (err) {
         // Related: https://github.com/ziglang/zig/issues/4019
         error.SystemOutdated => return error.SkipZigTest,
lib/std/os.zig
@@ -97,6 +97,7 @@ pub const MADV = system.MADV;
 pub const MAP = system.MAP;
 pub const MSF = system.MSF;
 pub const MAX_ADDR_LEN = system.MAX_ADDR_LEN;
+pub const MFD = system.MFD;
 pub const MMAP2_UNIT = system.MMAP2_UNIT;
 pub const MSG = system.MSG;
 pub const NAME_MAX = system.NAME_MAX;
@@ -6522,20 +6523,37 @@ pub const MemFdCreateError = error{
 } || UnexpectedError;
 
 pub fn memfd_createZ(name: [*:0]const u8, flags: u32) MemFdCreateError!fd_t {
-    // memfd_create is available only in glibc versions starting with 2.27.
-    const use_c = std.c.versionCheck(.{ .major = 2, .minor = 27, .patch = 0 }).ok;
-    const sys = if (use_c) std.c else linux;
-    const getErrno = if (use_c) std.c.getErrno else linux.getErrno;
-    const rc = sys.memfd_create(name, flags);
-    switch (getErrno(rc)) {
-        .SUCCESS => return @intCast(fd_t, rc),
-        .FAULT => unreachable, // name has invalid memory
-        .INVAL => unreachable, // name/flags are faulty
-        .NFILE => return error.SystemFdQuotaExceeded,
-        .MFILE => return error.ProcessFdQuotaExceeded,
-        .NOMEM => return error.OutOfMemory,
-        .NOSYS => return error.SystemOutdated,
-        else => |err| return unexpectedErrno(err),
+    switch (builtin.os.tag) {
+        .linux => {
+            // memfd_create is available only in glibc versions starting with 2.27.
+            const use_c = std.c.versionCheck(.{ .major = 2, .minor = 27, .patch = 0 }).ok;
+            const sys = if (use_c) std.c else linux;
+            const getErrno = if (use_c) std.c.getErrno else linux.getErrno;
+            const rc = sys.memfd_create(name, flags);
+            switch (getErrno(rc)) {
+                .SUCCESS => return @intCast(fd_t, rc),
+                .FAULT => unreachable, // name has invalid memory
+                .INVAL => unreachable, // name/flags are faulty
+                .NFILE => return error.SystemFdQuotaExceeded,
+                .MFILE => return error.ProcessFdQuotaExceeded,
+                .NOMEM => return error.OutOfMemory,
+                .NOSYS => return error.SystemOutdated,
+                else => |err| return unexpectedErrno(err),
+            }
+        },
+        .freebsd => {
+            const rc = system.memfd_create(name, flags);
+            switch (errno(rc)) {
+                .SUCCESS => return rc,
+                .BADF => unreachable, // name argument NULL
+                .INVAL => unreachable, // name too long or invalid/unsupported flags.
+                .MFILE => return error.ProcessFdQuotaExceeded,
+                .NFILE => return error.SystemFdQuotaExceeded,
+                .NOSYS => return error.SystemOutdated,
+                else => |err| return unexpectedErrno(err),
+            }
+        },
+        else => @compileError("target OS does not support memfd_create()"),
     }
 }