| author | |
| committer | |
| log | 53433cdea2cee73caea52a6baa10dc7bc7f6da4d |
| tree | be054df879f9fd491f0a2b9fc87f1af3ccff9d29 |
| parent | 4664eae1e40813fb50bab83247cc7391312e38cb |
Do the alignment dance by ourselves whenever posix_memalign is not
available.
Don't try to use malloc as it has too many edge cases, figuring out
whether a block of memory is manually aligned by the mechanism above or
is directly coming from malloc becomes too hard to be valuable.9 files changed, 67 insertions(+), 47 deletions(-)
lib/std/c.zig-12| ... | ... | @@ -246,20 +246,8 @@ pub extern "c" fn setresuid(ruid: uid_t, euid: uid_t, suid: uid_t) c_int; |
| 246 | 246 | pub extern "c" fn setresgid(rgid: gid_t, egid: gid_t, sgid: gid_t) c_int; |
| 247 | 247 | |
| 248 | 248 | pub extern "c" fn malloc(usize) ?*c_void; |
| 249 | ||
| 250 | pub usingnamespace switch (builtin.os.tag) { | |
| 251 | .linux, .freebsd, .kfreebsd, .netbsd => struct { | |
| 252 | pub extern "c" fn malloc_usable_size(?*const c_void) usize; | |
| 253 | }, | |
| 254 | .macos, .ios, .watchos, .tvos => struct { | |
| 255 | pub extern "c" fn malloc_size(?*const c_void) usize; | |
| 256 | }, | |
| 257 | else => struct {}, | |
| 258 | }; | |
| 259 | ||
| 260 | 249 | pub extern "c" fn realloc(?*c_void, usize) ?*c_void; |
| 261 | 250 | pub extern "c" fn free(*c_void) void; |
| 262 | pub extern "c" fn posix_memalign(memptr: *?*c_void, alignment: usize, size: usize) c_int; | |
| 263 | 251 | |
| 264 | 252 | pub extern "c" fn futimes(fd: fd_t, times: *[2]timeval) c_int; |
| 265 | 253 | pub extern "c" fn utimes(path: [*:0]const u8, times: *[2]timeval) c_int; |
lib/std/c/darwin.zig+3| ... | ... | @@ -45,6 +45,9 @@ pub const _fstatat = if (builtin.arch == .aarch64) fstatat else @"fstatat$INODE6 |
| 45 | 45 | pub extern "c" fn mach_absolute_time() u64; |
| 46 | 46 | pub extern "c" fn mach_timebase_info(tinfo: ?*mach_timebase_info_data) void; |
| 47 | 47 | |
| 48 | pub extern "c" fn malloc_size(?*const c_void) usize; | |
| 49 | pub extern "c" fn posix_memalign(memptr: *?*c_void, alignment: usize, size: usize) c_int; | |
| 50 | ||
| 48 | 51 | pub extern "c" fn kevent64( |
| 49 | 52 | kq: c_int, |
| 50 | 53 | changelist: [*]const kevent64_s, |
lib/std/c/dragonfly.zig+2| ... | ... | @@ -17,6 +17,8 @@ pub extern "c" fn getrandom(buf_ptr: [*]u8, buf_len: usize, flags: c_uint) isize |
| 17 | 17 | pub const dl_iterate_phdr_callback = fn (info: *dl_phdr_info, size: usize, data: ?*c_void) callconv(.C) c_int; |
| 18 | 18 | pub extern "c" fn dl_iterate_phdr(callback: dl_iterate_phdr_callback, data: ?*c_void) c_int; |
| 19 | 19 | |
| 20 | pub extern "c" fn posix_memalign(memptr: *?*c_void, alignment: usize, size: usize) c_int; | |
| 21 | ||
| 20 | 22 | pub const pthread_mutex_t = extern struct { |
| 21 | 23 | inner: ?*c_void = null, |
| 22 | 24 | }; |
lib/std/c/freebsd.zig+3| ... | ... | @@ -13,6 +13,9 @@ pub extern "c" fn getdents(fd: c_int, buf_ptr: [*]u8, nbytes: usize) usize; |
| 13 | 13 | pub extern "c" fn sigaltstack(ss: ?*stack_t, old_ss: ?*stack_t) c_int; |
| 14 | 14 | pub extern "c" fn getrandom(buf_ptr: [*]u8, buf_len: usize, flags: c_uint) isize; |
| 15 | 15 | |
| 16 | pub extern "c" fn posix_memalign(memptr: *?*c_void, alignment: usize, size: usize) c_int; | |
| 17 | pub extern "c" fn malloc_usable_size(?*const c_void) usize; | |
| 18 | ||
| 16 | 19 | pub const sf_hdtr = extern struct { |
| 17 | 20 | headers: [*]const iovec_const, |
| 18 | 21 | hdr_cnt: c_int, |
lib/std/c/linux.zig+2| ... | ... | @@ -101,6 +101,8 @@ pub extern "c" fn copy_file_range(fd_in: fd_t, off_in: ?*i64, fd_out: fd_t, off_ |
| 101 | 101 | pub extern "c" fn signalfd(fd: fd_t, mask: *const sigset_t, flags: c_uint) c_int; |
| 102 | 102 | |
| 103 | 103 | pub extern "c" fn prlimit(pid: pid_t, resource: rlimit_resource, new_limit: *const rlimit, old_limit: *rlimit) c_int; |
| 104 | pub extern "c" fn posix_memalign(memptr: *?*c_void, alignment: usize, size: usize) c_int; | |
| 105 | pub extern "c" fn malloc_usable_size(?*const c_void) usize; | |
| 104 | 106 | |
| 105 | 107 | pub const pthread_attr_t = extern struct { |
| 106 | 108 | __size: [56]u8, |
lib/std/c/netbsd.zig+3| ... | ... | @@ -30,6 +30,9 @@ pub extern "c" fn __getrusage50(who: c_int, usage: *rusage) c_int; |
| 30 | 30 | // libc aliases this as sched_yield |
| 31 | 31 | pub extern "c" fn __libc_thr_yield() c_int; |
| 32 | 32 | |
| 33 | pub extern "c" fn posix_memalign(memptr: *?*c_void, alignment: usize, size: usize) c_int; | |
| 34 | pub extern "c" fn malloc_usable_size(?*const c_void) usize; | |
| 35 | ||
| 33 | 36 | pub const pthread_mutex_t = extern struct { |
| 34 | 37 | ptm_magic: u32 = 0x33330003, |
| 35 | 38 | ptm_errorcheck: padded_pthread_spin_t = 0, |
lib/std/c/openbsd.zig+3| ... | ... | @@ -32,3 +32,6 @@ pub const pthread_spinlock_t = extern struct { |
| 32 | 32 | pub const pthread_attr_t = extern struct { |
| 33 | 33 | inner: ?*c_void = null, |
| 34 | 34 | }; |
| 35 | ||
| 36 | pub extern "c" fn posix_memalign(memptr: *?*c_void, alignment: usize, size: usize) c_int; | |
| 37 | pub extern "c" fn malloc_usable_size(?*const c_void) usize; |
lib/std/c/windows.zig+1-3| ... | ... | @@ -5,6 +5,4 @@ |
| 5 | 5 | // and substantial portions of the software. |
| 6 | 6 | pub extern "c" fn _errno() *c_int; |
| 7 | 7 | |
| 8 | pub extern "c" fn _aligned_free(memblock: ?*c_void) void; | |
| 9 | pub extern "c" fn _aligned_malloc(size: usize, alignment: usize) ?*c_void; | |
| 10 | pub extern "c" fn _aligned_realloc(memblock: ?*c_void, size: usize, alignment: usize) ?*c_void; | |
| 8 | pub extern "c" fn _msize(memblock: ?*c_void) usize; |
lib/std/heap.zig+50-32| ... | ... | @@ -38,37 +38,63 @@ const CAllocator = struct { |
| 38 | 38 | pub const supports_malloc_size = true; |
| 39 | 39 | pub const malloc_size = c.malloc_usable_size; |
| 40 | 40 | } |
| 41 | else if (comptime @hasDecl(c, "_msize")) | |
| 42 | struct { | |
| 43 | pub const supports_malloc_size = true; | |
| 44 | pub const malloc_size = c._msize; | |
| 45 | } | |
| 41 | 46 | else |
| 42 | 47 | struct { |
| 43 | 48 | pub const supports_malloc_size = false; |
| 44 | 49 | }; |
| 45 | 50 | |
| 46 | // The alignment guaranteed by malloc, the value matches the result of the C | |
| 47 | // expression `alignof(max_alignment_t)` | |
| 48 | const min_ptr_alignment = comptime std.math.max( | |
| 49 | @alignOf(c_longdouble), | |
| 50 | @alignOf(c_longlong), | |
| 51 | ); | |
| 51 | pub const supports_posix_memalign = false and @hasDecl(c, "posix_memalign"); | |
| 52 | 52 | |
| 53 | fn aligned_alloc(len: usize, alignment: usize) ?*c_void { | |
| 54 | // The minimum alignment supported by both APIs is the size of a pointer | |
| 55 | const eff_alignment = std.math.max(alignment, @sizeOf(usize)); | |
| 53 | fn get_header(ptr: [*]u8) *[*]u8 { | |
| 54 | return @intToPtr(*[*]u8, @ptrToInt(ptr) - @sizeOf(usize)); | |
| 55 | } | |
| 56 | 56 | |
| 57 | if (builtin.os.tag == .windows) { | |
| 58 | return c._aligned_malloc(len, eff_alignment); | |
| 57 | fn aligned_alloc(len: usize, alignment: usize) ?[*]u8 { | |
| 58 | if (supports_posix_memalign) { | |
| 59 | // The minimum alignment supported posix_memalign is the pointer size | |
| 60 | const eff_alignment = std.math.max(alignment, @sizeOf(usize)); | |
| 61 | ||
| 62 | var aligned_ptr: ?*c_void = undefined; | |
| 63 | if (c.posix_memalign(&aligned_ptr, eff_alignment, len) != 0) | |
| 64 | return null; | |
| 65 | ||
| 66 | return @ptrCast([*]u8, aligned_ptr); | |
| 59 | 67 | } |
| 60 | 68 | |
| 61 | var aligned_ptr: ?*c_void = undefined; | |
| 62 | if (c.posix_memalign(&aligned_ptr, eff_alignment, len) != 0) | |
| 63 | return null; | |
| 69 | // Thin wrapper around regular malloc, overallocate to account for | |
| 70 | // alignment padding and store the orignal malloc()'ed pointer before | |
| 71 | // the aligned address. | |
| 72 | var unaligned_ptr = @ptrCast([*]u8, c.malloc(len + alignment - 1 + @sizeOf(usize)) orelse return null); | |
| 73 | const unaligned_addr = @ptrToInt(unaligned_ptr); | |
| 74 | const aligned_addr = mem.alignForward(unaligned_addr + @sizeOf(usize), alignment); | |
| 75 | var aligned_ptr = unaligned_ptr + (aligned_addr - unaligned_addr); | |
| 76 | get_header(aligned_ptr).* = unaligned_ptr; | |
| 77 | ||
| 64 | 78 | return aligned_ptr; |
| 65 | 79 | } |
| 66 | 80 | |
| 67 | fn aligned_free(ptr: *c_void) void { | |
| 68 | if (builtin.os.tag == .windows) { | |
| 69 | return c._aligned_free(ptr); | |
| 81 | fn aligned_free(ptr: [*]u8) void { | |
| 82 | if (supports_posix_memalign) { | |
| 83 | return c.free(ptr); | |
| 70 | 84 | } |
| 71 | c.free(ptr); | |
| 85 | ||
| 86 | const unaligned_ptr = get_header(ptr).*; | |
| 87 | c.free(unaligned_ptr); | |
| 88 | } | |
| 89 | ||
| 90 | fn aligned_alloc_size(ptr: [*]u8) usize { | |
| 91 | if (supports_posix_memalign) { | |
| 92 | return malloc_size(ptr); | |
| 93 | } | |
| 94 | ||
| 95 | const unaligned_ptr = get_header(ptr).*; | |
| 96 | const delta = @ptrToInt(ptr) - @ptrToInt(unaligned_ptr); | |
| 97 | return malloc_size(unaligned_ptr) - delta; | |
| 72 | 98 | } |
| 73 | 99 | |
| 74 | 100 | fn alloc( |
| ... | ... | @@ -81,23 +107,18 @@ const CAllocator = struct { |
| 81 | 107 | assert(len > 0); |
| 82 | 108 | assert(std.math.isPowerOfTwo(alignment)); |
| 83 | 109 | |
| 84 | var ptr = if (alignment <= min_ptr_alignment) | |
| 85 | @ptrCast([*]u8, c.malloc(len) orelse return error.OutOfMemory) | |
| 86 | else | |
| 87 | @ptrCast([*]u8, aligned_alloc(len, alignment) orelse return error.OutOfMemory); | |
| 88 | ||
| 89 | if (len_align == 0) | |
| 110 | var ptr = aligned_alloc(len, alignment) orelse return error.OutOfMemory; | |
| 111 | if (len_align == 0) { | |
| 90 | 112 | return ptr[0..len]; |
| 91 | ||
| 113 | } | |
| 92 | 114 | const full_len = init: { |
| 93 | 115 | if (supports_malloc_size) { |
| 94 | const s = malloc_size(ptr); | |
| 116 | const s = aligned_alloc_size(ptr); | |
| 95 | 117 | assert(s >= len); |
| 96 | 118 | break :init s; |
| 97 | 119 | } |
| 98 | 120 | break :init len; |
| 99 | 121 | }; |
| 100 | ||
| 101 | 122 | return ptr[0..mem.alignBackwardAnyAlign(full_len, len_align)]; |
| 102 | 123 | } |
| 103 | 124 | |
| ... | ... | @@ -110,17 +131,14 @@ const CAllocator = struct { |
| 110 | 131 | return_address: usize, |
| 111 | 132 | ) Allocator.Error!usize { |
| 112 | 133 | if (new_len == 0) { |
| 113 | if (buf_align <= min_ptr_alignment) | |
| 114 | c.free(buf.ptr) | |
| 115 | else | |
| 116 | aligned_free(buf.ptr); | |
| 134 | aligned_free(buf.ptr); | |
| 117 | 135 | return 0; |
| 118 | 136 | } |
| 119 | 137 | if (new_len <= buf.len) { |
| 120 | 138 | return mem.alignAllocLen(buf.len, new_len, len_align); |
| 121 | 139 | } |
| 122 | 140 | if (supports_malloc_size) { |
| 123 | const full_len = malloc_size(buf.ptr); | |
| 141 | const full_len = aligned_alloc_size(buf.ptr); | |
| 124 | 142 | if (new_len <= full_len) { |
| 125 | 143 | return mem.alignAllocLen(full_len, new_len, len_align); |
| 126 | 144 | } |