Skip to content

Commit 3c298fb

Browse files
committed
Add RSS memory limit to external watchdog thread
The Contabo node was OOM-killed at 11.3 GB RSS (12 GB VPS) despite having rss_limit_mb=4000 in config — the existing RSS check only ran inside the share processing loop and missed memory growth from mempool, UTXO cache, and DOGE block storage. The external watchdog thread now checks RSS every 10 seconds and aborts cleanly before the kernel OOM killer sends uncatchable SIGKILL. This produces a crash log and (with ulimit -c unlimited) a core dump.
1 parent d3585bd commit 3c298fb

1 file changed

Lines changed: 40 additions & 1 deletion

File tree

src/c2pool/c2pool_refactored.cpp

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6577,16 +6577,55 @@ int main(int argc, char* argv[]) {
65776577
// External watchdog thread — independent of io_context
65786578
std::thread ext_watchdog([hb_ioc, now_ms,
65796579
hb_think, hb_monitor, hb_ltc_sync, hb_ltc_mempool,
6580-
hb_doge_sync, hb_doge_mempool]() {
6580+
hb_doge_sync, hb_doge_mempool,
6581+
rss_limit_mb]() {
65816582
constexpr int CHECK_SEC = 10;
65826583
constexpr int FREEZE_SEC = 30;
65836584
// Grace period: let the event loop start up before monitoring
65846585
std::this_thread::sleep_for(std::chrono::seconds(FREEZE_SEC));
65856586

6587+
// RSS reader (works on Linux via /proc, returns 0 elsewhere)
6588+
auto read_rss_mb = []() -> long {
6589+
#ifdef __linux__
6590+
FILE* f = fopen("/proc/self/status", "r");
6591+
if (!f) return 0;
6592+
char line[256];
6593+
long kb = 0;
6594+
while (fgets(line, sizeof(line), f)) {
6595+
if (strncmp(line, "VmRSS:", 6) == 0) {
6596+
sscanf(line, "VmRSS: %ld", &kb);
6597+
break;
6598+
}
6599+
}
6600+
fclose(f);
6601+
return kb / 1024;
6602+
#else
6603+
return 0;
6604+
#endif
6605+
};
6606+
65866607
while (!g_shutdown_requested) {
65876608
std::this_thread::sleep_for(std::chrono::seconds(CHECK_SEC));
65886609
if (g_shutdown_requested) break;
65896610

6611+
// RSS limit check — catch memory leaks before OOM killer
6612+
long rss_mb = read_rss_mb();
6613+
if (rss_mb > 0 && rss_limit_mb > 0 && rss_mb > rss_limit_mb) {
6614+
fprintf(stderr,
6615+
"\n=== RSS LIMIT EXCEEDED ===\n"
6616+
"RSS: %ld MB (limit: %ld MB)\n",
6617+
rss_mb, rss_limit_mb);
6618+
char msg[256];
6619+
snprintf(msg, sizeof(msg),
6620+
"RSS LIMIT — %ld MB > %ld MB limit",
6621+
rss_mb, rss_limit_mb);
6622+
write_crash_log(msg);
6623+
fprintf(stderr, "=== ABORTING (clean exit before OOM killer) ===\n");
6624+
fflush(stderr);
6625+
std::signal(SIGABRT, SIG_DFL);
6626+
abort();
6627+
}
6628+
65906629
int64_t now = now_ms();
65916630
int64_t last_ioc = hb_ioc->load();
65926631
int64_t age_sec = (now - last_ioc) / 1000;

0 commit comments

Comments
 (0)