From 6ad347fae4520f39520d34bd7c7f5ddafab13a69 Mon Sep 17 00:00:00 2001 From: Tim Besard Date: Fri, 12 May 2023 20:34:20 +0200 Subject: [PATCH] unix: constrained_memory should return UINT64_MAX (#3753) Document that we return UINT64_MAX if the cgroup limit is set to the max. For cgroupv2, that happens if we encounter `max`, while cgroupv1 returns 9223372036854771712 when no limit is set (which according to [this StackExchange discussion] is derived from LONG_MAX and PAGE_SIZE). So make sure we also detect this case for cgroupv1. [this StackExchange discussion]: https://unix.stackexchange.com/questions/420906/what-is-the-value-for-the-cgroups-limit-in-bytes-if-the-memory-is-not-restricte Addresses: https://github.com/libuv/libuv/pull/3744/files#r974062912 --- docs/src/misc.rst | 5 +++-- src/unix/linux.c | 15 +++++++++++++-- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/docs/src/misc.rst b/docs/src/misc.rst index c2ad5804..8c3a00e9 100644 --- a/docs/src/misc.rst +++ b/docs/src/misc.rst @@ -586,8 +586,9 @@ API Gets the total amount of memory available to the process (in bytes) based on limits imposed by the OS. If there is no such constraint, or the constraint - is unknown, `0` is returned. Note that it is not unusual for this value to - be less than or greater than :c:func:`uv_get_total_memory`. + is unknown, `0` is returned. If there is a constraining mechanism, but there + is no constraint set, `UINT64_MAX` is returned. Note that it is not unusual + for this value to be less than or greater than :c:func:`uv_get_total_memory`. .. note:: This function currently only returns a non-zero value on Linux, based diff --git a/src/unix/linux.c b/src/unix/linux.c index c5911552..b4bc1de7 100644 --- a/src/unix/linux.c +++ b/src/unix/linux.c @@ -1841,7 +1841,7 @@ static uint64_t uv__read_uint64(const char* filename) { if (0 == uv__slurp(filename, buf, sizeof(buf))) if (1 != sscanf(buf, "%" PRIu64, &rc)) if (0 == strcmp(buf, "max\n")) - rc = ~0ull; + rc = UINT64_MAX; return rc; } @@ -1877,6 +1877,7 @@ static void uv__get_cgroup1_memory_limits(char buf[static 1024], uint64_t* high, char filename[4097]; char* p; int n; + uint64_t cgroup1_max; /* Find out where the controller is mounted. */ p = uv__cgroup1_find_memory_controller(buf, &n); @@ -1893,12 +1894,22 @@ static void uv__get_cgroup1_memory_limits(char buf[static 1024], uint64_t* high, * as indicated by uv__read_uint64 returning 0. */ if (*high != 0 && *max != 0) - return; + goto update_limits; } /* Fall back to the limits of the global memory controller. */ *high = uv__read_uint64("/sys/fs/cgroup/memory/memory.soft_limit_in_bytes"); *max = uv__read_uint64("/sys/fs/cgroup/memory/memory.limit_in_bytes"); + + /* uv__read_uint64 detects cgroup2's "max", so we need to separately detect + * cgroup1's maximum value (which is derived from LONG_MAX and PAGE_SIZE). + */ +update_limits: + cgroup1_max = LONG_MAX & ~(sysconf(_SC_PAGESIZE) - 1); + if (*high == cgroup1_max) + *high = UINT64_MAX; + if (*max == cgroup1_max) + *max = UINT64_MAX; } static void uv__get_cgroup2_memory_limits(char buf[static 1024], uint64_t* high,