authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-02-03 20:40:57-08:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-02-06 14:23:23-08:00
loga4d4e086c59b702c34218105764d4ec491ecc566
tree165cd9428e064ede06408a792cbdfdfff6f39996
parenta0b2a18648ec4c465f3e19c05338b554c0742dfb

introduce std.posix.mremap and use it

in std.heap.page_allocator

3 files changed, 59 insertions(+), 4 deletions(-)

lib/std/heap/PageAllocator.zig+6-4
...@@ -140,7 +140,8 @@ fn free(context: *anyopaque, slice: []u8, alignment: mem.Alignment, return_addre...@@ -140,7 +140,8 @@ fn free(context: *anyopaque, slice: []u8, alignment: mem.Alignment, return_addre
140 }140 }
141}141}
142142
143fn realloc(memory: []u8, new_len: usize, may_move: bool) ?[*]u8 {143fn realloc(uncasted_memory: []u8, new_len: usize, may_move: bool) ?[*]u8 {
144 const memory: []align(std.heap.page_size_min) u8 = @alignCast(uncasted_memory);
144 const page_size = std.heap.pageSize();145 const page_size = std.heap.pageSize();
145 const new_size_aligned = mem.alignForward(usize, new_len, page_size);146 const new_size_aligned = mem.alignForward(usize, new_len, page_size);
146147
...@@ -153,7 +154,7 @@ fn realloc(memory: []u8, new_len: usize, may_move: bool) ?[*]u8 {...@@ -153,7 +154,7 @@ fn realloc(memory: []u8, new_len: usize, may_move: bool) ?[*]u8 {
153 // For shrinking that is not releasing, we will only decommit154 // For shrinking that is not releasing, we will only decommit
154 // the pages not needed anymore.155 // the pages not needed anymore.
155 windows.VirtualFree(156 windows.VirtualFree(
156 @as(*anyopaque, @ptrFromInt(new_addr_end)),157 @ptrFromInt(new_addr_end),
157 old_addr_end - new_addr_end,158 old_addr_end - new_addr_end,
158 windows.MEM_DECOMMIT,159 windows.MEM_DECOMMIT,
159 );160 );
...@@ -171,10 +172,11 @@ fn realloc(memory: []u8, new_len: usize, may_move: bool) ?[*]u8 {...@@ -171,10 +172,11 @@ fn realloc(memory: []u8, new_len: usize, may_move: bool) ?[*]u8 {
171 if (new_size_aligned == page_aligned_len)172 if (new_size_aligned == page_aligned_len)
172 return memory.ptr;173 return memory.ptr;
173174
174 const mremap_available = false; // native_os == .linux;175 const mremap_available = native_os == .linux;
175 if (mremap_available) {176 if (mremap_available) {
176 // TODO: if the next_mmap_addr_hint is within the remapped range, update it177 // TODO: if the next_mmap_addr_hint is within the remapped range, update it
177 return posix.mremap(memory, new_len, .{ .MAYMOVE = may_move }, null) catch return null;178 const new_memory = posix.mremap(memory.ptr, memory.len, new_len, .{ .MAYMOVE = may_move }, null) catch return null;
179 return new_memory.ptr;
178 }180 }
179181
180 if (new_size_aligned < page_aligned_len) {182 if (new_size_aligned < page_aligned_len) {
lib/std/os/linux.zig+18
...@@ -305,6 +305,13 @@ pub const MAP = switch (native_arch) {...@@ -305,6 +305,13 @@ pub const MAP = switch (native_arch) {
305 else => @compileError("missing std.os.linux.MAP constants for this architecture"),305 else => @compileError("missing std.os.linux.MAP constants for this architecture"),
306};306};
307307
308pub const MREMAP = packed struct(u32) {
309 MAYMOVE: bool = false,
310 FIXED: bool = false,
311 DONTUNMAP: bool = false,
312 _: u29 = 0,
313};
314
308pub const O = switch (native_arch) {315pub const O = switch (native_arch) {
309 .x86_64 => packed struct(u32) {316 .x86_64 => packed struct(u32) {
310 ACCMODE: ACCMODE = .RDONLY,317 ACCMODE: ACCMODE = .RDONLY,
...@@ -934,6 +941,17 @@ pub fn mprotect(address: [*]const u8, length: usize, protection: usize) usize {...@@ -934,6 +941,17 @@ pub fn mprotect(address: [*]const u8, length: usize, protection: usize) usize {
934 return syscall3(.mprotect, @intFromPtr(address), length, protection);941 return syscall3(.mprotect, @intFromPtr(address), length, protection);
935}942}
936943
944pub fn mremap(old_addr: ?[*]const u8, old_len: usize, new_len: usize, flags: MREMAP, new_addr: ?[*]const u8) usize {
945 return syscall5(
946 .mremap,
947 @intFromPtr(old_addr),
948 old_len,
949 new_len,
950 @as(u32, @bitCast(flags)),
951 @intFromPtr(new_addr),
952 );
953}
954
937pub const MSF = struct {955pub const MSF = struct {
938 pub const ASYNC = 1;956 pub const ASYNC = 1;
939 pub const INVALIDATE = 2;957 pub const INVALIDATE = 2;
lib/std/posix.zig+35
...@@ -83,6 +83,7 @@ pub const MAP = system.MAP;...@@ -83,6 +83,7 @@ pub const MAP = system.MAP;
83pub const MAX_ADDR_LEN = system.MAX_ADDR_LEN;83pub const MAX_ADDR_LEN = system.MAX_ADDR_LEN;
84pub const MFD = system.MFD;84pub const MFD = system.MFD;
85pub const MMAP2_UNIT = system.MMAP2_UNIT;85pub const MMAP2_UNIT = system.MMAP2_UNIT;
86pub const MREMAP = system.MREMAP;
86pub const MSF = system.MSF;87pub const MSF = system.MSF;
87pub const MSG = system.MSG;88pub const MSG = system.MSG;
88pub const NAME_MAX = system.NAME_MAX;89pub const NAME_MAX = system.NAME_MAX;
...@@ -4809,6 +4810,40 @@ pub fn munmap(memory: []align(page_size_min) const u8) void {...@@ -4809,6 +4810,40 @@ pub fn munmap(memory: []align(page_size_min) const u8) void {
4809 }4810 }
4810}4811}
48114812
4813pub const MRemapError = error{
4814 LockedMemoryLimitExceeded,
4815 /// Either a bug in the calling code, or the operating system abused the
4816 /// EINVAL error code.
4817 InvalidSyscallParameters,
4818 OutOfMemory,
4819} || UnexpectedError;
4820
4821pub fn mremap(
4822 old_address: ?[*]align(page_size_min) u8,
4823 old_len: usize,
4824 new_len: usize,
4825 flags: system.MREMAP,
4826 new_address: ?[*]align(page_size_min) u8,
4827) MRemapError![]align(page_size_min) u8 {
4828 const rc = system.mremap(old_address, old_len, new_len, flags, new_address);
4829 const err: E = if (builtin.link_libc) blk: {
4830 if (rc != std.c.MAP_FAILED) return @as([*]align(page_size_min) u8, @ptrCast(@alignCast(rc)))[0..new_len];
4831 break :blk @enumFromInt(system._errno().*);
4832 } else blk: {
4833 const err = errno(rc);
4834 if (err == .SUCCESS) return @as([*]align(page_size_min) u8, @ptrFromInt(rc))[0..new_len];
4835 break :blk err;
4836 };
4837 switch (err) {
4838 .SUCCESS => unreachable,
4839 .AGAIN => return error.LockedMemoryLimitExceeded,
4840 .INVAL => return error.InvalidSyscallParameters,
4841 .NOMEM => return error.OutOfMemory,
4842 .FAULT => unreachable,
4843 else => return unexpectedErrno(err),
4844 }
4845}
4846
4812pub const MSyncError = error{4847pub const MSyncError = error{
4813 UnmappedMemory,4848 UnmappedMemory,
4814 PermissionDenied,4849 PermissionDenied,