Commit a4d4e086c5
Changed files (3)
lib
std
lib/std/heap/PageAllocator.zig
@@ -140,7 +140,8 @@ fn free(context: *anyopaque, slice: []u8, alignment: mem.Alignment, return_addre
}
}
-fn realloc(memory: []u8, new_len: usize, may_move: bool) ?[*]u8 {
+fn realloc(uncasted_memory: []u8, new_len: usize, may_move: bool) ?[*]u8 {
+ const memory: []align(std.heap.page_size_min) u8 = @alignCast(uncasted_memory);
const page_size = std.heap.pageSize();
const new_size_aligned = mem.alignForward(usize, new_len, page_size);
@@ -153,7 +154,7 @@ fn realloc(memory: []u8, new_len: usize, may_move: bool) ?[*]u8 {
// For shrinking that is not releasing, we will only decommit
// the pages not needed anymore.
windows.VirtualFree(
- @as(*anyopaque, @ptrFromInt(new_addr_end)),
+ @ptrFromInt(new_addr_end),
old_addr_end - new_addr_end,
windows.MEM_DECOMMIT,
);
@@ -171,10 +172,11 @@ fn realloc(memory: []u8, new_len: usize, may_move: bool) ?[*]u8 {
if (new_size_aligned == page_aligned_len)
return memory.ptr;
- const mremap_available = false; // native_os == .linux;
+ const mremap_available = native_os == .linux;
if (mremap_available) {
// TODO: if the next_mmap_addr_hint is within the remapped range, update it
- return posix.mremap(memory, new_len, .{ .MAYMOVE = may_move }, null) catch return null;
+ const new_memory = posix.mremap(memory.ptr, memory.len, new_len, .{ .MAYMOVE = may_move }, null) catch return null;
+ return new_memory.ptr;
}
if (new_size_aligned < page_aligned_len) {
lib/std/os/linux.zig
@@ -305,6 +305,13 @@ pub const MAP = switch (native_arch) {
else => @compileError("missing std.os.linux.MAP constants for this architecture"),
};
+pub const MREMAP = packed struct(u32) {
+ MAYMOVE: bool = false,
+ FIXED: bool = false,
+ DONTUNMAP: bool = false,
+ _: u29 = 0,
+};
+
pub const O = switch (native_arch) {
.x86_64 => packed struct(u32) {
ACCMODE: ACCMODE = .RDONLY,
@@ -934,6 +941,17 @@ pub fn mprotect(address: [*]const u8, length: usize, protection: usize) usize {
return syscall3(.mprotect, @intFromPtr(address), length, protection);
}
+pub fn mremap(old_addr: ?[*]const u8, old_len: usize, new_len: usize, flags: MREMAP, new_addr: ?[*]const u8) usize {
+ return syscall5(
+ .mremap,
+ @intFromPtr(old_addr),
+ old_len,
+ new_len,
+ @as(u32, @bitCast(flags)),
+ @intFromPtr(new_addr),
+ );
+}
+
pub const MSF = struct {
pub const ASYNC = 1;
pub const INVALIDATE = 2;
lib/std/posix.zig
@@ -83,6 +83,7 @@ pub const MAP = system.MAP;
pub const MAX_ADDR_LEN = system.MAX_ADDR_LEN;
pub const MFD = system.MFD;
pub const MMAP2_UNIT = system.MMAP2_UNIT;
+pub const MREMAP = system.MREMAP;
pub const MSF = system.MSF;
pub const MSG = system.MSG;
pub const NAME_MAX = system.NAME_MAX;
@@ -4809,6 +4810,40 @@ pub fn munmap(memory: []align(page_size_min) const u8) void {
}
}
+pub const MRemapError = error{
+ LockedMemoryLimitExceeded,
+ /// Either a bug in the calling code, or the operating system abused the
+ /// EINVAL error code.
+ InvalidSyscallParameters,
+ OutOfMemory,
+} || UnexpectedError;
+
+pub fn mremap(
+ old_address: ?[*]align(page_size_min) u8,
+ old_len: usize,
+ new_len: usize,
+ flags: system.MREMAP,
+ new_address: ?[*]align(page_size_min) u8,
+) MRemapError![]align(page_size_min) u8 {
+ const rc = system.mremap(old_address, old_len, new_len, flags, new_address);
+ const err: E = if (builtin.link_libc) blk: {
+ if (rc != std.c.MAP_FAILED) return @as([*]align(page_size_min) u8, @ptrCast(@alignCast(rc)))[0..new_len];
+ break :blk @enumFromInt(system._errno().*);
+ } else blk: {
+ const err = errno(rc);
+ if (err == .SUCCESS) return @as([*]align(page_size_min) u8, @ptrFromInt(rc))[0..new_len];
+ break :blk err;
+ };
+ switch (err) {
+ .SUCCESS => unreachable,
+ .AGAIN => return error.LockedMemoryLimitExceeded,
+ .INVAL => return error.InvalidSyscallParameters,
+ .NOMEM => return error.OutOfMemory,
+ .FAULT => unreachable,
+ else => return unexpectedErrno(err),
+ }
+}
+
pub const MSyncError = error{
UnmappedMemory,
PermissionDenied,