[tor-commits] [tor/master] get_total_system_memory(): see how much RAM we have

nickm at torproject.org nickm at torproject.org
Thu Apr 24 14:32:26 UTC 2014


commit aca05fc5c08d6296c4f93850a0256bfd96890b18
Author: Nick Mathewson <nickm at torproject.org>
Date:   Thu Apr 3 11:46:01 2014 -0400

    get_total_system_memory(): see how much RAM we have
---
 configure.ac         |    2 +
 src/common/compat.c  |  119 ++++++++++++++++++++++++++++++++++++++++++++++++++
 src/common/compat.h  |    2 +
 src/or/main.c        |    1 +
 src/test/test_util.c |   29 ++++++++++++
 5 files changed, 153 insertions(+)

diff --git a/configure.ac b/configure.ac
index 6e41041..d8543b0 100644
--- a/configure.ac
+++ b/configure.ac
@@ -353,6 +353,7 @@ AC_CHECK_FUNCS(
         strtok_r \
         strtoull \
         sysconf \
+	sysctl \
         uname \
         vasprintf \
 	_vscprintf
@@ -877,6 +878,7 @@ AC_CHECK_HEADERS(
         sys/prctl.h \
         sys/resource.h \
         sys/socket.h \
+	sys/sysctl.h \
         sys/syslimits.h \
         sys/time.h \
         sys/types.h \
diff --git a/src/common/compat.c b/src/common/compat.c
index 135f2c9..58dd7f5 100644
--- a/src/common/compat.c
+++ b/src/common/compat.c
@@ -38,6 +38,9 @@
 #ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
 #endif
+#ifdef HAVE_SYS_SYSCTL_H
+#include <sys/sysctl.h>
+#endif
 #ifdef HAVE_SYS_STAT_H
 #include <sys/stat.h>
 #endif
@@ -3311,3 +3314,119 @@ format_win32_error(DWORD err)
 }
 #endif
 
+#if defined(HW_PHYSMEM64)
+/* This appears to be an OpenBSD thing */
+#define INT64_HW_MEM HW_PHYSMEM64
+#elif defined(HW_MEMSIZE)
+/* OSX defines this one */
+#define INT64_HW_MEM HW_MEMSIZE
+#endif
+
+/**
+ * Helper: try to detect the total system memory, and return it. On failure,
+ * return 0.
+ */
+static uint64_t
+get_total_system_memory_impl(void)
+{
+#if defined(__linux__)
+  /* On linux, sysctl is deprecated. Because proc is so awesome that you
+   * shouldn't _want_ to write portable code, I guess? */
+  unsigned long long result=0;
+  int fd = -1;
+  char *s = NULL;
+  const char *cp;
+  size_t file_size=0;
+  if (-1 == (fd = tor_open_cloexec("/proc/meminfo",O_RDONLY,0)))
+    return 0;
+  s = read_file_to_str_until_eof(fd, 65536, &file_size);
+  if (!s)
+    goto err;
+  cp = strstr(s, "MemTotal:");
+  if (!cp)
+    goto err;
+  /* Use the system sscanf so that space will match a wider number of space */
+  if (sscanf(cp, "MemTotal: %llu kB\n", &result) != 1)
+    goto err;
+
+  close(fd);
+  tor_free(s);
+  return result * 1024;
+
+ err:
+  tor_free(s);
+  close(fd);
+  return 0;
+#elif defined (_WIN32)
+  /* Windows has MEMORYSTATUSEX; pretty straightforward. */
+  MEMORYSTATUSEX ms;
+  memset(&ms, 0, sizeof(ms));
+  ms.dwLength = sizeof(ms);
+  if (! GlobalMemoryStatusEx(&ms))
+    return 0;
+
+  return ms.ullTotalPhys;
+
+#elif defined(HAVE_SYSCTL) && defined(INT64_HW_MEM)
+  /* On many systems, HW_PYHSMEM is clipped to 32 bits; let's use a better
+   * variant if we know about it. */
+  uint64_t memsize = 0;
+  size_t len = sizeof(memsize);
+  int mib[2] = {CTL_HW, INT64_HW_MEM};
+  if (sysctl(mib,2,&memsize,&len,NULL,0))
+    return 0;
+
+  return memsize;
+
+#elif defined(HAVE_SYSCTL) && defined(HW_PHYSMEM)
+  /* On some systems (like FreeBSD I hope) you can use a size_t with
+   * HW_PHYSMEM. */
+  size_t memsize=0;
+  size_t len = sizeof(memsize);
+  int mib[2] = {CTL_HW, HW_USERMEM};
+  if (sysctl(mib,2,&memsize,&len,NULL,0))
+    return -1;
+
+  return memsize;
+
+#else
+  /* I have no clue. */
+  return 0;
+#endif
+}
+
+/**
+ * Try to find out how much physical memory the system has. On success,
+ * return 0 and set *<b>mem_out</b> to that value. On failure, return -1.
+ */
+int
+get_total_system_memory(size_t *mem_out)
+{
+  static size_t mem_cached=0;
+  uint64_t m = get_total_system_memory_impl();
+  if (0 == m) {
+    /* We couldn't find our memory total */
+    if (0 == mem_cached) {
+      /* We have no cached value either */
+      *mem_out = 0;
+      return -1;
+    }
+
+    *mem_out = mem_cached;
+    return 0;
+  }
+
+#if SIZE_T_MAX != UINT64_MAX
+  if (m > SIZE_T_MAX) {
+    /* I think this could happen if we're a 32-bit Tor running on a 64-bit
+     * system: we could have more system memory than would fit in a
+     * size_t. */
+    m = SIZE_T_MAX;
+  }
+#endif
+
+  *mem_out = mem_cached = (size_t) m;
+
+  return -1;
+}
+
diff --git a/src/common/compat.h b/src/common/compat.h
index bb88818..01faf14 100644
--- a/src/common/compat.h
+++ b/src/common/compat.h
@@ -637,6 +637,8 @@ char *make_path_absolute(char *fname);
 
 char **get_environment(void);
 
+int get_total_system_memory(size_t *mem_out);
+
 int spawn_func(void (*func)(void *), void *data);
 void spawn_exit(void) ATTR_NORETURN;
 
diff --git a/src/or/main.c b/src/or/main.c
index feca35c..8c75a3b 100644
--- a/src/or/main.c
+++ b/src/or/main.c
@@ -2751,6 +2751,7 @@ sandbox_init_filter(void)
       "/dev/srandom", 0,
       "/dev/urandom", 0,
       "/dev/random", 0,
+      "/proc/meminfo", 0,
       NULL, 0
   );
 
