authorgravatar for bblack@wikimedia.orgBrandon Black <bblack@wikimedia.org> 2025-08-19 14:57:41-05:00
committergravatar for alex@alexrp.comAlex Rønne Petersen <alex@alexrp.com> 2025-08-20 23:38:45+02:00
log8248597a2726663a89e31896f0e9751db5b9db82
treef7d70d0dadad659f801a5c75b40e85a6513f7c51
parent172e97154de214fd3f4ecf1753382fb687f9b4ab

Add mlock syscalls to std.c and std.posix

Linux already gained the relevant syscalls and consts in #24473 The basic mlock() and munlock() are fairly universal across the *nix world with a consistent interface, but are missing on wasi and windows. The mlockall() and munlockall() calls are not as widely supported as the basic ones. Notable non-implementers include darwin, haiku, and serenity (and of course wasi and windows again). mlock2() is Linux-only, as are its MLOCK flags.

2 files changed, 122 insertions(+), 0 deletions(-)

lib/std/c.zig+50
...@@ -1599,6 +1599,25 @@ pub const MADV = switch (native_os) {...@@ -1599,6 +1599,25 @@ pub const MADV = switch (native_os) {
1599 },1599 },
1600 else => void,1600 else => void,
1601};1601};
1602pub const MCL = switch (native_os) {
1603 .linux => linux.MCL,
1604 // https://github.com/freebsd/freebsd-src/blob/39fea5c8dc598021e900c4feaf0e18111fda57b2/sys/sys/mman.h#L133
1605 // https://github.com/DragonFlyBSD/DragonFlyBSD/blob/088552723935447397400336f5ddb7aa5f5de660/sys/sys/mman.h#L118
1606 // https://github.com/NetBSD/src/blob/fd2741deca927c18e3ba15acdf78b8b14b2abe36/sys/sys/mman.h#L179
1607 // https://github.com/openbsd/src/blob/39404228f6d36c0ca4be5f04ab5385568ebd6aa3/sys/sys/mman.h#L129
1608 // https://github.com/kofemann/opensolaris/blob/80192cd83bf665e708269dae856f9145f7190f74/usr/src/uts/common/sys/mman.h#L379
1609 // https://github.com/illumos/illumos-gate/blob/5280477614f83fea20fc938729df6adb3e44340d/usr/src/uts/common/sys/mman.h#L343
1610 .freebsd, .dragonfly, .netbsd, .openbsd, .solaris, .illumos => packed struct(c_int) {
1611 CURRENT: bool = 0,
1612 FUTURE: bool = 0,
1613 _: std.meta.Int(.unsigned, @bitSizeOf(c_int) - 2) = 0,
1614 },
1615 else => void,
1616};
1617pub const MLOCK = switch (native_os) {
1618 .linux => linux.MLOCK,
1619 else => void,
1620};
1602pub const MSF = switch (native_os) {1621pub const MSF = switch (native_os) {
1603 .linux => linux.MSF,1622 .linux => linux.MSF,
1604 .emscripten => emscripten.MSF,1623 .emscripten => emscripten.MSF,
...@@ -10425,6 +10444,31 @@ pub const gettimeofday = switch (native_os) {...@@ -10425,6 +10444,31 @@ pub const gettimeofday = switch (native_os) {
10425 else => private.gettimeofday,10444 else => private.gettimeofday,
10426};10445};
1042710446
10447pub const mlock = switch (native_os) {
10448 .windows, .wasi => {},
10449 else => private.mlock,
10450};
10451
10452pub const mlock2 = switch (native_os) {
10453 linux => private.mlock2,
10454 else => {},
10455};
10456
10457pub const munlock = switch (native_os) {
10458 .windows, .wasi => {},
10459 else => private.munlock,
10460};
10461
10462pub const mlockall = switch (native_os) {
10463 .linux, .freebsd, .dragonfly, .netbsd, .openbsd, .solaris, .illumos => private.mlockall,
10464 else => {},
10465};
10466
10467pub const munlockall = switch (native_os) {
10468 .linux, .freebsd, .dragonfly, .netbsd, .openbsd, .solaris, .illumos => private.munlockall,
10469 else => {},
10470};
10471
10428pub const msync = switch (native_os) {10472pub const msync = switch (native_os) {
10429 .netbsd => private.__msync13,10473 .netbsd => private.__msync13,
10430 else => private.msync,10474 else => private.msync,
...@@ -11314,6 +11358,12 @@ const private = struct {...@@ -11314,6 +11358,12 @@ const private = struct {
11314 extern "c" fn malloc_usable_size(?*const anyopaque) usize;11358 extern "c" fn malloc_usable_size(?*const anyopaque) usize;
11315 extern "c" fn posix_memalign(memptr: *?*anyopaque, alignment: usize, size: usize) c_int;11359 extern "c" fn posix_memalign(memptr: *?*anyopaque, alignment: usize, size: usize) c_int;
1131611360
11361 extern "c" fn mlock(addr: *align(page_size) const anyopaque, len: usize) c_int;
11362 extern "c" fn mlock2(addr: *align(page_size) const anyopaque, len: usize, flags: MLOCK) c_int;
11363 extern "c" fn munlock(addr: *align(page_size) const anyopaque, len: usize) c_int;
11364 extern "c" fn mlockall(flags: MCL) c_int;
11365 extern "c" fn munlockall() c_int;
11366
11317 /// macos modernized symbols.11367 /// macos modernized symbols.
11318 /// x86_64 links to $INODE64 suffix for 64-bit support.11368 /// x86_64 links to $INODE64 suffix for 64-bit support.
11319 /// Note these are not necessary on aarch64.11369 /// Note these are not necessary on aarch64.
lib/std/posix.zig+72
...@@ -81,7 +81,9 @@ pub const Kevent = system.Kevent;...@@ -81,7 +81,9 @@ pub const Kevent = system.Kevent;
81pub const MADV = system.MADV;81pub const MADV = system.MADV;
82pub const MAP = system.MAP;82pub const MAP = system.MAP;
83pub const MAX_ADDR_LEN = system.MAX_ADDR_LEN;83pub const MAX_ADDR_LEN = system.MAX_ADDR_LEN;
84pub const MCL = system.MCL;
84pub const MFD = system.MFD;85pub const MFD = system.MFD;
86pub const MLOCK = system.MLOCK;
85pub const MREMAP = system.MREMAP;87pub const MREMAP = system.MREMAP;
86pub const MSF = system.MSF;88pub const MSF = system.MSF;
87pub const MSG = system.MSG;89pub const MSG = system.MSG;
...@@ -4745,6 +4747,76 @@ pub fn fanotify_markZ(...@@ -4745,6 +4747,76 @@ pub fn fanotify_markZ(
4745 }4747 }
4746}4748}
47474749
4750pub const MlockError = error{
4751 PermissionDenied,
4752 LockedMemoryLimitExceeded,
4753 SystemResources,
4754} || UnexpectedError;
4755
4756pub fn mlock(memory: []align(page_size_min) const u8) MlockError!void {
4757 if (@TypeOf(system.mlock) == void)
4758 @compileError("mlock not supported on this OS");
4759 return switch (errno(system.mlock(memory.ptr, memory.len))) {
4760 .SUCCESS => {},
4761 .INVAL => unreachable, // unaligned, negative, runs off end of addrspace
4762 .PERM => error.PermissionDenied,
4763 .NOMEM => error.LockedMemoryLimitExceeded,
4764 .AGAIN => error.SystemResources,
4765 else => |err| unexpectedErrno(err),
4766 };
4767}
4768
4769pub fn mlock2(memory: []align(page_size_min) const u8, flags: MLOCK) MlockError!void {
4770 if (@TypeOf(system.mlock2) == void)
4771 @compileError("mlock2 not supported on this OS");
4772 return switch (errno(system.mlock2(memory.ptr, memory.len, flags))) {
4773 .SUCCESS => {},
4774 .INVAL => unreachable, // bad memory or bad flags
4775 .PERM => error.PermissionDenied,
4776 .NOMEM => error.LockedMemoryLimitExceeded,
4777 .AGAIN => error.SystemResources,
4778 else => |err| unexpectedErrno(err),
4779 };
4780}
4781
4782pub fn munlock(memory: []align(page_size_min) const u8) MlockError!void {
4783 if (@TypeOf(system.munlock) == void)
4784 @compileError("munlock not supported on this OS");
4785 return switch (errno(system.munlock(memory.ptr, memory.len))) {
4786 .SUCCESS => {},
4787 .INVAL => unreachable, // unaligned or runs off end of addr space
4788 .PERM => return error.PermissionDenied,
4789 .NOMEM => return error.LockedMemoryLimitExceeded,
4790 .AGAIN => return error.SystemResources,
4791 else => |err| unexpectedErrno(err),
4792 };
4793}
4794
4795pub fn mlockall(flags: MCL) MlockError!void {
4796 if (@TypeOf(system.mlockall) == void)
4797 @compileError("mlockall not supported on this OS");
4798 return switch (errno(system.mlockall(flags))) {
4799 .SUCCESS => {},
4800 .INVAL => unreachable, // bad flags
4801 .PERM => error.PermissionDenied,
4802 .NOMEM => error.LockedMemoryLimitExceeded,
4803 .AGAIN => error.SystemResources,
4804 else => |err| unexpectedErrno(err),
4805 };
4806}
4807
4808pub fn munlockall() MlockError!void {
4809 if (@TypeOf(system.munlockall) == void)
4810 @compileError("munlockall not supported on this OS");
4811 return switch (errno(system.munlockall())) {
4812 .SUCCESS => {},
4813 .PERM => error.PermissionDenied,
4814 .NOMEM => error.LockedMemoryLimitExceeded,
4815 .AGAIN => error.SystemResources,
4816 else => |err| unexpectedErrno(err),
4817 };
4818}
4819
4748pub const MProtectError = error{4820pub const MProtectError = error{
4749 /// The memory cannot be given the specified access. This can happen, for example, if you4821 /// The memory cannot be given the specified access. This can happen, for example, if you
4750 /// mmap(2) a file to which you have read-only access, then ask mprotect() to mark it4822 /// mmap(2) a file to which you have read-only access, then ask mprotect() to mark it