OLD | NEW |
(Empty) | |
| 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 // AIX |
| 37 #elif defined(TUKLIB_PHYSMEM_AIX) |
| 38 # include <sys/systemcfg.h> |
| 39 |
| 40 #elif defined(TUKLIB_PHYSMEM_SYSCONF) |
| 41 # include <unistd.h> |
| 42 |
| 43 #elif defined(TUKLIB_PHYSMEM_SYSCTL) |
| 44 # ifdef HAVE_SYS_PARAM_H |
| 45 # include <sys/param.h> |
| 46 # endif |
| 47 # include <sys/sysctl.h> |
| 48 |
| 49 // Tru64 |
| 50 #elif defined(TUKLIB_PHYSMEM_GETSYSINFO) |
| 51 # include <sys/sysinfo.h> |
| 52 # include <machine/hal_sysinfo.h> |
| 53 |
| 54 // HP-UX |
| 55 #elif defined(TUKLIB_PHYSMEM_PSTAT_GETSTATIC) |
| 56 # include <sys/param.h> |
| 57 # include <sys/pstat.h> |
| 58 |
| 59 // IRIX |
| 60 #elif defined(TUKLIB_PHYSMEM_GETINVENT_R) |
| 61 # include <invent.h> |
| 62 |
| 63 // This sysinfo() is Linux-specific. |
| 64 #elif defined(TUKLIB_PHYSMEM_SYSINFO) |
| 65 # include <sys/sysinfo.h> |
| 66 #endif |
| 67 |
| 68 |
| 69 extern uint64_t |
| 70 tuklib_physmem(void) |
| 71 { |
| 72 uint64_t ret = 0; |
| 73 |
| 74 #if defined(_WIN32) || defined(__CYGWIN__) |
| 75 if ((GetVersion() & 0xFF) >= 5) { |
| 76 // Windows 2000 and later have GlobalMemoryStatusEx() which |
| 77 // supports reporting values greater than 4 GiB. To keep the |
| 78 // code working also on older Windows versions, use |
| 79 // GlobalMemoryStatusEx() conditionally. |
| 80 HMODULE kernel32 = GetModuleHandle("kernel32.dll"); |
| 81 if (kernel32 != NULL) { |
| 82 BOOL (WINAPI *gmse)(LPMEMORYSTATUSEX) = GetProcAddress( |
| 83 kernel32, "GlobalMemoryStatusEx"); |
| 84 if (gmse != NULL) { |
| 85 MEMORYSTATUSEX meminfo; |
| 86 meminfo.dwLength = sizeof(meminfo); |
| 87 if (gmse(&meminfo)) |
| 88 ret = meminfo.ullTotalPhys; |
| 89 } |
| 90 } |
| 91 } |
| 92 |
| 93 if (ret == 0) { |
| 94 // GlobalMemoryStatus() is supported by Windows 95 and later, |
| 95 // so it is fine to link against it unconditionally. Note that |
| 96 // GlobalMemoryStatus() has no return value. |
| 97 MEMORYSTATUS meminfo; |
| 98 meminfo.dwLength = sizeof(meminfo); |
| 99 GlobalMemoryStatus(&meminfo); |
| 100 ret = meminfo.dwTotalPhys; |
| 101 } |
| 102 |
| 103 #elif defined(__OS2__) |
| 104 unsigned long mem; |
| 105 if (DosQuerySysInfo(QSV_TOTPHYSMEM, QSV_TOTPHYSMEM, |
| 106 &mem, sizeof(mem)) == 0) |
| 107 ret = mem; |
| 108 |
| 109 #elif defined(__DJGPP__) |
| 110 __dpmi_free_mem_info meminfo; |
| 111 if (__dpmi_get_free_memory_information(&meminfo) == 0 |
| 112 && meminfo.total_number_of_physical_pages |
| 113 != (unsigned long)-1) |
| 114 ret = (uint64_t)meminfo.total_number_of_physical_pages * 4096; |
| 115 |
| 116 #elif defined(__VMS) |
| 117 int vms_mem; |
| 118 int val = SYI$_MEMSIZE; |
| 119 if (LIB$GETSYI(&val, &vms_mem, 0, 0, 0, 0) == SS$_NORMAL) |
| 120 ret = (uint64_t)vms_mem * 8192; |
| 121 |
| 122 #elif defined(TUKLIB_PHYSMEM_AIX) |
| 123 ret = _system_configuration.physmem; |
| 124 |
| 125 #elif defined(TUKLIB_PHYSMEM_SYSCONF) |
| 126 const long pagesize = sysconf(_SC_PAGESIZE); |
| 127 const long pages = sysconf(_SC_PHYS_PAGES); |
| 128 if (pagesize != -1 && pages != -1) |
| 129 // According to docs, pagesize * pages can overflow. |
| 130 // Simple case is 32-bit box with 4 GiB or more RAM, |
| 131 // which may report exactly 4 GiB of RAM, and "long" |
| 132 // being 32-bit will overflow. Casting to uint64_t |
| 133 // hopefully avoids overflows in the near future. |
| 134 ret = (uint64_t)pagesize * (uint64_t)pages; |
| 135 |
| 136 #elif defined(TUKLIB_PHYSMEM_SYSCTL) |
| 137 int name[2] = { |
| 138 CTL_HW, |
| 139 #ifdef HW_PHYSMEM64 |
| 140 HW_PHYSMEM64 |
| 141 #else |
| 142 HW_PHYSMEM |
| 143 #endif |
| 144 }; |
| 145 union { |
| 146 uint32_t u32; |
| 147 uint64_t u64; |
| 148 } mem; |
| 149 size_t mem_ptr_size = sizeof(mem.u64); |
| 150 if (sysctl(name, 2, &mem.u64, &mem_ptr_size, NULL, 0) != -1) { |
| 151 // IIRC, 64-bit "return value" is possible on some 64-bit |
| 152 // BSD systems even with HW_PHYSMEM (instead of HW_PHYSMEM64), |
| 153 // so support both. |
| 154 if (mem_ptr_size == sizeof(mem.u64)) |
| 155 ret = mem.u64; |
| 156 else if (mem_ptr_size == sizeof(mem.u32)) |
| 157 ret = mem.u32; |
| 158 } |
| 159 |
| 160 #elif defined(TUKLIB_PHYSMEM_GETSYSINFO) |
| 161 // Docs are unclear if "start" is needed, but it doesn't hurt |
| 162 // much to have it. |
| 163 int memkb; |
| 164 int start = 0; |
| 165 if (getsysinfo(GSI_PHYSMEM, (caddr_t)&memkb, sizeof(memkb), &start) |
| 166 != -1) |
| 167 ret = (uint64_t)memkb * 1024; |
| 168 |
| 169 #elif defined(TUKLIB_PHYSMEM_PSTAT_GETSTATIC) |
| 170 struct pst_static pst; |
| 171 if (pstat_getstatic(&pst, sizeof(pst), 1, 0) != -1) |
| 172 ret = (uint64_t)pst.physical_memory * (uint64_t)pst.page_size; |
| 173 |
| 174 #elif defined(TUKLIB_PHYSMEM_GETINVENT_R) |
| 175 inv_state_t *st = NULL; |
| 176 if (setinvent_r(&st) != -1) { |
| 177 inventory_t *i; |
| 178 while ((i = getinvent_r(st)) != NULL) { |
| 179 if (i->inv_class == INV_MEMORY |
| 180 && i->inv_type == INV_MAIN_MB) { |
| 181 ret = (uint64_t)i->inv_state << 20; |
| 182 break; |
| 183 } |
| 184 } |
| 185 |
| 186 endinvent_r(st); |
| 187 } |
| 188 |
| 189 #elif defined(TUKLIB_PHYSMEM_SYSINFO) |
| 190 struct sysinfo si; |
| 191 if (sysinfo(&si) == 0) |
| 192 ret = (uint64_t)si.totalram * si.mem_unit; |
| 193 #endif |
| 194 |
| 195 return ret; |
| 196 } |
OLD | NEW |