unix: check RLIMIT_AS and RLIMIT_DATA in uv_get_constrained_memory

Add uv__get_rlimit_max_memory() helper that checks RLIMIT_AS and
RLIMIT_DATA resource limits across all Unix platforms. This helper
returns the minimum of these rlimits if set.

Update all Unix platform implementations of uv_get_constrained_memory()
to use this helper, ensuring consistent handling of resource limits:
- Linux: combine cgroup limits with rlimits
- z/OS: combine RLIMIT_MEMLIMIT with rlimits
- Other Unix platforms: use rlimits (previously returned 0)

This provides a more accurate view of available memory when processes
have rlimit constraints in addition to platform-specific limits.

Related: https://github.com/JuliaLang/julia/pull/51656

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Jameson Nash 2025-10-01 21:32:22 +00:00
parent 74079a8e47
commit 7ffec72cdb
15 changed files with 65 additions and 15 deletions

View File

@ -396,7 +396,7 @@ uint64_t uv_get_total_memory(void) {
uint64_t uv_get_constrained_memory(void) {
return 0; /* Memory constraints are unknown. */
return uv__get_rlimit_max_memory();
}

View File

@ -2149,3 +2149,30 @@ int uv__sock_reuseport(int fd) {
return 0;
}
uint64_t uv__get_rlimit_max_memory(void) {
struct rlimit rl;
uint64_t result = 0;
uint64_t rlimit_value;
#if defined(RLIMIT_AS)
/* Check RLIMIT_AS (virtual memory limit). */
if (getrlimit(RLIMIT_AS, &rl) == 0 && rl.rlim_cur != RLIM_INFINITY) {
rlimit_value = rl.rlim_cur;
if (result == 0 || rlimit_value < result)
result = rlimit_value;
}
#endif
#if defined(RLIMIT_DATA)
/* Check RLIMIT_DATA (data segment limit). */
if (getrlimit(RLIMIT_DATA, &rl) == 0 && rl.rlim_cur != RLIM_INFINITY) {
rlimit_value = rl.rlim_cur;
if (result == 0 || rlimit_value < result)
result = rlimit_value;
}
#endif
return result;
}

View File

@ -85,7 +85,7 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
}
uint64_t uv_get_constrained_memory(void) {
return 0; /* Memory constraints are unknown. */
return uv__get_rlimit_max_memory();
}
uint64_t uv_get_available_memory(void) {

View File

@ -121,7 +121,7 @@ uint64_t uv_get_total_memory(void) {
uint64_t uv_get_constrained_memory(void) {
return 0; /* Memory constraints are unknown. */
return uv__get_rlimit_max_memory();
}

View File

@ -117,7 +117,7 @@ uint64_t uv_get_total_memory(void) {
uint64_t uv_get_constrained_memory(void) {
return 0; /* Memory constraints are unknown. */
return uv__get_rlimit_max_memory();
}

View File

@ -80,7 +80,7 @@ uint64_t uv_get_total_memory(void) {
uint64_t uv_get_constrained_memory(void) {
return 0; /* Memory constraints are unknown. */
return uv__get_rlimit_max_memory();
}

View File

@ -163,7 +163,7 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
}
uint64_t uv_get_constrained_memory(void) {
return 0; /* Memory constraints are unknown. */
return uv__get_rlimit_max_memory();
}

View File

@ -245,7 +245,7 @@ uint64_t uv_get_total_memory(void) {
uint64_t uv_get_constrained_memory(void) {
return 0; /* Memory constraints are unknown. */
return uv__get_rlimit_max_memory();
}

View File

@ -377,6 +377,7 @@ int uv__signal_loop_fork(uv_loop_t* loop);
/* platform specific */
uint64_t uv__hrtime(uv_clocktype_t type);
uint64_t uv__get_rlimit_max_memory(void);
int uv__kqueue_init(uv_loop_t* loop);
int uv__platform_loop_init(uv_loop_t* loop);
void uv__platform_loop_delete(uv_loop_t* loop);

View File

@ -53,6 +53,7 @@
#include <sys/sysmacros.h>
#include <sys/types.h>
#include <sys/utsname.h>
#include <sys/resource.h>
#include <time.h>
#include <unistd.h>
@ -2217,11 +2218,21 @@ static uint64_t uv__get_cgroup_constrained_memory(char buf[static 1024]) {
uint64_t uv_get_constrained_memory(void) {
char buf[1024];
uint64_t cgroup_limit;
uint64_t rlimit_limit;
if (uv__slurp("/proc/self/cgroup", buf, sizeof(buf)))
return 0;
return uv__get_cgroup_constrained_memory(buf);
cgroup_limit = uv__get_cgroup_constrained_memory(buf);
rlimit_limit = uv__get_rlimit_max_memory();
/* Return the minimum of cgroup and rlimit constraints. */
if (cgroup_limit == 0)
return rlimit_limit;
if (rlimit_limit == 0)
return cgroup_limit;
return cgroup_limit < rlimit_limit ? cgroup_limit : rlimit_limit;
}

View File

@ -127,7 +127,7 @@ uint64_t uv_get_total_memory(void) {
uint64_t uv_get_constrained_memory(void) {
return 0; /* Memory constraints are unknown. */
return uv__get_rlimit_max_memory();
}

View File

@ -135,7 +135,7 @@ uint64_t uv_get_total_memory(void) {
uint64_t uv_get_constrained_memory(void) {
return 0; /* Memory constraints are unknown. */
return uv__get_rlimit_max_memory();
}

View File

@ -188,12 +188,23 @@ uint64_t uv_get_total_memory(void) {
uint64_t uv_get_constrained_memory(void) {
struct rlimit rl;
uint64_t memlimit;
uint64_t rlimit_limit;
/* RLIMIT_MEMLIMIT return value is in megabytes rather than bytes. */
if (getrlimit(RLIMIT_MEMLIMIT, &rl) == 0)
return rl.rlim_cur * 1024 * 1024;
memlimit = 0;
if (getrlimit(RLIMIT_MEMLIMIT, &rl) == 0 && rl.rlim_cur != RLIM_INFINITY)
memlimit = rl.rlim_cur * 1024 * 1024;
return 0; /* There is no memory limit set. */
/* Also check RLIMIT_AS and RLIMIT_DATA. */
rlimit_limit = uv__get_rlimit_max_memory();
/* Return the minimum of RLIMIT_MEMLIMIT and other rlimits. */
if (memlimit == 0)
return rlimit_limit;
if (rlimit_limit == 0)
return memlimit;
return memlimit < rlimit_limit ? memlimit : rlimit_limit;
}

View File

@ -118,7 +118,7 @@ uint64_t uv_get_total_memory(void) {
uint64_t uv_get_constrained_memory(void) {
return 0;
return uv__get_rlimit_max_memory();
}

View File

@ -413,7 +413,7 @@ uint64_t uv_get_total_memory(void) {
uint64_t uv_get_constrained_memory(void) {
return 0; /* Memory constraints are unknown. */
return uv__get_rlimit_max_memory();
}