]> icculus.org git repositories - icculus/xz.git/blob - src/common/physmem.h
Put the interesting parts of XZ Utils into the public domain.
[icculus/xz.git] / src / common / physmem.h
1 ///////////////////////////////////////////////////////////////////////////////
2 //
3 /// \file       physmem.h
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 #ifndef PHYSMEM_H
14 #define PHYSMEM_H
15
16 #if defined(HAVE_PHYSMEM_SYSCONF)
17 #       include <unistd.h>
18
19 #elif defined(HAVE_PHYSMEM_SYSCTL)
20 #       ifdef HAVE_SYS_PARAM_H
21 #               include <sys/param.h>
22 #       endif
23 #       ifdef HAVE_SYS_SYSCTL_H
24 #               include <sys/sysctl.h>
25 #       endif
26
27 #elif defined(HAVE_PHYSMEM_SYSINFO)
28 #       include <sys/sysinfo.h>
29
30 #elif defined(_WIN32)
31 #       ifndef _WIN32_WINNT
32 #               define _WIN32_WINNT 0x0500
33 #       endif
34 #       include <windows.h>
35
36 #elif defined(__DJGPP__)
37 #       include <dpmi.h>
38 #endif
39
40
41 /// \brief      Get the amount of physical memory in bytes
42 ///
43 /// \return     Amount of physical memory in bytes. On error, zero is
44 ///             returned.
45 static inline uint64_t
46 physmem(void)
47 {
48         uint64_t ret = 0;
49
50 #if defined(HAVE_PHYSMEM_SYSCONF)
51         const long pagesize = sysconf(_SC_PAGESIZE);
52         const long pages = sysconf(_SC_PHYS_PAGES);
53         if (pagesize != -1 || pages != -1)
54                 // According to docs, pagesize * pages can overflow.
55                 // Simple case is 32-bit box with 4 GiB or more RAM,
56                 // which may report exactly 4 GiB of RAM, and "long"
57                 // being 32-bit will overflow. Casting to uint64_t
58                 // hopefully avoids overflows in the near future.
59                 ret = (uint64_t)(pagesize) * (uint64_t)(pages);
60
61 #elif defined(HAVE_PHYSMEM_SYSCTL)
62         int name[2] = { CTL_HW, HW_PHYSMEM };
63         union {
64                 unsigned long ul;
65                 unsigned int ui;
66         } mem;
67         size_t mem_ptr_size = sizeof(mem.ul);
68         if (!sysctl(name, 2, &mem.ul, &mem_ptr_size, NULL, NULL)) {
69                 // Some systems use unsigned int as the "return value".
70                 // This makes a difference on 64-bit boxes.
71                 if (mem_ptr_size == sizeof(mem.ul))
72                         ret = mem.ul;
73                 else if (mem_ptr_size == sizeof(mem.ui))
74                         ret = mem.ui;
75         }
76
77 #elif defined(HAVE_PHYSMEM_SYSINFO)
78         struct sysinfo si;
79         if (sysinfo(&si) == 0)
80                 ret = (uint64_t)(si.totalram) * si.mem_unit;
81
82 #elif defined(_WIN32)
83         if ((GetVersion() & 0xFF) >= 5) {
84                 // Windows 2000 and later have GlobalMemoryStatusEx() which
85                 // supports reporting values greater than 4 GiB. To keep the
86                 // code working also on older Windows versions, use
87                 // GlobalMemoryStatusEx() conditionally.
88                 HMODULE kernel32 = GetModuleHandle("kernel32.dll");
89                 if (kernel32 != NULL) {
90                         BOOL (WINAPI *gmse)(LPMEMORYSTATUSEX) = GetProcAddress(
91                                         kernel32, "GlobalMemoryStatusEx");
92                         if (gmse != NULL) {
93                                 MEMORYSTATUSEX meminfo;
94                                 meminfo.dwLength = sizeof(meminfo);
95                                 if (gmse(&meminfo))
96                                         ret = meminfo.ullTotalPhys;
97                         }
98                 }
99         }
100
101         if (ret == 0) {
102                 // GlobalMemoryStatus() is supported by Windows 95 and later,
103                 // so it is fine to link against it unconditionally. Note that
104                 // GlobalMemoryStatus() has no return value.
105                 MEMORYSTATUS meminfo;
106                 meminfo.dwLength = sizeof(meminfo);
107                 GlobalMemoryStatus(&meminfo);
108                 ret = meminfo.dwTotalPhys;
109         }
110
111 #elif defined(__DJGPP__)
112         __dpmi_free_mem_info meminfo;
113         if (__dpmi_get_free_memory_information(&meminfo) == 0
114                         && meminfo.total_number_of_physical_pages
115                                 != (unsigned long)(-1))
116                 ret = (uint64_t)(meminfo.total_number_of_physical_pages)
117                                 * 4096;
118 #endif
119
120         return ret;
121 }
122
123 #endif