diff --git a/src/test/test_util.c b/src/test/test_util.c
index a471b8e..20e6585 100644
--- a/src/test/test_util.c
+++ b/src/test/test_util.c
@@ -3606,6 +3606,34 @@ test_util_socketpair(void *arg)
     tor_close_socket(fds[1]);
 }
 
+static void
+test_util_max_mem(void *arg)
+{
+  size_t memory1, memory2;
+  int r, r2;
+  (void) arg;
+
+  r = get_total_system_memory(&memory1);
+  r2 = get_total_system_memory(&memory2);
+  tt_int_op(r, ==, r2);
+  tt_int_op(memory2, ==, memory1);
+
+  TT_BLATHER(("System memory: "U64_FORMAT, U64_PRINTF_ARG(memory1)));
+
+  if (r==0) {
+    /* You have at least a megabyte. */
+    tt_int_op(memory1, >, (1<<20));
+  } else {
+    /* You do not have a petabyte. */
+#if SIZEOF_SIZE_T == SIZEOF_UINT64_T
+    tt_int_op(memory1, <, (U64_LITERAL(1)<<50));
+#endif
+  }
+
+ done:
+  ;
+}
+
 struct testcase_t util_tests[] = {
   UTIL_LEGACY(time),
   UTIL_TEST(parse_http_time, 0),
@@ -3669,6 +3697,7 @@ struct testcase_t util_tests[] = {
     (void*)"0" },
   { "socketpair_ersatz", test_util_socketpair, TT_FORK,
     &socketpair_setup, (void*)"1" },
+  UTIL_TEST(max_mem, 0),
   END_OF_TESTCASES
 };
 





More information about the tor-commits mailing list