Files
codebase-memory-mcp/src/foundation/system_info_internal.h
T
Sam Li a5a3d1d60a feat(platform): cgroup-aware CPU/memory detection in detect_system_linux
Inside a container, sysconf(_SC_NPROCESSORS_ONLN) and sysinfo() report
the host's CPU count and RAM, not the cgroup's effective quota — so
cbm_default_worker_count over-provisions workers and the mmap budget can
exceed the cgroup memory cap, driving OOMKills (#363).

detect_system_linux now reads the cgroup limits:
- cbm_detect_cgroup_cpus: cgroup v2 cpu.max, then v1 cpu.cfs_quota_us /
  cpu.cfs_period_us → ceil(quota/period); -1 when unlimited.
- cbm_detect_cgroup_mem: cgroup v2 memory.max, then v1
  memory.limit_in_bytes; 0 when unlimited or the v1 near-ULLONG_MAX
  sentinel.
- Effective value is min(cgroup, host), guarding against mis-mounted
  cgroups that report more than the host.

Helpers read via a bounded read_small_file (fopen "re", capped fread)
and are exposed through system_info_internal.h for unit tests that drive
them against a fake cgroup tree. The test teardown uses opendir/unlink/
rmdir (no shell spawn).

Distilled from #365 onto current main (unioned the test additions with
the CBM_WORKERS tests from #364, and replaced the test-cleanup
system("rm -rf") with a shell-free recursive remove). Closes #363
together with #364.
2026-05-30 17:47:18 +02:00

45 lines
1.5 KiB
C

/*
* system_info_internal.h — Internal helpers exposed for testing.
*
* These functions are implementation details of system_info.c; they are
* declared here only so that test_platform.c can drive them against a
* fake cgroup filesystem. Production code outside system_info.c should
* use the public APIs in platform.h instead.
*/
#ifndef CBM_FOUNDATION_SYSTEM_INFO_INTERNAL_H
#define CBM_FOUNDATION_SYSTEM_INFO_INTERNAL_H
#include <stddef.h>
#ifdef __linux__
/*
* Effective CPU count for the cgroup rooted at `cgroup_root`.
*
* Reads (in order):
* 1. cgroup v2: "<cgroup_root>/cpu.max" ("<quota> <period>" or "max ...")
* 2. cgroup v1: "<cgroup_root>/cpu/cpu.cfs_quota_us" + ".../cpu.cfs_period_us"
*
* Returns ceil(quota / period) (>= 1) when a valid CPU quota is in place.
* Returns -1 when no cgroup limit is present (caller should fall back to
* sysconf(_SC_NPROCESSORS_ONLN)).
*/
int cbm_detect_cgroup_cpus(const char *cgroup_root);
/*
* Effective memory limit (bytes) for the cgroup rooted at `cgroup_root`.
*
* Reads (in order):
* 1. cgroup v2: "<cgroup_root>/memory.max" ("max" or integer bytes)
* 2. cgroup v1: "<cgroup_root>/memory/memory.limit_in_bytes"
*
* Returns the byte count when a finite limit is in place. Returns 0 when
* no cgroup limit is present, the limit is "max"/unlimited, or the value
* is so large it represents the cgroup-v1 "unlimited" sentinel.
*/
size_t cbm_detect_cgroup_mem(const char *cgroup_root);
#endif /* __linux__ */
#endif /* CBM_FOUNDATION_SYSTEM_INFO_INTERNAL_H */