root/src/simh/sim_os_mem.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. memory_available_uv
  2. mem_parse_value
  3. sim_memory_available

   1 /*
   2  * vim: filetype=c:tabstop=2:ai:expandtab
   3  * SPDX-License-Identifier: ICU
   4  * scspell-id: f59cc352-0209-11f0-af38-80ee73e9b8e7
   5  *
   6  * ---------------------------------------------------------------------------
   7  *
   8  * Copyright (c) 2025 Jeffrey H. Johnson
   9  * Copyright (c) 2025 The DPS8M Development Team
  10  *
  11  * This software is made available under the terms of the ICU License.
  12  * See the LICENSE.md file at the top-level directory of this distribution.
  13  *
  14  * ---------------------------------------------------------------------------
  15  */
  16 
  17 /*
  18  * Memory availability, checked in the following order:
  19  *
  20  * 1. libuv uv_get_available_memory
  21  * 2. libuv uv_get_free_memory
  22  * 3. Linux "available" memory
  23  * 4. Linux "free+buffer+cache" memory
  24  * 5. Linux "committable" memory
  25  * 6. Zero
  26  */
  27 
  28 #include <errno.h>
  29 #include <stdbool.h>
  30 #include <limits.h>
  31 #include <stdio.h>
  32 #include <stdlib.h>
  33 #include <string.h>
  34 #include <uv.h>
  35 
  36 #define MEM_BUFFER_SIZE 4096
  37 #define UV_VERSION(major, minor, patch) ((major << 16) | (minor << 8) | (patch))
  38 
  39 static uint64_t
  40 memory_available_uv(void) {
     /* [previous][next][first][last][top][bottom][index][help] */
  41   uint64_t available_memory_b = 0;
  42 
  43 #if UV_VERSION(1, 45, 0) <= UV_VERSION_HEX
  44   available_memory_b = uv_get_available_memory();
  45 #endif
  46   if (0 == available_memory_b)
  47     available_memory_b = uv_get_free_memory();
  48 
  49   return available_memory_b;
  50 }
  51 
  52 static int
  53 mem_parse_value(const char *line, const char *label, uint64_t *value)
     /* [previous][next][first][last][top][bottom][index][help] */
  54 {
  55   if (!line || !label || !value)
  56     return -1;
  57 
  58   size_t label_len = strlen(label);
  59   if (0 != strncmp(line, label, label_len))
  60     return -1;
  61 
  62   const char *ptr = line + label_len;
  63   while (' ' == *ptr || '\t' == *ptr)
  64     ptr++;
  65 
  66   char *endptr;
  67   errno = 0;
  68   *value = strtoull(ptr, &endptr, 10) * 1024;
  69   if (ERANGE == errno || ULLONG_MAX == *value || ptr == endptr)
  70     return -1;
  71 
  72   while (' ' == *endptr || '\t' == *endptr)
  73     endptr++;
  74   if (0 != strncmp(endptr, "kB", 2) || 3 < strlen(endptr))
  75     return -1;
  76 
  77   return 0;
  78 }
  79 
  80 uint64_t
  81 sim_memory_available(void) {
     /* [previous][next][first][last][top][bottom][index][help] */
  82   FILE *fp = fopen("/proc/meminfo", "r");
  83   uint64_t uv_usable_memory = memory_available_uv();
  84 
  85   if (!fp)
  86     return uv_usable_memory;
  87 
  88   char buffer[MEM_BUFFER_SIZE];
  89   uint64_t commit_limit = 0, mem_free = 0, buffers = 0, cached = 0, mem_available = 0;
  90   bool found_commit = false, found_free = false, found_buffers = false, found_cached = false, found_available = false;
  91 
  92   while (fgets(buffer, sizeof(buffer), fp)) {
  93     buffer[sizeof(buffer) - 1] = '\0';
  94 
  95     if (false == found_commit && 0 == mem_parse_value(buffer, "CommitLimit:", &commit_limit))
  96       found_commit = true;
  97     else if (false == found_free && 0 == mem_parse_value(buffer, "MemFree:", &mem_free))
  98       found_free = true;
  99     else if (false == found_buffers && 0 == mem_parse_value(buffer, "Buffers:", &buffers))
 100       found_buffers = true;
 101     else if (false == found_cached && 0 == mem_parse_value(buffer, "Cached:", &cached))
 102       found_cached = true;
 103     else if (false == found_available && 0 == mem_parse_value(buffer, "MemAvailable:", &mem_available))
 104       found_available = true;
 105 
 106     if (found_commit && found_free && found_buffers && found_cached && found_available)
 107       break;
 108   }
 109 
 110   (void)fclose(fp);
 111 
 112   uint64_t linux_commit_memory = found_commit ? commit_limit : 0;
 113   uint64_t linux_freebufcache_memory = (found_free && found_buffers && found_cached) ?
 114                                        (mem_free + buffers + cached) : 0;
 115   uint64_t linux_available_memory = found_available ? mem_available : 0;
 116 
 117   if (uv_usable_memory)
 118     return uv_usable_memory;
 119 
 120   if (linux_available_memory)
 121     return linux_available_memory;
 122 
 123   if (linux_freebufcache_memory)
 124     return linux_freebufcache_memory;
 125 
 126   if (linux_commit_memory)
 127     return linux_commit_memory;
 128 
 129   return 0;
 130 }

/* [previous][next][first][last][top][bottom][index][help] */