Skip to content

Commit 8c573cf

Browse files
authored
runtime: make free_memory() and total_memory() return Result types to allow for reporting errors (#24651)
1 parent 061da6a commit 8c573cf

File tree

9 files changed

+99
-31
lines changed

9 files changed

+99
-31
lines changed

cmd/tools/vdoctor.v

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,8 +104,8 @@ fn (mut a App) collect_info() {
104104
}
105105
a.line('OS', '${os_kind}, ${os_details}')
106106
a.line('Processor', arch_details.join(', '))
107-
total_memory := f32(runtime.total_memory()) / (1024.0 * 1024.0 * 1024.0)
108-
free_memory := f32(runtime.free_memory()) / (1024.0 * 1024.0 * 1024.0)
107+
total_memory := f32(runtime.total_memory() or { 0 }) / (1024.0 * 1024.0 * 1024.0)
108+
free_memory := f32(runtime.free_memory() or { 0 }) / (1024.0 * 1024.0 * 1024.0)
109109
if total_memory != 0 && free_memory != 0 {
110110
a.line('Memory', '${free_memory:.2}GB/${total_memory:.2}GB')
111111
} else {

vlib/runtime/free_memory_impl_darwin.c.v

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
module runtime
22

33
#include <mach/mach.h>
4+
#include <mach/task.h>
45

56
@[typedef]
67
pub struct C.vm_size_t {
@@ -17,21 +18,46 @@ pub struct C.vm_statistics64_data_t {
1718
@[typedef]
1819
pub struct C.host_t {}
1920

21+
@[typedef]
22+
pub struct C.task_t {}
23+
2024
fn C.mach_host_self() C.host_t
25+
fn C.mach_task_self() C.task_t
26+
fn C.mach_port_deallocate(task C.task_t, host C.host_t) int
2127
fn C.host_page_size(host C.host_t, out_page_size &C.vm_size_t) int
2228
fn C.host_statistics64(host C.host_t, flavor int, host_info_out &int, host_info_outCnt &u32) int
2329

24-
fn free_memory_impl() usize {
30+
fn free_memory_impl() !usize {
2531
$if macos {
2632
mut hs := C.vm_statistics64_data_t{}
2733
mut vmsz := u32(C.HOST_VM_INFO64_COUNT)
2834
mut hps := u32(0)
2935
mut host := C.mach_host_self()
36+
defer {
37+
// Critical: Release send right for host port
38+
// --------------------------------------------------
39+
// Mach ports are system resources. Calling mach_host_self()
40+
// increments the port's reference count. We must manually release
41+
// to prevent resource leaks (port exhaustion can cause kernel failures).
42+
// mach_port_deallocate decrements the reference count, allowing
43+
// system resource reclamation when count reaches zero.
44+
// Parameters:
45+
// C.mach_task_self() - Port for current task
46+
// host - Host port to release
47+
// Return value ignored (_) since we only care about resource cleanup
48+
_ := C.mach_port_deallocate(C.mach_task_self(), host)
49+
}
3050
unsafe {
31-
C.host_statistics64(host, C.HOST_VM_INFO64, &int(&hs), &vmsz)
32-
C.host_page_size(host, &C.vm_size_t(&hps))
51+
retval_1 := C.host_statistics64(host, C.HOST_VM_INFO64, &int(&hs), &vmsz)
52+
if retval_1 != C.KERN_SUCCESS {
53+
return error('free_memory: `C.host_statistics64()` return = ${retval_1}')
54+
}
55+
retval_2 := C.host_page_size(host, &C.vm_size_t(&hps))
56+
if retval_2 != C.KERN_SUCCESS {
57+
return error('free_memory: `C.host_page_size()` return = ${retval_2}')
58+
}
3359
}
3460
return usize(u64(hs.free_count) * u64(hps))
3561
}
36-
return 1
62+
return error('free_memory: not implemented')
3763
}
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
module runtime
22

3-
fn free_memory_impl() usize {
4-
return 1
3+
fn free_memory_impl() !usize {
4+
return error('free_memory: not implemented')
55
}

vlib/runtime/free_memory_impl_freebsd.c.v

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,37 @@ module runtime
22

33
fn C.sysctlnametomib(name charptr, mib &int, len &usize) int
44

5-
fn free_memory_impl() usize {
5+
fn free_memory_impl() !usize {
66
$if cross ? {
7-
return 1
7+
return error('free_memory: not implemented')
88
}
99
$if !cross ? {
1010
$if freebsd {
1111
page_size := usize(C.sysconf(C._SC_PAGESIZE))
12+
c_errno_1 := C.errno
13+
if page_size == usize(-1) {
14+
return error('free_memory: `C.sysconf()` return error code = ${c_errno_1}')
15+
}
1216
mut mib := [4]int{}
1317
mut len := usize(4)
14-
unsafe { C.sysctlnametomib(c'vm.stats.vm.v_free_count', &mib[0], &len) }
18+
retval_2 := unsafe {
19+
C.sysctlnametomib(c'vm.stats.vm.v_free_count', &mib[0], &len)
20+
}
21+
c_errno_2 := C.errno
22+
if retval_2 == -1 {
23+
return error('free_memory: `C.sysctlnametomib()` return error code = ${c_errno_2}')
24+
}
1525
mut free_pages := int(0)
1626
bufsize := usize(4)
17-
unsafe { C.sysctl(&mib[0], mib.len, &free_pages, &bufsize, 0, 0) }
27+
retval_3 := unsafe {
28+
C.sysctl(&mib[0], mib.len, &free_pages, &bufsize, 0, 0)
29+
}
30+
c_errno_3 := C.errno
31+
if retval_3 == -1 {
32+
return error('free_memory: `C.sysctl()` return error code = ${c_errno_3}')
33+
}
1834
return page_size * usize(free_pages)
1935
}
2036
}
21-
return 1
37+
return error('free_memory: not implemented')
2238
}
Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,23 @@
11
module runtime
22

3-
fn free_memory_impl() usize {
3+
fn free_memory_impl() !usize {
44
$if cross ? {
5-
return 1
5+
return error('free_memory: not implemented')
66
}
77
$if !cross ? {
88
$if linux {
99
page_size := usize(C.sysconf(C._SC_PAGESIZE))
10+
c_errno_1 := C.errno
11+
if page_size == usize(-1) {
12+
return error('free_memory: `C.sysconf(C._SC_PAGESIZE)` return error code = ${c_errno_1}')
13+
}
1014
av_phys_pages := usize(C.sysconf(C._SC_AVPHYS_PAGES))
15+
c_errno_2 := C.errno
16+
if av_phys_pages == usize(-1) {
17+
return error('free_memory: `C.sysconf(C._SC_AVPHYS_PAGES)` return error code = ${c_errno_2}')
18+
}
1119
return page_size * av_phys_pages
1220
}
1321
}
14-
return 1
22+
return error('free_memory: not implemented')
1523
}

vlib/runtime/free_memory_impl_openbsd.c.v

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,22 @@ struct C.uvmexp {
88
free int
99
}
1010

11-
fn free_memory_impl() usize {
11+
fn free_memory_impl() !usize {
1212
$if cross ? {
13-
return 1
13+
return error('free_memory: not implemented')
1414
}
1515
$if !cross ? {
1616
$if openbsd {
1717
mib := [C.CTL_VM, C.VM_UVMEXP]!
1818
mut uvm := C.uvmexp{0, 0}
1919
mut len := sizeof(C.uvmexp)
20-
unsafe { C.sysctl(&mib[0], mib.len, &uvm, &len, C.NULL, 0) }
20+
retval := unsafe { C.sysctl(&mib[0], mib.len, &uvm, &len, C.NULL, 0) }
21+
c_errno := C.errno
22+
if retval == -1 {
23+
return error('free_memory: `C.sysctl()` return error code = ${c_errno}')
24+
}
2125
return usize(uvm.pagesize) * usize(uvm.free)
2226
}
2327
}
24-
return 1
28+
return error('free_memory: not implemented')
2529
}

vlib/runtime/runtime_nix.c.v

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,23 @@ pub fn nr_cpus() int {
88
}
99

1010
// total_memory returns total physical memory found on the system.
11-
pub fn total_memory() usize {
11+
pub fn total_memory() !usize {
1212
page_size := usize(C.sysconf(C._SC_PAGESIZE))
13+
c_errno_1 := C.errno
14+
if page_size == usize(-1) {
15+
return error('total_memory: `C.sysconf(C._SC_PAGESIZE)` return error code = ${c_errno_1}')
16+
}
1317
phys_pages := usize(C.sysconf(C._SC_PHYS_PAGES))
18+
c_errno_2 := C.errno
19+
if phys_pages == usize(-1) {
20+
return error('total_memory: `C.sysconf(C._SC_PHYS_PAGES)` return error code = ${c_errno_2}')
21+
}
1422
return page_size * phys_pages
1523
}
1624

1725
// free_memory returns free physical memory found on the system.
1826
// Note: implementation available only on Darwin, FreeBSD, Linux, OpenBSD and
19-
// Windows. Otherwise, returns 1.
20-
pub fn free_memory() usize {
21-
return free_memory_impl()
27+
// Windows. Otherwise, returns 'free_memory: not implemented'.
28+
pub fn free_memory() !usize {
29+
return free_memory_impl()!
2230
}

vlib/runtime/runtime_test.v

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,17 @@
11
import runtime
22

33
fn test_physical_memory() {
4-
total := runtime.total_memory()
5-
free := runtime.free_memory()
6-
println('total memory: ${total}')
7-
println('free memory: ${free}')
8-
assert total > 0 && free > 0
4+
$if windows || linux || darwin || freebsd || openbsd {
5+
total := runtime.total_memory()!
6+
free := runtime.free_memory()!
7+
println('total memory: ${total}')
8+
println('free memory: ${free}')
9+
assert total > 0 && free > 0
10+
} $else {
11+
total := runtime.total_memory()!
12+
_ := runtime.free_memory() or { assert err.msg().contains('not implemented') }
13+
assert total > 0
14+
}
915
}
1016

1117
fn test_nr_cpus() {

vlib/runtime/runtime_windows.c.v

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,14 @@ pub fn nr_cpus() int {
2323
}
2424

2525
// total_memory returns total physical memory found on the system.
26-
pub fn total_memory() usize {
26+
pub fn total_memory() !usize {
2727
memory_status := C.MEMORYSTATUS{}
2828
C.GlobalMemoryStatus(&memory_status)
2929
return memory_status.dwTotalPhys
3030
}
3131

3232
// free_memory returns free physical memory found on the system.
33-
pub fn free_memory() usize {
33+
pub fn free_memory() !usize {
3434
memory_status := C.MEMORYSTATUS{}
3535
C.GlobalMemoryStatus(&memory_status)
3636
return memory_status.dwAvailPhys

0 commit comments

Comments
 (0)