| /////////////////////////////////////////////////////////////////////////////// |
| // |
| /// \file physmem.h |
| /// \brief Get the amount of physical memory |
| // |
| // Author: Lasse Collin |
| // |
| // This file has been put into the public domain. |
| // You can do whatever you want with this file. |
| // |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| #ifndef PHYSMEM_H |
| #define PHYSMEM_H |
| |
| #if defined(HAVE_PHYSMEM_SYSCONF) |
| # include <unistd.h> |
| |
| #elif defined(HAVE_PHYSMEM_SYSCTL) |
| # ifdef HAVE_SYS_PARAM_H |
| # include <sys/param.h> |
| # endif |
| # ifdef HAVE_SYS_SYSCTL_H |
| # include <sys/sysctl.h> |
| # endif |
| |
| #elif defined(HAVE_PHYSMEM_SYSINFO) |
| # include <sys/sysinfo.h> |
| |
| #elif defined(_WIN32) |
| # ifndef _WIN32_WINNT |
| # define _WIN32_WINNT 0x0500 |
| # endif |
| # include <windows.h> |
| |
| #elif defined(__DJGPP__) |
| # include <dpmi.h> |
| #endif |
| |
| |
| /// \brief Get the amount of physical memory in bytes |
| /// |
| /// \return Amount of physical memory in bytes. On error, zero is |
| /// returned. |
| static inline uint64_t |
| physmem(void) |
| { |
| uint64_t ret = 0; |
| |
| #if defined(HAVE_PHYSMEM_SYSCONF) |
| const long pagesize = sysconf(_SC_PAGESIZE); |
| const long pages = sysconf(_SC_PHYS_PAGES); |
| if (pagesize != -1 || pages != -1) |
| // According to docs, pagesize * pages can overflow. |
| // Simple case is 32-bit box with 4 GiB or more RAM, |
| // which may report exactly 4 GiB of RAM, and "long" |
| // being 32-bit will overflow. Casting to uint64_t |
| // hopefully avoids overflows in the near future. |
| ret = (uint64_t)(pagesize) * (uint64_t)(pages); |
| |
| #elif defined(HAVE_PHYSMEM_SYSCTL) |
| int name[2] = { CTL_HW, HW_PHYSMEM }; |
| union { |
| unsigned long ul; |
| unsigned int ui; |
| } mem; |
| size_t mem_ptr_size = sizeof(mem.ul); |
| if (!sysctl(name, 2, &mem.ul, &mem_ptr_size, NULL, NULL)) { |
| // Some systems use unsigned int as the "return value". |
| // This makes a difference on 64-bit boxes. |
| if (mem_ptr_size == sizeof(mem.ul)) |
| ret = mem.ul; |
| else if (mem_ptr_size == sizeof(mem.ui)) |
| ret = mem.ui; |
| } |
| |
| #elif defined(HAVE_PHYSMEM_SYSINFO) |
| struct sysinfo si; |
| if (sysinfo(&si) == 0) |
| ret = (uint64_t)(si.totalram) * si.mem_unit; |
| |
| #elif defined(_WIN32) |
| if ((GetVersion() & 0xFF) >= 5) { |
| // Windows 2000 and later have GlobalMemoryStatusEx() which |
| // supports reporting values greater than 4 GiB. To keep the |
| // code working also on older Windows versions, use |
| // GlobalMemoryStatusEx() conditionally. |
| HMODULE kernel32 = GetModuleHandle("kernel32.dll"); |
| if (kernel32 != NULL) { |
| BOOL (WINAPI *gmse)(LPMEMORYSTATUSEX) = GetProcAddress( |
| kernel32, "GlobalMemoryStatusEx"); |
| if (gmse != NULL) { |
| MEMORYSTATUSEX meminfo; |
| meminfo.dwLength = sizeof(meminfo); |
| if (gmse(&meminfo)) |
| ret = meminfo.ullTotalPhys; |
| } |
| } |
| } |
| |
| if (ret == 0) { |
| // GlobalMemoryStatus() is supported by Windows 95 and later, |
| // so it is fine to link against it unconditionally. Note that |
| // GlobalMemoryStatus() has no return value. |
| MEMORYSTATUS meminfo; |
| meminfo.dwLength = sizeof(meminfo); |
| GlobalMemoryStatus(&meminfo); |
| ret = meminfo.dwTotalPhys; |
| } |
| |
| #elif defined(__DJGPP__) |
| __dpmi_free_mem_info meminfo; |
| if (__dpmi_get_free_memory_information(&meminfo) == 0 |
| && meminfo.total_number_of_physical_pages |
| != (unsigned long)(-1)) |
| ret = (uint64_t)(meminfo.total_number_of_physical_pages) |
| * 4096; |
| #endif |
| |
| return ret; |
| } |
| |
| #endif |