Initial project import

This commit is contained in:
Agila Forge Importer committed 2026-07-13 15:20:32 +00:00
commit 23f2d29e32
11957 files changed
+1754577

No files matched your search

+8
View File
@@ -0,0 +1,8 @@
## Description
`runtime` provides access to functions describing the current platform:
- whether it is 32bit or 64bit
- how many CPUs/cores are available
- total/free physical memory
- whether the platform is little endian or big endian
- etc.
@@ -0,0 +1,63 @@
module runtime
#include <mach/mach.h>
#include <mach/task.h>
@[typedef]
pub struct C.vm_size_t {
}
@[typedef]
pub struct C.vm_statistics64_data_t {
free_count u32
purgeable_count u32
speculative_count u32
external_page_count u32
}
@[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) i32
fn C.host_page_size(host C.host_t, out_page_size &C.vm_size_t) i32
fn C.host_statistics64(host C.host_t, flavor i32, host_info_out &int, host_info_outCnt &u32) i32
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 {
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 error('free_memory: not implemented')
}
@@ -0,0 +1,5 @@
module runtime
fn free_memory_impl() !usize {
return error('free_memory: not implemented')
}
@@ -0,0 +1,38 @@
module runtime
fn C.sysctlnametomib(name charptr, mib &int, len &usize) i32
fn free_memory_impl() !usize {
$if cross ? {
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)
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)
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 error('free_memory: not implemented')
}
@@ -0,0 +1,23 @@
module runtime
fn free_memory_impl() !usize {
$if cross ? {
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 error('free_memory: not implemented')
}
@@ -0,0 +1,29 @@
module runtime
#include <sys/sysctl.h>
#include <uvm/uvmexp.h>
struct C.uvmexp {
pagesize int
free int
}
fn free_memory_impl() !usize {
$if cross ? {
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 := usize(sizeof(C.uvmexp))
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 error('free_memory: not implemented')
}
+62
View File
@@ -0,0 +1,62 @@
// Copyright (c) 2019-2024 Alexander Medvednikov. All rights reserved.
// Use of this source code is governed by an MIT license
// that can be found in the LICENSE file.
module runtime
import os
// nr_jobs returns the same as `nr_cpus`, but influenced by the env variable `VJOBS`.
// If the environment variable `VJOBS` is set, and has a value > 0,
// then `nr_jobs` will return that number instead.
// This is useful for runtime tweaking of e.g. threaded or concurrent code.
pub fn nr_jobs() int {
$if cross ? {
// A single thread is *more likely* to work consistently everywhere during bootstrapping.
// NB: the compiler itself uses runtime.nr_jobs() and sync.pool to process things in parallel
// in its cgen stage. Returning 1 here, increases the chances of it working on non linux systems.
return 1
}
mut cpus := nr_cpus()
// allow for overrides, for example using `VJOBS=32 ./v test .`
vjobs := os.getenv('VJOBS').int()
if vjobs > 0 {
cpus = vjobs
}
if cpus == 0 {
return 1
}
return cpus
}
// is_32bit returns true if the current executable is running on a 32 bit system.
pub fn is_32bit() bool {
$if x32 {
return true
}
return false
}
// is_64bit returns true if the current executable is running on a 64 bit system.
pub fn is_64bit() bool {
$if x64 {
return true
}
return false
}
// is_little_endian returns true if the current executable is running on a little-endian system.
pub fn is_little_endian() bool {
$if little_endian {
return true
}
return false
}
// is_big_endian returns true if the current executable is running on a big-endian system.
pub fn is_big_endian() bool {
$if big_endian {
return true
}
return false
}
+35
View File
@@ -0,0 +1,35 @@
module runtime
fn C.sysconf(name i32) i64
// nr_cpus returns the number of virtual CPU cores found on the system.
pub fn nr_cpus() int {
mut cpus := int(C.sysconf(C._SC_NPROCESSORS_ONLN))
if cpus < 1 {
eprintln('Warning: sysconf(_SC_NPROCESSORS_ONLN) returned -1, returning CPU count as 1')
cpus = 1
}
return cpus
}
// total_memory returns total physical memory found on the system.
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 'free_memory: not implemented'.
pub fn free_memory() !usize {
return free_memory_impl()!
}
+91
View File
@@ -0,0 +1,91 @@
import os
import runtime
fn test_physical_memory() {
$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() {
nr_cpus := runtime.nr_cpus()
println(' nr cpus: ${nr_cpus}')
assert nr_cpus > 0
}
fn test_nr_jobs() {
nr_jobs := runtime.nr_jobs()
println(' nr jobs: ${nr_jobs}')
assert nr_jobs > 0
}
fn test_nr_jobs_matches_nr_cpus_without_vjobs() {
env := os.environ()
had_vjobs := 'VJOBS' in env
saved_vjobs := env['VJOBS']
defer {
if had_vjobs {
os.setenv('VJOBS', saved_vjobs, true)
} else {
os.unsetenv('VJOBS')
}
}
os.unsetenv('VJOBS')
assert runtime.nr_jobs() == runtime.nr_cpus()
}
fn test_nr_jobs_uses_vjobs_override() {
env := os.environ()
had_vjobs := 'VJOBS' in env
saved_vjobs := env['VJOBS']
defer {
if had_vjobs {
os.setenv('VJOBS', saved_vjobs, true)
} else {
os.unsetenv('VJOBS')
}
}
expected_jobs := runtime.nr_cpus() + 1
os.setenv('VJOBS', expected_jobs.str(), true)
assert runtime.nr_jobs() == expected_jobs
}
fn test_is_32bit() {
x := runtime.is_32bit().str()
println(' is_32bit: ${x}')
assert x == 'true' || x == 'false'
}
fn test_is_64bit() {
x := runtime.is_64bit().str()
println(' is_64bit: ${x}')
assert x == 'true' || x == 'false'
}
fn test_is_little_endian() {
x := runtime.is_little_endian().str()
println(' is_le: ${x}')
assert x == 'true' || x == 'false'
}
fn test_is_big_endian() {
x := runtime.is_big_endian().str()
println(' is_be: ${x}')
assert x == 'true' || x == 'false'
}
fn test_is_big_endian_different_than_is_little_endian() {
assert runtime.is_big_endian() != runtime.is_little_endian()
}
fn test_is_32bit_different_than_is_64bit() {
assert runtime.is_32bit() != runtime.is_64bit()
}
+36
View File
@@ -0,0 +1,36 @@
module runtime
import os
@[typedef]
pub struct C.MEMORYSTATUS {
dwTotalPhys usize
dwAvailPhys usize
}
fn C.GlobalMemoryStatus(&C.MEMORYSTATUS)
// nr_cpus returns the number of virtual CPU cores found on the system.
pub fn nr_cpus() int {
sinfo := C.SYSTEM_INFO{}
C.GetSystemInfo(&sinfo)
mut nr := int(sinfo.dwNumberOfProcessors)
if nr == 0 {
nr = os.getenv('NUMBER_OF_PROCESSORS').int()
}
return nr
}
// total_memory returns total physical memory found on the system.
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 {
memory_status := C.MEMORYSTATUS{}
C.GlobalMemoryStatus(&memory_status)
return memory_status.dwAvailPhys
}
@@ -0,0 +1,17 @@
module runtime
struct C.task_basic_info {
resident_size u64
}
fn C.task_info(C.task_t, i32, &C.task_basic_info, &u64) i32
// used_memory retrieves the current physical memory usage of the process.
pub fn used_memory() !u64 {
mut info := C.task_basic_info{}
mut count := u64(C.MACH_TASK_BASIC_INFO_COUNT)
if C.task_info(C.mach_task_self(), C.TASK_BASIC_INFO, &info, &count) == C.KERN_SUCCESS {
return info.resident_size
}
return 0
}
@@ -0,0 +1,8 @@
module runtime
// used_memory retrieves the current physical memory usage of the process.
// Note: implementation available only on FreeBSD, macOS, Linux, OpenBSD and
// Windows. Otherwise, returns 'used_memory: not implemented'.
pub fn used_memory() !u64 {
return error('used_memory: not implemented')
}
@@ -0,0 +1,62 @@
module runtime
import os
$if tinyc {
#include <sys/resource.h>
}
struct C.rusage {
ru_maxrss int
ru_idrss int
}
fn C.getrusage(who i32, usage &C.rusage) i32
$if !tinyc {
#flag -lprocstat
#include <sys/user.h>
#include <libprocstat.h>
}
struct C.procstat {}
struct C.kinfo_proc {
ki_rssize u64
}
fn C.procstat_open_sysctl() &C.procstat
fn C.procstat_close(&C.procstat)
fn C.procstat_getprocs(&C.procstat, i32, i32, &u32) &C.kinfo_proc
// used_memory retrieves the current physical memory usage of the process.
pub fn used_memory() !u64 {
page_size := usize(C.sysconf(C._SC_PAGESIZE))
c_errno_1 := C.errno
if page_size == usize(-1) {
return error('used_memory: C.sysconf() return error code = ${c_errno_1}')
}
$if tinyc {
mut usage := C.rusage{}
x := C.getrusage(0, &usage)
if x == -1 {
c_errno_2 := C.errno
return error('used_memory: C.getrusage() return error code = ${c_errno_2}')
}
return u64(int_max(1, usage.ru_maxrss)) * 1024
} $else {
mut proc_status := C.procstat_open_sysctl()
defer {
C.procstat_close(proc_status)
}
mut count := u32(0)
kip := C.procstat_getprocs(proc_status, C.KERN_PROC_PID | C.KERN_PROC_INC_THREAD,
os.getpid(), &count)
if kip != 0 {
return u64(kip.ki_rssize * page_size)
}
}
return 0
}
@@ -0,0 +1,46 @@
module runtime
import os
// used_memory retrieves the current physical memory usage of the process.
@[manualfree]
pub fn used_memory() !u64 {
buffer := [1024]u8{}
pc := unsafe { &buffer[0] }
// see https://man7.org/linux/man-pages/man5/proc_pid_stat.5.html for a detailed description of the format.
// Here is an example:
// 699989 (test_program) R 178038 699989 178038 34816 699989 0 102 0 0 0 0 0 0 0 20 0 1 0 84188763 5726208 129 18446744073709551615 93824992239616 93824992257073 140737488345056 0 0 0 0 0 0 0 0 0 17 0 0 0 0 0 0 93824992275088 93824992276672 93824992280576 140737488346201 140737488346221 140737488346221 140737488351211 0
// => read the file in the fixed buffer, search to after the `)` to skip the variable name part, then scan till the `129` RSS value, and then convert it from pages to bytes.
mut f := os.open_file('/proc/self/stat', 'r')!
defer { f.close() }
read := f.read_into_ptr(pc, buffer.len)!
if read <= 0 {
return error('could not read from /proc/self/stat')
}
mut c := 0
unsafe {
// scan to after the process name (`comm`) field:
for c < buffer.len && *pc != `)` {
pc++
c++
}
mut spaces := 0
// the following fields, are space separated numbers, skip past them to the `rss` field:
for c < buffer.len && spaces < 22 {
if *pc == ` ` {
spaces++
}
pc++
c++
}
mut ndigits := 0
// scan till the end of the `rss` field:
for c < buffer.len && *(pc + ndigits) != ` ` {
ndigits++
c++
}
rss_pages := pc.vstring_with_len(ndigits).u64()
page_size := C.sysconf(C._SC_PAGESIZE)
return u64(rss_pages * page_size)
}
}
@@ -0,0 +1,26 @@
module runtime
#include <sys/resource.h>
struct C.rusage {
ru_maxrss int
}
fn C.getrusage(who i32, usage &C.rusage) i32
// used_memory retrieves the current physical memory usage of the process.
pub fn used_memory() !u64 {
page_size := usize(C.sysconf(C._SC_PAGESIZE))
c_errno_1 := C.errno
if page_size == usize(-1) {
return error('used_memory: C.sysconf() return error code = ${c_errno_1}')
}
mut usage := C.rusage{}
ret := C.getrusage(C.RUSAGE_SELF, &usage)
if ret == -1 {
c_errno_2 := C.errno
return error('used_memory: C.getrusage() return error code = ${c_errno_2}')
}
return u64(int_max(1, usage.ru_maxrss)) * 1024
}
+24
View File
@@ -0,0 +1,24 @@
import runtime
fn test_used_memory() {
used1 := runtime.used_memory()!
println('used memory 1 : ${used1}')
mut mem1 := unsafe { malloc(8 * 1024 * 1024) }
unsafe { vmemset(mem1, 1, 8 * 1024 * 1024) }
used2 := runtime.used_memory()!
println('used memory 2 : ${used2}')
mut mem2 := unsafe { malloc(64 * 1024 * 1024) }
unsafe { vmemset(mem2, 1, 64 * 1024 * 1024) }
used3 := runtime.used_memory()!
println('used memory 3 : ${used3}')
assert used1 > 0
assert used2 >= used1
assert used3 > used2
unsafe {
println(*&u8(mem1 + 1024))
println(*&u8(mem2 + 1024))
}
}
@@ -0,0 +1,32 @@
module runtime
#define PSAPI_VERSION 2
#include <psapi.h>
// Windows 7+ exports K32GetProcessMemoryInfo from kernel32.dll, so avoid
// depending on psapi.lib during bootstrap builds.
@[typedef]
struct C.PROCESS_MEMORY_COUNTERS {
cb u32
PageFaultCount u32
PeakWorkingSetSize usize
WorkingSetSize usize
QuotaPeakPagedPoolUsage usize
QuotaPagedPoolUsage usize
QuotaPeakNonPagedPoolUsage usize
QuotaNonPagedPoolUsage usize
PagefileUsage usize
PeakPagefileUsage usize
}
fn C.K32GetProcessMemoryInfo(voidptr, &C.PROCESS_MEMORY_COUNTERS, u32) bool
// used_memory retrieves the current physical memory usage of the process.
pub fn used_memory() !u64 {
mut pmc := C.PROCESS_MEMORY_COUNTERS{}
pmc.cb = u32(sizeof(pmc))
if C.K32GetProcessMemoryInfo(C.GetCurrentProcess(), &pmc, pmc.cb) {
return u64(pmc.WorkingSetSize)
}
return 0
}