tor  0.4.2.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-2019, The Tor Project, Inc. */
4 /* See LICENSE for licensing information */
5 
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 
21 #ifdef HAVE_FCNTL_H
22 #include <fcntl.h>
23 #endif
24 #ifdef HAVE_MALLOC_H
25 #include <malloc.h>
26 #endif
27 #ifdef HAVE_UNISTD_H
28 #include <unistd.h>
29 #endif
30 
31 #ifdef _WIN32
32 #include <windows.h>
33 #endif
34 #include <string.h>
35 
36 #if defined(HAVE_SYS_SYSCTL_H) && !defined(_WIN32) && !defined(__linux__)
37 #include <sys/sysctl.h>
38 #endif
39 
40 DISABLE_GCC_WARNING(aggregate-return)
43 void
44 tor_log_mallinfo(int severity)
45 {
46 #ifdef HAVE_MALLINFO
47  struct mallinfo mi;
48  memset(&mi, 0, sizeof(mi));
49  mi = mallinfo();
50  tor_log(severity, LD_MM,
51  "mallinfo() said: arena=%d, ordblks=%d, smblks=%d, hblks=%d, "
52  "hblkhd=%d, usmblks=%d, fsmblks=%d, uordblks=%d, fordblks=%d, "
53  "keepcost=%d",
54  mi.arena, mi.ordblks, mi.smblks, mi.hblks,
55  mi.hblkhd, mi.usmblks, mi.fsmblks, mi.uordblks, mi.fordblks,
56  mi.keepcost);
57 #else /* !(defined(HAVE_MALLINFO)) */
58  (void)severity;
59 #endif /* defined(HAVE_MALLINFO) */
60 }
61 ENABLE_GCC_WARNING(aggregate-return)
62 
63 #if defined(HW_PHYSMEM64)
64 /* OpenBSD and NetBSD define this */
65 #define INT64_HW_MEM HW_PHYSMEM64
66 #elif defined(HW_MEMSIZE)
67 /* OSX defines this one */
68 #define INT64_HW_MEM HW_MEMSIZE
69 #endif /* defined(HW_PHYSMEM64) || ... */
70 
75 static uint64_t
77 {
78 #if defined(__linux__)
79  /* On linux, sysctl is deprecated. Because proc is so awesome that you
80  * shouldn't _want_ to write portable code, I guess? */
81  unsigned long long result=0;
82  int fd = -1;
83  char *s = NULL;
84  const char *cp;
85  size_t file_size=0;
86  if (-1 == (fd = tor_open_cloexec("/proc/meminfo",O_RDONLY,0)))
87  return 0;
88  s = read_file_to_str_until_eof(fd, 65536, &file_size);
89  if (!s)
90  goto err;
91  cp = strstr(s, "MemTotal:");
92  if (!cp)
93  goto err;
94  /* Use the system sscanf so that space will match a wider number of space */
95  if (sscanf(cp, "MemTotal: %llu kB\n", &result) != 1)
96  goto err;
97 
98  close(fd);
99  tor_free(s);
100  return result * 1024;
101 
102  /* LCOV_EXCL_START Can't reach this unless proc is broken. */
103  err:
104  tor_free(s);
105  close(fd);
106  return 0;
107  /* LCOV_EXCL_STOP */
108 #elif defined (_WIN32)
109  /* Windows has MEMORYSTATUSEX; pretty straightforward. */
110  MEMORYSTATUSEX ms;
111  memset(&ms, 0, sizeof(ms));
112  ms.dwLength = sizeof(ms);
113  if (! GlobalMemoryStatusEx(&ms))
114  return 0;
115 
116  return ms.ullTotalPhys;
117 
118 #elif defined(HAVE_SYSCTL) && defined(INT64_HW_MEM)
119  /* On many systems, HW_PHYSMEM is clipped to 32 bits; let's use a better
120  * variant if we know about it. */
121  uint64_t memsize = 0;
122  size_t len = sizeof(memsize);
123  int mib[2] = {CTL_HW, INT64_HW_MEM};
124  if (sysctl(mib,2,&memsize,&len,NULL,0))
125  return 0;
126 
127  return memsize;
128 
129 #elif defined(HAVE_SYSCTL) && defined(HW_PHYSMEM)
130  /* On some systems (like FreeBSD I hope) you can use a size_t with
131  * HW_PHYSMEM. */
132  size_t memsize=0;
133  size_t len = sizeof(memsize);
134  int mib[2] = {CTL_HW, HW_PHYSMEM};
135  if (sysctl(mib,2,&memsize,&len,NULL,0))
136  return 0;
137 
138  return memsize;
139 
140 #else
141  /* I have no clue. */
142  return 0;
143 #endif /* defined(__linux__) || ... */
144 }
145 
151 get_total_system_memory, (size_t *mem_out))
152 {
153  static size_t mem_cached=0;
154  uint64_t m = get_total_system_memory_impl();
155  if (0 == m) {
156  /* LCOV_EXCL_START -- can't make this happen without mocking. */
157  /* We couldn't find our memory total */
158  if (0 == mem_cached) {
159  /* We have no cached value either */
160  *mem_out = 0;
161  return -1;
162  }
163 
164  *mem_out = mem_cached;
165  return 0;
166  /* LCOV_EXCL_STOP */
167  }
168 
169 #if SIZE_MAX != UINT64_MAX
170  if (m > SIZE_MAX) {
171  /* I think this could happen if we're a 32-bit Tor running on a 64-bit
172  * system: we could have more system memory than would fit in a
173  * size_t. */
174  m = SIZE_MAX;
175  }
176 #endif /* SIZE_MAX != UINT64_MAX */
177 
178  *mem_out = mem_cached = (size_t) m;
179 
180  return 0;
181 }
int tor_open_cloexec(const char *path, int flags, unsigned mode)
Definition: files.c:54
void tor_log(int severity, log_domain_mask_t domain, const char *format,...)
Definition: log.c:633
#define tor_free(p)
Definition: malloc.h:52
Integer definitions used throughout Tor.
Headers for util_malloc.c.
Header for meminfo.c.
static uint64_t get_total_system_memory_impl(void)
Definition: meminfo.c:76
Utility macros to handle different features and behavior in different compilers.
char * read_file_to_str_until_eof(int fd, size_t max_bytes_to_read, size_t *sz_out) ATTR_MALLOC
Definition: files.c:564
MOCK_IMPL(int, get_total_system_memory,(size_t *mem_out))
Definition: meminfo.c:150
Wrappers for reading and writing data to files on disk.
void tor_log_mallinfo(int severity)
Definition: meminfo.c:44
Headers for log.c.
#define LD_MM
Definition: log.h:72