Tor  0.4.7.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 
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"
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  */
53 static 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  */
128 MOCK_IMPL(int,
129 get_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.
int tor_open_cloexec(const char *path, int flags, unsigned mode)
Definition: files.c:54
char * read_file_to_str_until_eof(int fd, size_t max_bytes_to_read, size_t *sz_out) ATTR_MALLOC
Definition: files.c:580
Headers for log.c.
Headers for util_malloc.c.
#define tor_free(p)
Definition: malloc.h:52
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:400
Header for util_string.c.