From 8c573cf355531bfde029eb912890735f039ef7bf Mon Sep 17 00:00:00 2001 From: kbkpbot Date: Thu, 5 Jun 2025 03:35:49 +0800 Subject: [PATCH] runtime: make free_memory() and total_memory() return Result types to allow for reporting errors (#24651) --- cmd/tools/vdoctor.v | 4 +-- vlib/runtime/free_memory_impl_darwin.c.v | 34 ++++++++++++++++++++--- vlib/runtime/free_memory_impl_default.c.v | 4 +-- vlib/runtime/free_memory_impl_freebsd.c.v | 26 +++++++++++++---- vlib/runtime/free_memory_impl_linux.c.v | 14 ++++++++-- vlib/runtime/free_memory_impl_openbsd.c.v | 12 +++++--- vlib/runtime/runtime_nix.c.v | 16 ++++++++--- vlib/runtime/runtime_test.v | 16 +++++++---- vlib/runtime/runtime_windows.c.v | 4 +-- 9 files changed, 99 insertions(+), 31 deletions(-) diff --git a/cmd/tools/vdoctor.v b/cmd/tools/vdoctor.v index 41c18cbd67..ca09631b22 100644 --- a/cmd/tools/vdoctor.v +++ b/cmd/tools/vdoctor.v @@ -104,8 +104,8 @@ fn (mut a App) collect_info() { } a.line('OS', '${os_kind}, ${os_details}') a.line('Processor', arch_details.join(', ')) - total_memory := f32(runtime.total_memory()) / (1024.0 * 1024.0 * 1024.0) - free_memory := f32(runtime.free_memory()) / (1024.0 * 1024.0 * 1024.0) + total_memory := f32(runtime.total_memory() or { 0 }) / (1024.0 * 1024.0 * 1024.0) + free_memory := f32(runtime.free_memory() or { 0 }) / (1024.0 * 1024.0 * 1024.0) if total_memory != 0 && free_memory != 0 { a.line('Memory', '${free_memory:.2}GB/${total_memory:.2}GB') } else { diff --git a/vlib/runtime/free_memory_impl_darwin.c.v b/vlib/runtime/free_memory_impl_darwin.c.v index 2c926d70ad..ae75b6d65f 100644 --- a/vlib/runtime/free_memory_impl_darwin.c.v +++ b/vlib/runtime/free_memory_impl_darwin.c.v @@ -1,6 +1,7 @@ module runtime #include +#include @[typedef] pub struct C.vm_size_t { @@ -17,21 +18,46 @@ pub struct C.vm_statistics64_data_t { @[typedef] pub struct C.host_t {} +@[typedef] +pub struct C.task_t {} + fn C.mach_host_self() C.host_t +fn C.mach_task_self() C.task_t +fn C.mach_port_deallocate(task C.task_t, host C.host_t) int fn C.host_page_size(host C.host_t, out_page_size &C.vm_size_t) int fn C.host_statistics64(host C.host_t, flavor int, host_info_out &int, host_info_outCnt &u32) int -fn free_memory_impl() usize { +fn free_memory_impl() !usize { $if macos { mut hs := C.vm_statistics64_data_t{} mut vmsz := u32(C.HOST_VM_INFO64_COUNT) mut hps := u32(0) mut host := C.mach_host_self() + defer { + // Critical: Release send right for host port + // -------------------------------------------------- + // Mach ports are system resources. Calling mach_host_self() + // increments the port's reference count. We must manually release + // to prevent resource leaks (port exhaustion can cause kernel failures). + // mach_port_deallocate decrements the reference count, allowing + // system resource reclamation when count reaches zero. + // Parameters: + // C.mach_task_self() - Port for current task + // host - Host port to release + // Return value ignored (_) since we only care about resource cleanup + _ := C.mach_port_deallocate(C.mach_task_self(), host) + } unsafe { - C.host_statistics64(host, C.HOST_VM_INFO64, &int(&hs), &vmsz) - C.host_page_size(host, &C.vm_size_t(&hps)) + retval_1 := C.host_statistics64(host, C.HOST_VM_INFO64, &int(&hs), &vmsz) + if retval_1 != C.KERN_SUCCESS { + return error('free_memory: `C.host_statistics64()` return = ${retval_1}') + } + retval_2 := C.host_page_size(host, &C.vm_size_t(&hps)) + if retval_2 != C.KERN_SUCCESS { + return error('free_memory: `C.host_page_size()` return = ${retval_2}') + } } return usize(u64(hs.free_count) * u64(hps)) } - return 1 + return error('free_memory: not implemented') } diff --git a/vlib/runtime/free_memory_impl_default.c.v b/vlib/runtime/free_memory_impl_default.c.v index eacb8fff16..83da715c4c 100644 --- a/vlib/runtime/free_memory_impl_default.c.v +++ b/vlib/runtime/free_memory_impl_default.c.v @@ -1,5 +1,5 @@ module runtime -fn free_memory_impl() usize { - return 1 +fn free_memory_impl() !usize { + return error('free_memory: not implemented') } diff --git a/vlib/runtime/free_memory_impl_freebsd.c.v b/vlib/runtime/free_memory_impl_freebsd.c.v index 0286e87918..4fea509d16 100644 --- a/vlib/runtime/free_memory_impl_freebsd.c.v +++ b/vlib/runtime/free_memory_impl_freebsd.c.v @@ -2,21 +2,37 @@ module runtime fn C.sysctlnametomib(name charptr, mib &int, len &usize) int -fn free_memory_impl() usize { +fn free_memory_impl() !usize { $if cross ? { - return 1 + return error('free_memory: not implemented') } $if !cross ? { $if freebsd { page_size := usize(C.sysconf(C._SC_PAGESIZE)) + c_errno_1 := C.errno + if page_size == usize(-1) { + return error('free_memory: `C.sysconf()` return error code = ${c_errno_1}') + } mut mib := [4]int{} mut len := usize(4) - unsafe { C.sysctlnametomib(c'vm.stats.vm.v_free_count', &mib[0], &len) } + retval_2 := unsafe { + C.sysctlnametomib(c'vm.stats.vm.v_free_count', &mib[0], &len) + } + c_errno_2 := C.errno + if retval_2 == -1 { + return error('free_memory: `C.sysctlnametomib()` return error code = ${c_errno_2}') + } mut free_pages := int(0) bufsize := usize(4) - unsafe { C.sysctl(&mib[0], mib.len, &free_pages, &bufsize, 0, 0) } + retval_3 := unsafe { + C.sysctl(&mib[0], mib.len, &free_pages, &bufsize, 0, 0) + } + c_errno_3 := C.errno + if retval_3 == -1 { + return error('free_memory: `C.sysctl()` return error code = ${c_errno_3}') + } return page_size * usize(free_pages) } } - return 1 + return error('free_memory: not implemented') } diff --git a/vlib/runtime/free_memory_impl_linux.c.v b/vlib/runtime/free_memory_impl_linux.c.v index fc957531b0..057108b5d6 100644 --- a/vlib/runtime/free_memory_impl_linux.c.v +++ b/vlib/runtime/free_memory_impl_linux.c.v @@ -1,15 +1,23 @@ module runtime -fn free_memory_impl() usize { +fn free_memory_impl() !usize { $if cross ? { - return 1 + return error('free_memory: not implemented') } $if !cross ? { $if linux { page_size := usize(C.sysconf(C._SC_PAGESIZE)) + c_errno_1 := C.errno + if page_size == usize(-1) { + return error('free_memory: `C.sysconf(C._SC_PAGESIZE)` return error code = ${c_errno_1}') + } av_phys_pages := usize(C.sysconf(C._SC_AVPHYS_PAGES)) + c_errno_2 := C.errno + if av_phys_pages == usize(-1) { + return error('free_memory: `C.sysconf(C._SC_AVPHYS_PAGES)` return error code = ${c_errno_2}') + } return page_size * av_phys_pages } } - return 1 + return error('free_memory: not implemented') } diff --git a/vlib/runtime/free_memory_impl_openbsd.c.v b/vlib/runtime/free_memory_impl_openbsd.c.v index 2065110a63..37007e2944 100644 --- a/vlib/runtime/free_memory_impl_openbsd.c.v +++ b/vlib/runtime/free_memory_impl_openbsd.c.v @@ -8,18 +8,22 @@ struct C.uvmexp { free int } -fn free_memory_impl() usize { +fn free_memory_impl() !usize { $if cross ? { - return 1 + return error('free_memory: not implemented') } $if !cross ? { $if openbsd { mib := [C.CTL_VM, C.VM_UVMEXP]! mut uvm := C.uvmexp{0, 0} mut len := sizeof(C.uvmexp) - unsafe { C.sysctl(&mib[0], mib.len, &uvm, &len, C.NULL, 0) } + retval := unsafe { C.sysctl(&mib[0], mib.len, &uvm, &len, C.NULL, 0) } + c_errno := C.errno + if retval == -1 { + return error('free_memory: `C.sysctl()` return error code = ${c_errno}') + } return usize(uvm.pagesize) * usize(uvm.free) } } - return 1 + return error('free_memory: not implemented') } diff --git a/vlib/runtime/runtime_nix.c.v b/vlib/runtime/runtime_nix.c.v index 3891acfe09..8183253015 100644 --- a/vlib/runtime/runtime_nix.c.v +++ b/vlib/runtime/runtime_nix.c.v @@ -8,15 +8,23 @@ pub fn nr_cpus() int { } // total_memory returns total physical memory found on the system. -pub fn total_memory() usize { +pub fn total_memory() !usize { page_size := usize(C.sysconf(C._SC_PAGESIZE)) + c_errno_1 := C.errno + if page_size == usize(-1) { + return error('total_memory: `C.sysconf(C._SC_PAGESIZE)` return error code = ${c_errno_1}') + } phys_pages := usize(C.sysconf(C._SC_PHYS_PAGES)) + c_errno_2 := C.errno + if phys_pages == usize(-1) { + return error('total_memory: `C.sysconf(C._SC_PHYS_PAGES)` return error code = ${c_errno_2}') + } return page_size * phys_pages } // free_memory returns free physical memory found on the system. // Note: implementation available only on Darwin, FreeBSD, Linux, OpenBSD and -// Windows. Otherwise, returns 1. -pub fn free_memory() usize { - return free_memory_impl() +// Windows. Otherwise, returns 'free_memory: not implemented'. +pub fn free_memory() !usize { + return free_memory_impl()! } diff --git a/vlib/runtime/runtime_test.v b/vlib/runtime/runtime_test.v index 347fc5a7fb..01a2f8303a 100644 --- a/vlib/runtime/runtime_test.v +++ b/vlib/runtime/runtime_test.v @@ -1,11 +1,17 @@ import runtime fn test_physical_memory() { - total := runtime.total_memory() - free := runtime.free_memory() - println('total memory: ${total}') - println('free memory: ${free}') - assert total > 0 && free > 0 + $if windows || linux || darwin || freebsd || openbsd { + total := runtime.total_memory()! + free := runtime.free_memory()! + println('total memory: ${total}') + println('free memory: ${free}') + assert total > 0 && free > 0 + } $else { + total := runtime.total_memory()! + _ := runtime.free_memory() or { assert err.msg().contains('not implemented') } + assert total > 0 + } } fn test_nr_cpus() { diff --git a/vlib/runtime/runtime_windows.c.v b/vlib/runtime/runtime_windows.c.v index 6c0912b8f4..37a7a400cc 100644 --- a/vlib/runtime/runtime_windows.c.v +++ b/vlib/runtime/runtime_windows.c.v @@ -23,14 +23,14 @@ pub fn nr_cpus() int { } // total_memory returns total physical memory found on the system. -pub fn total_memory() usize { +pub fn total_memory() !usize { memory_status := C.MEMORYSTATUS{} C.GlobalMemoryStatus(&memory_status) return memory_status.dwTotalPhys } // free_memory returns free physical memory found on the system. -pub fn free_memory() usize { +pub fn free_memory() !usize { memory_status := C.MEMORYSTATUS{} C.GlobalMemoryStatus(&memory_status) return memory_status.dwAvailPhys