|
@@ -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;
|
|
|
+}
|
|
|
+
|