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