1 /////////////////////////////////////////////////////////////////////////////// 2 // 3 /// \file tuklib_physmem.c 4 /// \brief Get the amount of physical memory 5 // 6 // Author: Lasse Collin 7 // 8 // This file has been put into the public domain. 9 // You can do whatever you want with this file. 10 // 11 /////////////////////////////////////////////////////////////////////////////// 12 13 #include "tuklib_physmem.h" 14 15 // We want to use Windows-specific code on Cygwin, which also has memory 16 // information available via sysconf(), but on Cygwin 1.5 and older it 17 // gives wrong results (from our point of view). 18 #if defined(_WIN32) || defined(__CYGWIN__) 19 # ifndef _WIN32_WINNT 20 # define _WIN32_WINNT 0x0500 21 # endif 22 # include <windows.h> 23 24 #elif defined(__OS2__) 25 # define INCL_DOSMISC 26 # include <os2.h> 27 28 #elif defined(__DJGPP__) 29 # include <dpmi.h> 30 31 #elif defined(__VMS) 32 # include <lib$routines.h> 33 # include <syidef.h> 34 # include <ssdef.h> 35 36 #elif defined(TUKLIB_PHYSMEM_SYSCONF) 37 # include <unistd.h> 38 39 #elif defined(TUKLIB_PHYSMEM_SYSCTL) 40 # ifdef HAVE_SYS_PARAM_H 41 # include <sys/param.h> 42 # endif 43 # include <sys/sysctl.h> 44 45 // IRIX 46 #elif defined(TUKLIB_PHYSMEM_GETINVENT_R) 47 # include <invent.h> 48 49 // This sysinfo() is Linux-specific. 50 #elif defined(TUKLIB_PHYSMEM_SYSINFO) 51 # include <sys/sysinfo.h> 52 #endif 53 54 55 extern uint64_t 56 tuklib_physmem(void) 57 { 58 uint64_t ret = 0; 59 60 #if defined(_WIN32) || defined(__CYGWIN__) 61 if ((GetVersion() & 0xFF) >= 5) { 62 // Windows 2000 and later have GlobalMemoryStatusEx() which 63 // supports reporting values greater than 4 GiB. To keep the 64 // code working also on older Windows versions, use 65 // GlobalMemoryStatusEx() conditionally. 66 HMODULE kernel32 = GetModuleHandle("kernel32.dll"); 67 if (kernel32 != NULL) { 68 BOOL (WINAPI *gmse)(LPMEMORYSTATUSEX) = GetProcAddress( 69 kernel32, "GlobalMemoryStatusEx"); 70 if (gmse != NULL) { 71 MEMORYSTATUSEX meminfo; 72 meminfo.dwLength = sizeof(meminfo); 73 if (gmse(&meminfo)) 74 ret = meminfo.ullTotalPhys; 75 } 76 } 77 } 78 79 if (ret == 0) { 80 // GlobalMemoryStatus() is supported by Windows 95 and later, 81 // so it is fine to link against it unconditionally. Note that 82 // GlobalMemoryStatus() has no return value. 83 MEMORYSTATUS meminfo; 84 meminfo.dwLength = sizeof(meminfo); 85 GlobalMemoryStatus(&meminfo); 86 ret = meminfo.dwTotalPhys; 87 } 88 89 #elif defined(__OS2__) 90 unsigned long mem; 91 if (DosQuerySysInfo(QSV_TOTPHYSMEM, QSV_TOTPHYSMEM, 92 &mem, sizeof(mem)) == 0) 93 ret = mem; 94 95 #elif defined(__DJGPP__) 96 __dpmi_free_mem_info meminfo; 97 if (__dpmi_get_free_memory_information(&meminfo) == 0 98 && meminfo.total_number_of_physical_pages 99 != (unsigned long)-1) 100 ret = (uint64_t)meminfo.total_number_of_physical_pages * 4096; 101 102 #elif defined(__VMS) 103 int vms_mem; 104 int val = SYI$_MEMSIZE; 105 if (LIB$GETSYI(&val, &vms_mem, 0, 0, 0, 0) == SS$_NORMAL) 106 ret = (uint64_t)vms_mem * 8192; 107 108 #elif defined(TUKLIB_PHYSMEM_SYSCONF) 109 const long pagesize = sysconf(_SC_PAGESIZE); 110 const long pages = sysconf(_SC_PHYS_PAGES); 111 if (pagesize != -1 || pages != -1) 112 // According to docs, pagesize * pages can overflow. 113 // Simple case is 32-bit box with 4 GiB or more RAM, 114 // which may report exactly 4 GiB of RAM, and "long" 115 // being 32-bit will overflow. Casting to uint64_t 116 // hopefully avoids overflows in the near future. 117 ret = (uint64_t)pagesize * (uint64_t)pages; 118 119 #elif defined(TUKLIB_PHYSMEM_SYSCTL) 120 int name[2] = { 121 CTL_HW, 122 #ifdef HW_PHYSMEM64 123 HW_PHYSMEM64 124 #else 125 HW_PHYSMEM 126 #endif 127 }; 128 union { 129 uint32_t u32; 130 uint64_t u64; 131 } mem; 132 size_t mem_ptr_size = sizeof(mem.u64); 133 if (sysctl(name, 2, &mem.u64, &mem_ptr_size, NULL, 0) != -1) { 134 // IIRC, 64-bit "return value" is possible on some 64-bit 135 // BSD systems even with HW_PHYSMEM (instead of HW_PHYSMEM64), 136 // so support both. 137 if (mem_ptr_size == sizeof(mem.u64)) 138 ret = mem.u64; 139 else if (mem_ptr_size == sizeof(mem.u32)) 140 ret = mem.u32; 141 } 142 143 #elif defined(TUKLIB_PHYSMEM_GETINVENT_R) 144 inv_state_t *st = NULL; 145 if (setinvent_r(&st) != -1) { 146 inventory_t *i; 147 while ((i = getinvent_r(st)) != NULL) { 148 if (i->inv_class == INV_MEMORY 149 && i->inv_type == INV_MAIN_MB) { 150 ret = (uint64_t)i->inv_state << 20; 151 break; 152 } 153 } 154 155 endinvent_r(st); 156 } 157 158 #elif defined(TUKLIB_PHYSMEM_SYSINFO) 159 struct sysinfo si; 160 if (sysinfo(&si) == 0) 161 ret = (uint64_t)si.totalram * si.mem_unit; 162 #endif 163 164 return ret; 165 } 166