Tor 0.4.9.0-alpha-dev
meminfo.c
Go to the documentation of this file.
1/* Copyright (c) 2003-2004, Roger Dingledine
2 * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
3 * Copyright (c) 2007-2021, The Tor Project, Inc. */
4/* See LICENSE for licensing information */
5
6/**
7 * \file meminfo.c
8 *
9 * \brief Functions to query total memory, and access meta-information about
10 * the allocator.
11 **/
12
13#include "lib/meminfo/meminfo.h"
14
16#include "lib/cc/torint.h"
17#include "lib/fs/files.h"
18#include "lib/log/log.h"
19#include "lib/malloc/malloc.h"
21
22#ifdef HAVE_FCNTL_H
23#include <fcntl.h>
24#endif
25#ifdef HAVE_MALLOC_H
26#include <malloc.h>
27#endif
28#ifdef HAVE_UNISTD_H
29#include <unistd.h>
30#endif
31
32#ifdef _WIN32
33#include <windows.h>
34#endif
35#include <string.h>
36
37#if defined(HAVE_SYS_SYSCTL_H) && !defined(_WIN32) && !defined(__linux__)
38#include <sys/sysctl.h>
39#endif
40
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) || ... */
48
49/**
50 * Helper: try to detect the total system memory, and return it. On failure,
51 * return 0.
52 */
53static uint64_t
55{
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;
60 int fd = -1;
61 char *s = NULL;
62 const char *cp;
63 size_t file_size=0;
64 if (-1 == (fd = tor_open_cloexec("/proc/meminfo",O_RDONLY,0)))
65 return 0;
66 s = read_file_to_str_until_eof(fd, 65536, &file_size);
67 if (!s)
68 goto err;
69 cp = find_str_at_start_of_line(s, "MemTotal:");
70 if (!cp)
71 goto err;
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)
74 goto err;
75
76 close(fd);
77 tor_free(s);
78 return result * 1024;
79
80 /* LCOV_EXCL_START Can't reach this unless proc is broken. */
81 err:
82 tor_free(s);
83 close(fd);
84 return 0;
85 /* LCOV_EXCL_STOP */
86#elif defined (_WIN32)
87 /* Windows has MEMORYSTATUSEX; pretty straightforward. */
88 MEMORYSTATUSEX ms;
89 memset(&ms, 0, sizeof(ms));
90 ms.dwLength = sizeof(ms);
91 if (! GlobalMemoryStatusEx(&ms))
92 return 0;
93
94 return ms.ullTotalPhys;
95
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. */
99 uint64_t memsize = 0;
100 size_t len = sizeof(memsize);
101 int mib[2] = {CTL_HW, INT64_HW_MEM};
102 if (sysctl(mib,2,&memsize,&len,NULL,0))
103 return 0;
104
105 return memsize;
106
107#elif defined(HAVE_SYSCTL) && defined(HW_PHYSMEM)
108 /* On some systems (like FreeBSD I hope) you can use a size_t with
109 * HW_PHYSMEM. */
110 size_t memsize=0;
111 size_t len = sizeof(memsize);
112 int mib[2] = {CTL_HW, HW_PHYSMEM};
113 if (sysctl(mib,2,&memsize,&len,NULL,0))
114 return 0;
115
116 return memsize;
117
118#else
119 /* I have no clue. */
120 return 0;
121#endif /* defined(__linux__) || ... */
122}
123
124/**
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.
127 */
128MOCK_IMPL(int,
129get_total_system_memory, (size_t *mem_out))
130{
131 static size_t mem_cached=0;
132 uint64_t m = get_total_system_memory_impl();
133 if (0 == m) {
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 */
138 *mem_out = 0;
139 return -1;
140 }
141
142 *mem_out = mem_cached;
143 return 0;
144 /* LCOV_EXCL_STOP */
145 }
146
147#if SIZE_MAX != UINT64_MAX
148 if (m > SIZE_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
151 * size_t. */
152 m = SIZE_MAX;
153 }
154#endif /* SIZE_MAX != UINT64_MAX */
155
156 *mem_out = mem_cached = (size_t) m;
157
158 return 0;
159}
Utility macros to handle different features and behavior in different compilers.
Wrappers for reading and writing data to files on disk.
char * read_file_to_str_until_eof(int fd, size_t max_bytes_to_read, size_t *sz_out) ATTR_MALLOC
Definition: files.c:581
int tor_open_cloexec(const char *path, int flags, unsigned mode)
Definition: files.c:54
Headers for log.c.
Headers for util_malloc.c.
#define tor_free(p)
Definition: malloc.h:56
static uint64_t get_total_system_memory_impl(void)
Definition: meminfo.c:54
int get_total_system_memory(size_t *mem_out)
Definition: meminfo.c:129
Header for meminfo.c.
#define MOCK_IMPL(rv, funcname, arglist)
Definition: testsupport.h:133
Integer definitions used throughout Tor.
const char * find_str_at_start_of_line(const char *haystack, const char *needle)
Definition: util_string.c:402
Header for util_string.c.