LCOV - code coverage report
Current view: top level - lib/meminfo - meminfo.c (source / functions) Hit Total Coverage
Test: lcov.info Lines: 21 24 87.5 %
Date: 2021-11-24 03:28:48 Functions: 2 2 100.0 %

          Line data    Source code
       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
      54         690 : get_total_system_memory_impl(void)
      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         690 :   unsigned long long result=0;
      60         690 :   int fd = -1;
      61         690 :   char *s = NULL;
      62         690 :   const char *cp;
      63         690 :   size_t file_size=0;
      64         690 :   if (-1 == (fd = tor_open_cloexec("/proc/meminfo",O_RDONLY,0)))
      65             :     return 0;
      66         690 :   s = read_file_to_str_until_eof(fd, 65536, &file_size);
      67         690 :   if (!s)
      68           0 :     goto err;
      69         690 :   cp = find_str_at_start_of_line(s, "MemTotal:");
      70         690 :   if (!cp)
      71           0 :     goto err;
      72             :   /* Use the system sscanf so that space will match a wider number of space */
      73         690 :   if (sscanf(cp, "MemTotal: %llu kB\n", &result) != 1)
      74           0 :     goto err;
      75             : 
      76         690 :   close(fd);
      77         690 :   tor_free(s);
      78         690 :   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         690 : MOCK_IMPL(int,
     129             : get_total_system_memory, (size_t *mem_out))
     130             : {
     131         690 :   static size_t mem_cached=0;
     132         690 :   uint64_t m = get_total_system_memory_impl();
     133         690 :   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         690 :   *mem_out = mem_cached = (size_t) m;
     157             : 
     158         690 :   return 0;
     159             : }

Generated by: LCOV version 1.14