1 /* Copyright (c) 2003-2004, Roger Dingledine
2 * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
3 * Copyright (c) 2007-2020, The Tor Project, Inc. */
4 /* See LICENSE for licensing information */
9 * \brief Functions to query total memory, and access meta-information about
13 #include "lib/meminfo/meminfo.h"
15 #include "lib/cc/compat_compiler.h"
16 #include "lib/cc/torint.h"
17 #include "lib/fs/files.h"
18 #include "lib/log/log.h"
19 #include "lib/malloc/malloc.h"
20 #include "lib/string/util_string.h"
37 #if defined(HAVE_SYS_SYSCTL_H) && !defined(_WIN32) && !defined(__linux__)
38 #include <sys/sysctl.h>
41 #if defined(HW_PHYSMEM64)
42 /* OpenBSD and NetBSD define this */
43 #define INT64_HW_MEM HW_PHYSMEM64
44 #elif defined(HW_MEMSIZE)
45 /* OSX defines this one */
46 #define INT64_HW_MEM HW_MEMSIZE
47 #endif /* defined(HW_PHYSMEM64) || ... */
50 * Helper: try to detect the total system memory, and return it. On failure,
54 get_total_system_memory_impl(void)
56 #if defined(__linux__)
57 /* On linux, sysctl is deprecated. Because proc is so awesome that you
58 * shouldn't _want_ to write portable code, I guess? */
59 unsigned long long result
=0;
64 if (-1 == (fd
= tor_open_cloexec("/proc/meminfo",O_RDONLY
,0)))
66 s
= read_file_to_str_until_eof(fd
, 65536, &file_size
);
69 cp
= find_str_at_start_of_line(s
, "MemTotal:");
72 /* Use the system sscanf so that space will match a wider number of space */
73 if (sscanf(cp
, "MemTotal: %llu kB\n", &result
) != 1)
80 /* LCOV_EXCL_START Can't reach this unless proc is broken. */
86 #elif defined (_WIN32)
87 /* Windows has MEMORYSTATUSEX; pretty straightforward. */
89 memset(&ms
, 0, sizeof(ms
));
90 ms
.dwLength
= sizeof(ms
);
91 if (! GlobalMemoryStatusEx(&ms
))
94 return ms
.ullTotalPhys
;
96 #elif defined(HAVE_SYSCTL) && defined(INT64_HW_MEM)
97 /* On many systems, HW_PHYSMEM is clipped to 32 bits; let's use a better
98 * variant if we know about it. */
100 size_t len
= sizeof(memsize
);
101 int mib
[2] = {CTL_HW
, INT64_HW_MEM
};
102 if (sysctl(mib
,2,&memsize
,&len
,NULL
,0))
107 #elif defined(HAVE_SYSCTL) && defined(HW_PHYSMEM)
108 /* On some systems (like FreeBSD I hope) you can use a size_t with
111 size_t len
= sizeof(memsize
);
112 int mib
[2] = {CTL_HW
, HW_PHYSMEM
};
113 if (sysctl(mib
,2,&memsize
,&len
,NULL
,0))
119 /* I have no clue. */
121 #endif /* defined(__linux__) || ... */
125 * Try to find out how much physical memory the system has. On success,
126 * return 0 and set *<b>mem_out</b> to that value. On failure, return -1.
129 get_total_system_memory
, (size_t *mem_out
))
131 static size_t mem_cached
=0;
132 uint64_t m
= get_total_system_memory_impl();
134 /* LCOV_EXCL_START -- can't make this happen without mocking. */
135 /* We couldn't find our memory total */
136 if (0 == mem_cached
) {
137 /* We have no cached value either */
142 *mem_out
= mem_cached
;
147 #if SIZE_MAX != UINT64_MAX
149 /* I think this could happen if we're a 32-bit Tor running on a 64-bit
150 * system: we could have more system memory than would fit in a
154 #endif /* SIZE_MAX != UINT64_MAX */
156 *mem_out
= mem_cached
= (size_t) m
;