Skip to content

Commit

Permalink
std.os: add sysconf(), getDefaultPageSize() with smoke tests
Browse files Browse the repository at this point in the history
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 ziglang#11308.
  • Loading branch information
matu3ba committed Aug 20, 2023
1 parent a1049d4 commit 1d9095a
Show file tree
Hide file tree
Showing 14 changed files with 127 additions and 8 deletions.
1 change: 1 addition & 0 deletions lib/std/c.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
5 changes: 4 additions & 1 deletion lib/std/c/darwin.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
4 changes: 4 additions & 0 deletions lib/std/c/dragonfly.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
4 changes: 4 additions & 0 deletions lib/std/c/freebsd.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
5 changes: 5 additions & 0 deletions lib/std/c/fuchsia.zig
Original file line number Diff line number Diff line change
@@ -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,
};
Expand Down
4 changes: 4 additions & 0 deletions lib/std/c/haiku.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
4 changes: 4 additions & 0 deletions lib/std/c/hermit.zig
Original file line number Diff line number Diff line change
@@ -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),
};
Expand Down
4 changes: 4 additions & 0 deletions lib/std/c/linux.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
5 changes: 5 additions & 0 deletions lib/std/c/minix.zig
Original file line number Diff line number Diff line change
@@ -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,
};
Expand Down
4 changes: 4 additions & 0 deletions lib/std/c/netbsd.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
4 changes: 4 additions & 0 deletions lib/std/c/openbsd.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
11 changes: 5 additions & 6 deletions lib/std/c/solaris.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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;

Expand Down Expand Up @@ -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,
Expand Down
67 changes: 67 additions & 0 deletions lib/std/os.zig
Original file line number Diff line number Diff line change
Expand Up @@ -4335,6 +4335,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,
Expand Down Expand Up @@ -4680,6 +4721,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,
Expand Down
13 changes: 12 additions & 1 deletion lib/std/os/test.zig
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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,
}
}

0 comments on commit 1d9095a

Please sign in to comment.