From b7481103787ee8521c6dc27db238ab564d56ebe7 Mon Sep 17 00:00:00 2001 From: Jan Philipp Hafer Date: Tue, 1 Aug 2023 01:39:42 +0200 Subject: [PATCH 1/3] std.os: add sysconf(), getDefaultPageSize() with smoke tests sysconf() abstracts posix sysconf for comptime- and runtime probing. getDefaultPageSize() reads the Kernel provided default page size, which remains constant from program start to end. Reproduce added abi bits with: git clone --depth=1 https://github.com/DragonFlyBSD/DragonFlyBSD git clone --depth=1 https://git.FreeBSD.org/src.git freebsd git clone --depth=1 https://fuchsia.googlesource.com/fuchsia git clone --depth=1 https://github.com/haiku/haiku git clone --depth=1 https://github.com/Stichting-MINIX-Research-Foundation/minix/ git clone --depth=1 https://github.com/NetBSD/src netbsd git clone --depth=1 https://github.com/openbsd/src openbsd git clone --depth=1 https://github.com/kofemann/opensolaris git clone --depth=1 https://github.com/apple-open-source-mirror/Libc rg 'define.*_SC_PAGE_SIZE' -B 1 --vimgrep Closes #11308. --- lib/std/c.zig | 1 + lib/std/c/darwin.zig | 5 ++- lib/std/c/dragonfly.zig | 4 +++ lib/std/c/freebsd.zig | 4 +++ lib/std/c/fuchsia.zig | 5 +++ lib/std/c/haiku.zig | 4 +++ lib/std/c/hermit.zig | 4 +++ lib/std/c/linux.zig | 4 +++ lib/std/c/minix.zig | 5 +++ lib/std/c/netbsd.zig | 4 +++ lib/std/c/openbsd.zig | 4 +++ lib/std/c/solaris.zig | 11 +++---- lib/std/os.zig | 67 +++++++++++++++++++++++++++++++++++++++++ lib/std/os/test.zig | 13 +++++++- 14 files changed, 127 insertions(+), 8 deletions(-) diff --git a/lib/std/c.zig b/lib/std/c.zig index 66875eadd034..32157b3611b4 100644 --- a/lib/std/c.zig +++ b/lib/std/c.zig @@ -78,6 +78,7 @@ pub usingnamespace switch (builtin.os.tag) { pub extern "c" fn getrusage(who: c_int, usage: *c.rusage) c_int; + pub extern "c" fn sysconf(sc: c_int) c_long; pub extern "c" fn sched_yield() c_int; pub extern "c" fn sigaction(sig: c_int, noalias act: ?*const c.Sigaction, noalias oact: ?*c.Sigaction) c_int; diff --git a/lib/std/c/darwin.zig b/lib/std/c/darwin.zig index fa121c49c527..39270a40f466 100644 --- a/lib/std/c/darwin.zig +++ b/lib/std/c/darwin.zig @@ -233,6 +233,9 @@ pub const mach_header_64 = macho.mach_header_64; pub const mach_header = macho.mach_header; pub const _errno = __error; +pub const _SC = struct { + pub const PAGESIZE = 29; +}; pub extern "c" fn @"close$NOCANCEL"(fd: fd_t) c_int; pub extern "c" fn mach_host_self() mach_port_t; @@ -3691,7 +3694,7 @@ pub const MachTask = extern struct { return left; } - fn getPageSize(task: MachTask) MachError!usize { + pub fn getPageSize(task: MachTask) MachError!usize { if (task.isValid()) { var info_count = TASK_VM_INFO_COUNT; var vm_info: task_vm_info_data_t = undefined; diff --git a/lib/std/c/dragonfly.zig b/lib/std/c/dragonfly.zig index 15a5f7ef0482..ae3509fa93b4 100644 --- a/lib/std/c/dragonfly.zig +++ b/lib/std/c/dragonfly.zig @@ -9,6 +9,10 @@ pub fn _errno() *c_int { return &errno; } +pub const _SC = struct { + pub const PAGESIZE = 47; +}; + pub extern "c" fn getdents(fd: c_int, buf_ptr: [*]u8, nbytes: usize) c_int; pub extern "c" fn sigaltstack(ss: ?*stack_t, old_ss: ?*stack_t) c_int; pub extern "c" fn getrandom(buf_ptr: [*]u8, buf_len: usize, flags: c_uint) isize; diff --git a/lib/std/c/freebsd.zig b/lib/std/c/freebsd.zig index 6a8997bedf99..11bf39339888 100644 --- a/lib/std/c/freebsd.zig +++ b/lib/std/c/freebsd.zig @@ -8,6 +8,10 @@ const iovec_const = std.os.iovec_const; extern "c" fn __error() *c_int; pub const _errno = __error; +pub const _SC = struct { + pub const PAGESIZE = 47; +}; + pub extern "c" fn getdents(fd: c_int, buf_ptr: [*]u8, nbytes: usize) isize; pub extern "c" fn sigaltstack(ss: ?*stack_t, old_ss: ?*stack_t) c_int; pub extern "c" fn getrandom(buf_ptr: [*]u8, buf_len: usize, flags: c_uint) isize; diff --git a/lib/std/c/fuchsia.zig b/lib/std/c/fuchsia.zig index af6c4756b9ee..eb5763bcafee 100644 --- a/lib/std/c/fuchsia.zig +++ b/lib/std/c/fuchsia.zig @@ -1,3 +1,8 @@ +// third party ulib musl +pub const _SC = struct { + pub const PAGESIZE = 30; +}; + pub const pthread_mutex_t = extern struct { size: [__SIZEOF_PTHREAD_MUTEX_T]u8 align(@alignOf(usize)) = [_]u8{0} ** __SIZEOF_PTHREAD_MUTEX_T, }; diff --git a/lib/std/c/haiku.zig b/lib/std/c/haiku.zig index a64eb03b419f..6276199ff050 100644 --- a/lib/std/c/haiku.zig +++ b/lib/std/c/haiku.zig @@ -9,6 +9,10 @@ extern "c" fn _errnop() *c_int; pub const _errno = _errnop; +pub const _SC = struct { + pub const PAGESIZE = 27; +}; + pub extern "c" fn find_directory(which: c_int, volume: i32, createIt: bool, path_ptr: [*]u8, length: i32) u64; pub extern "c" fn find_thread(thread_name: ?*anyopaque) i32; diff --git a/lib/std/c/hermit.zig b/lib/std/c/hermit.zig index 879346ba13d7..088cf0689f5f 100644 --- a/lib/std/c/hermit.zig +++ b/lib/std/c/hermit.zig @@ -1,6 +1,10 @@ const std = @import("std"); const maxInt = std.math.maxInt; +// pub const _SC = struct { +// pub const PAGESIZE = TODO; +// }; + pub const pthread_mutex_t = extern struct { inner: usize = ~@as(usize, 0), }; diff --git a/lib/std/c/linux.zig b/lib/std/c/linux.zig index c4986101dfad..33c3b7509171 100644 --- a/lib/std/c/linux.zig +++ b/lib/std/c/linux.zig @@ -105,6 +105,10 @@ pub const user_desc = linux.user_desc; pub const utsname = linux.utsname; pub const PR = linux.PR; +pub const _SC = struct { + pub const PAGESIZE = 30; +}; + pub const _errno = switch (native_abi) { .android => struct { extern fn __errno() *c_int; diff --git a/lib/std/c/minix.zig b/lib/std/c/minix.zig index 62cefc14fb57..fa9e0742d828 100644 --- a/lib/std/c/minix.zig +++ b/lib/std/c/minix.zig @@ -1,4 +1,9 @@ const builtin = @import("builtin"); + +pub const _SC = struct { + pub const PAGESIZE = 28; +}; + pub const pthread_mutex_t = extern struct { size: [__SIZEOF_PTHREAD_MUTEX_T]u8 align(@alignOf(usize)) = [_]u8{0} ** __SIZEOF_PTHREAD_MUTEX_T, }; diff --git a/lib/std/c/netbsd.zig b/lib/std/c/netbsd.zig index 23803144296a..11a198df4518 100644 --- a/lib/std/c/netbsd.zig +++ b/lib/std/c/netbsd.zig @@ -10,6 +10,10 @@ const rusage = std.c.rusage; extern "c" fn __errno() *c_int; pub const _errno = __errno; +pub const _SC = struct { + pub const PAGESIZE = 28; +}; + pub const dl_iterate_phdr_callback = *const fn (info: *dl_phdr_info, size: usize, data: ?*anyopaque) callconv(.C) c_int; pub extern "c" fn dl_iterate_phdr(callback: dl_iterate_phdr_callback, data: ?*anyopaque) c_int; diff --git a/lib/std/c/openbsd.zig b/lib/std/c/openbsd.zig index 33a60df95428..e341ad81d584 100644 --- a/lib/std/c/openbsd.zig +++ b/lib/std/c/openbsd.zig @@ -8,6 +8,10 @@ const iovec_const = std.os.iovec_const; extern "c" fn __errno() *c_int; pub const _errno = __errno; +pub const _SC = struct { + pub const PAGESIZE = 28; +}; + pub const dl_iterate_phdr_callback = *const fn (info: *dl_phdr_info, size: usize, data: ?*anyopaque) callconv(.C) c_int; pub extern "c" fn dl_iterate_phdr(callback: dl_iterate_phdr_callback, data: ?*anyopaque) c_int; diff --git a/lib/std/c/solaris.zig b/lib/std/c/solaris.zig index 58d02416cbdb..b42322ef3b39 100644 --- a/lib/std/c/solaris.zig +++ b/lib/std/c/solaris.zig @@ -9,6 +9,11 @@ const timezone = std.c.timezone; extern "c" fn ___errno() *c_int; pub const _errno = ___errno; +pub const _SC = struct { + pub const PAGESIZE = 11; + pub const NPROCESSORS_ONLN = 15; +}; + pub const dl_iterate_phdr_callback = *const fn (info: *dl_phdr_info, size: usize, data: ?*anyopaque) callconv(.C) c_int; pub extern "c" fn dl_iterate_phdr(callback: dl_iterate_phdr_callback, data: ?*anyopaque) c_int; @@ -17,7 +22,6 @@ pub extern "c" fn sigaltstack(ss: ?*stack_t, old_ss: ?*stack_t) c_int; pub extern "c" fn pipe2(fds: *[2]fd_t, flags: u32) c_int; pub extern "c" fn arc4random_buf(buf: [*]u8, len: usize) void; pub extern "c" fn posix_memalign(memptr: *?*anyopaque, alignment: usize, size: usize) c_int; -pub extern "c" fn sysconf(sc: c_int) i64; pub extern "c" fn signalfd(fd: fd_t, mask: *const sigset_t, flags: u32) c_int; pub extern "c" fn madvise(address: [*]u8, len: usize, advise: u32) c_int; @@ -1684,11 +1688,6 @@ pub const AF_SUN = struct { pub const NOPLM = 0x00000004; }; -// TODO: Add sysconf numbers when the other OSs do. -pub const _SC = struct { - pub const NPROCESSORS_ONLN = 15; -}; - pub const procfs = struct { pub const misc_header = extern struct { size: u32, diff --git a/lib/std/os.zig b/lib/std/os.zig index f2b2393b541d..178f704de095 100644 --- a/lib/std/os.zig +++ b/lib/std/os.zig @@ -4337,6 +4337,47 @@ pub fn fork() ForkError!pid_t { } } +/// Returns page size assigned by the Kernel to the process. This size is +/// constant during process lifetime, but other page sizes might be usable. +pub fn getDefaultPageSize() error{UnknownPageSize}!usize { + switch (builtin.cpu.arch) { // archs with fixed size page size + .wasm32, .wasm64 => return 64 * 1024, + else => {}, + } + + switch (builtin.os.tag) { // kernel chooses the page size + .linux => { + if (builtin.link_libc) { + return sysconf(std.c._SC.PAGESIZE) catch return error.UnknownPageSize; + } else { + return linux.getauxval(std.elf.AT_PAGESZ); + } + }, + .windows => { + var sbi: std.os.windows.SYSTEM_BASIC_INFORMATION = undefined; + const rc = std.os.windows.ntdll.NtQuerySystemInformation( + .SystemBasicInformation, + &sbi, + @sizeOf(std.os.windows.SYSTEM_BASIC_INFORMATION), + null, + ); + if (rc != .SUCCESS) { + return error.UnknownPageSize; + } + return sbi.PageSize; + }, + // zig fmt: off + .dragonfly, .freebsd, .fuchsia, .haiku, + .macos, .ios, .watchos, .tvos, + .minix, .netbsd, .openbsd, .solaris, => { + return sysconf(std.c._SC.PAGESIZE) catch return error.UnknownPageSize; + }, + // zig fmt: on + // TODO .hermit (no reliable page size and api yet) + else => unreachable, + } +} + pub const MMapError = error{ /// The underlying filesystem of the specified file does not support memory mapping. MemoryMappingNotSupported, @@ -4682,6 +4723,32 @@ pub fn pipe2(flags: u32) PipeError![2]fd_t { return fds; } +pub const SysConfError = error{ + NoLimit, + InvalidName, // To probe compiletime or runtime support +} || UnexpectedError; + +pub fn sysconf(sc: c_int) SysConfError!usize { + const limit: isize = std.c.sysconf(sc); + const is_minus_one = @clz(limit) == 0; // -1 only possible negative value <=> clz(-1) == 0 + const is_inval = isinval: { + switch (errno(limit)) { + .SUCCESS => break :isinval false, + .INVAL => break :isinval true, + else => |err| return unexpectedErrno(err), + } + }; + const choice: u8 = 0; + choice += @intFromBool(is_minus_one); + choice += @intFromBool(is_inval); + switch (choice) { + 0 => return @bitCast(limit), + 1 => return error.NoLimit, // sysconf -1, errno not set + 2 => return error.InvalidName, // sysconf -1, errno EINVAL + else => unreachable, + } +} + pub const SysCtlError = error{ PermissionDenied, SystemResources, diff --git a/lib/std/os/test.zig b/lib/std/os/test.zig index b9ea4f2e2df4..f71fcf58bc7e 100644 --- a/lib/std/os/test.zig +++ b/lib/std/os/test.zig @@ -1,4 +1,4 @@ -const std = @import("../std.zig"); +const std = @import("std"); const os = std.os; const testing = std.testing; const expect = testing.expect; @@ -1219,3 +1219,14 @@ test "fchmodat smoke test" { const st = try os.fstatat(tmp.dir.fd, "foo.txt", 0); try expectEqual(@as(os.mode_t, 0o755), st.mode & 0b111_111_111); } + +test "getDefaultPageSize smoke test" { + const page_size = try os.getDefaultPageSize(); + switch (page_size) { + // zig fmt: off + 1024, 2048, 4096, 8192, 16384, 32768, // 1, 2, 4, 8, 16, 32KB + 2097152, 4194304 => {}, // 2, 4MB + // zig fmt: on + else => return error.InvalidDefaultPageSize, + } +} From 587d3bd33f454e79d156a2d38009d4a21dc7944e Mon Sep 17 00:00:00 2001 From: Jan Philipp Hafer Date: Mon, 21 Aug 2023 16:14:14 +0200 Subject: [PATCH 2/3] const choice -> var choice --- lib/std/os.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/std/os.zig b/lib/std/os.zig index 178f704de095..fbb08e9d5628 100644 --- a/lib/std/os.zig +++ b/lib/std/os.zig @@ -4738,7 +4738,7 @@ pub fn sysconf(sc: c_int) SysConfError!usize { else => |err| return unexpectedErrno(err), } }; - const choice: u8 = 0; + var choice: u8 = 0; choice += @intFromBool(is_minus_one); choice += @intFromBool(is_inval); switch (choice) { From 5f11466f363bf0a6ea75e2d7345c672a0ee329f5 Mon Sep 17 00:00:00 2001 From: Jan Philipp Hafer Date: Wed, 23 Aug 2023 01:36:45 +0200 Subject: [PATCH 3/3] expect wasm32 to have 64KB page size --- lib/std/os/test.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/std/os/test.zig b/lib/std/os/test.zig index f71fcf58bc7e..a6a03c89065f 100644 --- a/lib/std/os/test.zig +++ b/lib/std/os/test.zig @@ -1224,7 +1224,7 @@ test "getDefaultPageSize smoke test" { const page_size = try os.getDefaultPageSize(); switch (page_size) { // zig fmt: off - 1024, 2048, 4096, 8192, 16384, 32768, // 1, 2, 4, 8, 16, 32KB + 1024, 2048, 4096, 8192, 16384, 32768, 65536, // 1, 2, 4, 8, 16, 32, 64KB 2097152, 4194304 => {}, // 2, 4MB // zig fmt: on else => return error.InvalidDefaultPageSize,