@ -41,9 +41,12 @@
# include "drivers/unix/thread_posix.h"
# include "servers/rendering_server.h"
# if def __APPLE__
# if defined(__APPLE__)
# include <mach-o/dyld.h>
# include <mach/host_info.h>
# include <mach/mach_host.h>
# include <mach/mach_time.h>
# include <sys/sysctl.h>
# endif
# if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__)
@ -51,6 +54,19 @@
# include <sys/sysctl.h>
# endif
# if defined(__FreeBSD__)
# include <kvm.h>
# endif
# if defined(__OpenBSD__)
# include <sys/swap.h>
# include <uvm/uvmexp.h>
# endif
# if defined(__NetBSD__)
# include <uvm/uvm_extern.h>
# endif
# include <dlfcn.h>
# include <errno.h>
# include <poll.h>
@ -59,6 +75,7 @@
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <sys/resource.h>
# include <sys/time.h>
# include <sys/wait.h>
# include <time.h>
@ -274,6 +291,192 @@ uint64_t OS_Unix::get_ticks_usec() const {
return longtime ;
}
Dictionary OS_Unix : : get_memory_info ( ) const {
Dictionary meminfo ;
meminfo [ " physical " ] = - 1 ;
meminfo [ " free " ] = - 1 ;
meminfo [ " available " ] = - 1 ;
meminfo [ " stack " ] = - 1 ;
# if defined(__APPLE__)
int pagesize = 0 ;
size_t len = sizeof ( pagesize ) ;
if ( sysctlbyname ( " vm.pagesize " , & pagesize , & len , nullptr , 0 ) < 0 ) {
ERR_PRINT ( vformat ( " Could not get vm.pagesize, error code: %d - %s " , errno , strerror ( errno ) ) ) ;
}
int64_t phy_mem = 0 ;
len = sizeof ( phy_mem ) ;
if ( sysctlbyname ( " hw.memsize " , & phy_mem , & len , nullptr , 0 ) < 0 ) {
ERR_PRINT ( vformat ( " Could not get hw.memsize, error code: %d - %s " , errno , strerror ( errno ) ) ) ;
}
mach_msg_type_number_t count = HOST_VM_INFO64_COUNT ;
vm_statistics64_data_t vmstat ;
if ( host_statistics64 ( mach_host_self ( ) , HOST_VM_INFO64 , ( host_info64_t ) & vmstat , & count ) ! = KERN_SUCCESS ) {
ERR_PRINT ( vformat ( " Could not get host vm statistics. " ) ) ;
}
struct xsw_usage swap_used ;
len = sizeof ( swap_used ) ;
if ( sysctlbyname ( " vm.swapusage " , & swap_used , & len , nullptr , 0 ) < 0 ) {
ERR_PRINT ( vformat ( " Could not get vm.swapusage, error code: %d - %s " , errno , strerror ( errno ) ) ) ;
}
if ( phy_mem ! = 0 ) {
meminfo [ " physical " ] = phy_mem ;
}
if ( vmstat . free_count * ( int64_t ) pagesize ! = 0 ) {
meminfo [ " free " ] = vmstat . free_count * ( int64_t ) pagesize ;
}
if ( swap_used . xsu_avail + vmstat . free_count * ( int64_t ) pagesize ! = 0 ) {
meminfo [ " available " ] = swap_used . xsu_avail + vmstat . free_count * ( int64_t ) pagesize ;
}
# elif defined(__FreeBSD__)
int pagesize = 0 ;
size_t len = sizeof ( pagesize ) ;
if ( sysctlbyname ( " vm.stats.vm.v_page_size " , & pagesize , & len , nullptr , 0 ) < 0 ) {
ERR_PRINT ( vformat ( " Could not get vm.stats.vm.v_page_size, error code: %d - %s " , errno , strerror ( errno ) ) ) ;
}
uint64_t mtotal = 0 ;
len = sizeof ( mtotal ) ;
if ( sysctlbyname ( " vm.stats.vm.v_page_count " , & mtotal , & len , nullptr , 0 ) < 0 ) {
ERR_PRINT ( vformat ( " Could not get vm.stats.vm.v_page_count, error code: %d - %s " , errno , strerror ( errno ) ) ) ;
}
uint64_t mfree = 0 ;
len = sizeof ( mfree ) ;
if ( sysctlbyname ( " vm.stats.vm.v_free_count " , & mfree , & len , nullptr , 0 ) < 0 ) {
ERR_PRINT ( vformat ( " Could not get vm.stats.vm.v_free_count, error code: %d - %s " , errno , strerror ( errno ) ) ) ;
}
uint64_t stotal = 0 ;
uint64_t sused = 0 ;
char errmsg [ _POSIX2_LINE_MAX ] = { } ;
kvm_t * kd = kvm_openfiles ( nullptr , " /dev/null " , nullptr , 0 , errmsg ) ;
if ( kd = = nullptr ) {
ERR_PRINT ( vformat ( " kvm_openfiles failed, error: %s " , errmsg ) ) ;
} else {
struct kvm_swap swap_info [ 32 ] ;
int count = kvm_getswapinfo ( kd , swap_info , 32 , 0 ) ;
for ( int i = 0 ; i < count ; i + + ) {
stotal + = swap_info [ i ] . ksw_total ;
sused + = swap_info [ i ] . ksw_used ;
}
kvm_close ( kd ) ;
}
if ( mtotal * pagesize ! = 0 ) {
meminfo [ " physical " ] = mtotal * pagesize ;
}
if ( mfree * pagesize ! = 0 ) {
meminfo [ " free " ] = mfree * pagesize ;
}
if ( ( mfree + stotal - sused ) * pagesize ! = 0 ) {
meminfo [ " available " ] = ( mfree + stotal - sused ) * pagesize ;
}
# elif defined(__OpenBSD__)
int pagesize = sysconf ( _SC_PAGESIZE ) ;
const int mib [ ] = { CTL_VM , VM_UVMEXP } ;
uvmexp uvmexp_info ;
size_t len = sizeof ( uvmexp_info ) ;
if ( sysctl ( mib , 2 , & uvmexp_info , & len , nullptr , 0 ) < 0 ) {
ERR_PRINT ( vformat ( " Could not get CTL_VM, VM_UVMEXP, error code: %d - %s " , errno , strerror ( errno ) ) ) ;
}
uint64_t stotal = 0 ;
uint64_t sused = 0 ;
int count = swapctl ( SWAP_NSWAP , 0 , 0 ) ;
if ( count > 0 ) {
swapent swap_info [ count ] ;
count = swapctl ( SWAP_STATS , swap_info , count ) ;
for ( int i = 0 ; i < count ; i + + ) {
if ( swap_info [ i ] . se_flags & SWF_ENABLE ) {
sused + = swap_info [ i ] . se_inuse ;
stotal + = swap_info [ i ] . se_nblks ;
}
}
}
if ( uvmexp_info . npages * pagesize ! = 0 ) {
meminfo [ " physical " ] = uvmexp_info . npages * pagesize ;
}
if ( uvmexp_info . free * pagesize ! = 0 ) {
meminfo [ " free " ] = uvmexp_info . free * pagesize ;
}
if ( ( uvmexp_info . free * pagesize ) + ( stotal - sused ) * DEV_BSIZE ! = 0 ) {
meminfo [ " available " ] = ( uvmexp_info . free * pagesize ) + ( stotal - sused ) * DEV_BSIZE ;
}
# elif defined(__NetBSD__)
int pagesize = sysconf ( _SC_PAGESIZE ) ;
const int mib [ ] = { CTL_VM , VM_UVMEXP2 } ;
uvmexp_sysctl uvmexp_info ;
size_t len = sizeof ( uvmexp_info ) ;
if ( sysctl ( mib , 2 , & uvmexp_info , & len , nullptr , 0 ) < 0 ) {
ERR_PRINT ( vformat ( " Could not get CTL_VM, VM_UVMEXP2, error code: %d - %s " , errno , strerror ( errno ) ) ) ;
}
if ( uvmexp_info . npages * pagesize ! = 0 ) {
meminfo [ " physical " ] = uvmexp_info . npages * pagesize ;
}
if ( uvmexp_info . free * pagesize ! = 0 ) {
meminfo [ " free " ] = uvmexp_info . free * pagesize ;
}
if ( ( uvmexp_info . free + uvmexp_info . swpages - uvmexp_info . swpginuse ) * pagesize ! = 0 ) {
meminfo [ " available " ] = ( uvmexp_info . free + uvmexp_info . swpages - uvmexp_info . swpginuse ) * pagesize ;
}
# else
Error err ;
Ref < FileAccess > f = FileAccess : : open ( " /proc/meminfo " , FileAccess : : READ , & err ) ;
uint64_t mtotal = 0 ;
uint64_t mfree = 0 ;
uint64_t sfree = 0 ;
while ( f . is_valid ( ) & & ! f - > eof_reached ( ) ) {
String s = f - > get_line ( ) . strip_edges ( ) ;
if ( s . begins_with ( " MemTotal: " ) ) {
Vector < String > stok = s . replace ( " MemTotal: " , " " ) . strip_edges ( ) . split ( " " ) ;
if ( stok . size ( ) = = 2 ) {
mtotal = stok [ 0 ] . to_int ( ) * 1024 ;
}
}
if ( s . begins_with ( " MemFree: " ) ) {
Vector < String > stok = s . replace ( " MemFree: " , " " ) . strip_edges ( ) . split ( " " ) ;
if ( stok . size ( ) = = 2 ) {
mfree = stok [ 0 ] . to_int ( ) * 1024 ;
}
}
if ( s . begins_with ( " SwapFree: " ) ) {
Vector < String > stok = s . replace ( " SwapFree: " , " " ) . strip_edges ( ) . split ( " " ) ;
if ( stok . size ( ) = = 2 ) {
sfree = stok [ 0 ] . to_int ( ) * 1024 ;
}
}
}
if ( mtotal ! = 0 ) {
meminfo [ " physical " ] = mtotal ;
}
if ( mfree ! = 0 ) {
meminfo [ " free " ] = mfree ;
}
if ( mfree + sfree ! = 0 ) {
meminfo [ " available " ] = mfree + sfree ;
}
# endif
rlimit stackinfo = { } ;
getrlimit ( RLIMIT_STACK , & stackinfo ) ;
if ( stackinfo . rlim_cur ! = 0 ) {
meminfo [ " stack " ] = ( int64_t ) stackinfo . rlim_cur ;
}
return meminfo ;
}
Error OS_Unix : : execute ( const String & p_path , const List < String > & p_arguments , String * r_pipe , int * r_exitcode , bool read_stderr , Mutex * p_pipe_mutex , bool p_open_console ) {
# ifdef __EMSCRIPTEN__
// Don't compile this code at all to avoid undefined references.