tuklib_physmem.c revision 207753
1207753Smm/////////////////////////////////////////////////////////////////////////////// 2207753Smm// 3207753Smm/// \file tuklib_physmem.c 4207753Smm/// \brief Get the amount of physical memory 5207753Smm// 6207753Smm// Author: Lasse Collin 7207753Smm// 8207753Smm// This file has been put into the public domain. 9207753Smm// You can do whatever you want with this file. 10207753Smm// 11207753Smm/////////////////////////////////////////////////////////////////////////////// 12207753Smm 13207753Smm#include "tuklib_physmem.h" 14207753Smm 15207753Smm// We want to use Windows-specific code on Cygwin, which also has memory 16207753Smm// information available via sysconf(), but on Cygwin 1.5 and older it 17207753Smm// gives wrong results (from our point of view). 18207753Smm#if defined(_WIN32) || defined(__CYGWIN__) 19207753Smm# ifndef _WIN32_WINNT 20207753Smm# define _WIN32_WINNT 0x0500 21207753Smm# endif 22207753Smm# include <windows.h> 23207753Smm 24207753Smm#elif defined(__OS2__) 25207753Smm# define INCL_DOSMISC 26207753Smm# include <os2.h> 27207753Smm 28207753Smm#elif defined(__DJGPP__) 29207753Smm# include <dpmi.h> 30207753Smm 31207753Smm#elif defined(__VMS) 32207753Smm# include <lib$routines.h> 33207753Smm# include <syidef.h> 34207753Smm# include <ssdef.h> 35207753Smm 36207753Smm#elif defined(TUKLIB_PHYSMEM_SYSCONF) 37207753Smm# include <unistd.h> 38207753Smm 39207753Smm#elif defined(TUKLIB_PHYSMEM_SYSCTL) 40207753Smm# ifdef HAVE_SYS_PARAM_H 41207753Smm# include <sys/param.h> 42207753Smm# endif 43207753Smm# include <sys/sysctl.h> 44207753Smm 45207753Smm// IRIX 46207753Smm#elif defined(TUKLIB_PHYSMEM_GETINVENT_R) 47207753Smm# include <invent.h> 48207753Smm 49207753Smm// This sysinfo() is Linux-specific. 50207753Smm#elif defined(TUKLIB_PHYSMEM_SYSINFO) 51207753Smm# include <sys/sysinfo.h> 52207753Smm#endif 53207753Smm 54207753Smm 55207753Smmextern uint64_t 56207753Smmtuklib_physmem(void) 57207753Smm{ 58207753Smm uint64_t ret = 0; 59207753Smm 60207753Smm#if defined(_WIN32) || defined(__CYGWIN__) 61207753Smm if ((GetVersion() & 0xFF) >= 5) { 62207753Smm // Windows 2000 and later have GlobalMemoryStatusEx() which 63207753Smm // supports reporting values greater than 4 GiB. To keep the 64207753Smm // code working also on older Windows versions, use 65207753Smm // GlobalMemoryStatusEx() conditionally. 66207753Smm HMODULE kernel32 = GetModuleHandle("kernel32.dll"); 67207753Smm if (kernel32 != NULL) { 68207753Smm BOOL (WINAPI *gmse)(LPMEMORYSTATUSEX) = GetProcAddress( 69207753Smm kernel32, "GlobalMemoryStatusEx"); 70207753Smm if (gmse != NULL) { 71207753Smm MEMORYSTATUSEX meminfo; 72207753Smm meminfo.dwLength = sizeof(meminfo); 73207753Smm if (gmse(&meminfo)) 74207753Smm ret = meminfo.ullTotalPhys; 75207753Smm } 76207753Smm } 77207753Smm } 78207753Smm 79207753Smm if (ret == 0) { 80207753Smm // GlobalMemoryStatus() is supported by Windows 95 and later, 81207753Smm // so it is fine to link against it unconditionally. Note that 82207753Smm // GlobalMemoryStatus() has no return value. 83207753Smm MEMORYSTATUS meminfo; 84207753Smm meminfo.dwLength = sizeof(meminfo); 85207753Smm GlobalMemoryStatus(&meminfo); 86207753Smm ret = meminfo.dwTotalPhys; 87207753Smm } 88207753Smm 89207753Smm#elif defined(__OS2__) 90207753Smm unsigned long mem; 91207753Smm if (DosQuerySysInfo(QSV_TOTPHYSMEM, QSV_TOTPHYSMEM, 92207753Smm &mem, sizeof(mem)) == 0) 93207753Smm ret = mem; 94207753Smm 95207753Smm#elif defined(__DJGPP__) 96207753Smm __dpmi_free_mem_info meminfo; 97207753Smm if (__dpmi_get_free_memory_information(&meminfo) == 0 98207753Smm && meminfo.total_number_of_physical_pages 99207753Smm != (unsigned long)-1) 100207753Smm ret = (uint64_t)meminfo.total_number_of_physical_pages * 4096; 101207753Smm 102207753Smm#elif defined(__VMS) 103207753Smm int vms_mem; 104207753Smm int val = SYI$_MEMSIZE; 105207753Smm if (LIB$GETSYI(&val, &vms_mem, 0, 0, 0, 0) == SS$_NORMAL) 106207753Smm ret = (uint64_t)vms_mem * 8192; 107207753Smm 108207753Smm#elif defined(TUKLIB_PHYSMEM_SYSCONF) 109207753Smm const long pagesize = sysconf(_SC_PAGESIZE); 110207753Smm const long pages = sysconf(_SC_PHYS_PAGES); 111207753Smm if (pagesize != -1 || pages != -1) 112207753Smm // According to docs, pagesize * pages can overflow. 113207753Smm // Simple case is 32-bit box with 4 GiB or more RAM, 114207753Smm // which may report exactly 4 GiB of RAM, and "long" 115207753Smm // being 32-bit will overflow. Casting to uint64_t 116207753Smm // hopefully avoids overflows in the near future. 117207753Smm ret = (uint64_t)pagesize * (uint64_t)pages; 118207753Smm 119207753Smm#elif defined(TUKLIB_PHYSMEM_SYSCTL) 120207753Smm int name[2] = { 121207753Smm CTL_HW, 122207753Smm#ifdef HW_PHYSMEM64 123207753Smm HW_PHYSMEM64 124207753Smm#else 125207753Smm HW_PHYSMEM 126207753Smm#endif 127207753Smm }; 128207753Smm union { 129207753Smm uint32_t u32; 130207753Smm uint64_t u64; 131207753Smm } mem; 132207753Smm size_t mem_ptr_size = sizeof(mem.u64); 133207753Smm if (sysctl(name, 2, &mem.u64, &mem_ptr_size, NULL, 0) != -1) { 134207753Smm // IIRC, 64-bit "return value" is possible on some 64-bit 135207753Smm // BSD systems even with HW_PHYSMEM (instead of HW_PHYSMEM64), 136207753Smm // so support both. 137207753Smm if (mem_ptr_size == sizeof(mem.u64)) 138207753Smm ret = mem.u64; 139207753Smm else if (mem_ptr_size == sizeof(mem.u32)) 140207753Smm ret = mem.u32; 141207753Smm } 142207753Smm 143207753Smm#elif defined(TUKLIB_PHYSMEM_GETINVENT_R) 144207753Smm inv_state_t *st = NULL; 145207753Smm if (setinvent_r(&st) != -1) { 146207753Smm inventory_t *i; 147207753Smm while ((i = getinvent_r(st)) != NULL) { 148207753Smm if (i->inv_class == INV_MEMORY 149207753Smm && i->inv_type == INV_MAIN_MB) { 150207753Smm ret = (uint64_t)i->inv_state << 20; 151207753Smm break; 152207753Smm } 153207753Smm } 154207753Smm 155207753Smm endinvent_r(st); 156207753Smm } 157207753Smm 158207753Smm#elif defined(TUKLIB_PHYSMEM_SYSINFO) 159207753Smm struct sysinfo si; 160207753Smm if (sysinfo(&si) == 0) 161207753Smm ret = (uint64_t)si.totalram * si.mem_unit; 162207753Smm#endif 163207753Smm 164207753Smm return ret; 165207753Smm} 166