From f22a6bbcc3bd4a8ae69d8526f6bf20af6a73dc8d Mon Sep 17 00:00:00 2001 From: iProgramInCpp Date: Thu, 9 Jul 2026 17:48:54 +0300 Subject: [PATCH 1/3] Add low memory alarm handling in safeMalloc, safeCalloc, and safeRealloc. Currently, the actual low memory implementation is a placeholder. --- src/low_memory.c | 15 ++++++++++ src/utils.h | 72 ++++++++++++++++++++++++++++++++++-------------- 2 files changed, 67 insertions(+), 20 deletions(-) create mode 100644 src/low_memory.c diff --git a/src/low_memory.c b/src/low_memory.c new file mode 100644 index 000000000..db91bebdc --- /dev/null +++ b/src/low_memory.c @@ -0,0 +1,15 @@ +#include "utils.h" + +// Call when memory is running low. This triggers low memory alarm callback +// functions which evict caches from memory to free it up. +bool lowMemoryAlarm() +{ + return false; +} + +// Registers a low memory alarm callback. When a low memory alarm is triggered, +// the function provided will be called, and it should free memory if possible. +void registerLowMemoryAlarmCallback(bool(*callbackFunction)(void)) +{ + +} diff --git a/src/utils.h b/src/utils.h index c527822ba..b2bd17fea 100644 --- a/src/utils.h +++ b/src/utils.h @@ -32,6 +32,14 @@ #define TYPEOF(x) long long #endif +#if defined(__GNUC__) && (__GNUC__ >= 3 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96)) +#define LIKELY(cond) __builtin_expect(!!(cond), 1) +#define UNLIKELY(cond) __builtin_expect(!!(cond), 0) +#else +#define LIKELY(cond) (cond) +#define UNLIKELY(cond) (cond) +#endif + #define forEach(type, item, array, count) \ for (TYPEOF(count) item##_i_ = 0; item##_i_ < (count); ++item##_i_) \ for (type* item = &(array)[item##_i_]; item; item = NULL) @@ -80,46 +88,70 @@ static inline void* requireNotNullFunction(void* ptr, const char* file, int line #define requireNotNull(ptr) requireNotNullFunction((void*)ptr, __FILE__, __LINE__, #ptr) #define requireNotNullMessage(ptr, msg) requireNotNullFunction((void*)ptr, __FILE__, __LINE__, msg) +// Call when memory is running low. This triggers low memory alarm callback +// functions which evict caches from memory to free it up. +bool lowMemoryAlarm(); + +// Registers a low memory alarm callback. When a low memory alarm is triggered, +// the function provided will be called, and it should free memory if possible. +void registerLowMemoryAlarmCallback(bool(*callbackFunction)(void)); + // Safe allocation macros - check for nullptr and abort with file/line info static inline void *safeMallocFunction(size_t size, const char *file, int line) { - void *ret = malloc(size); - if (!ret) { - fprintf(stderr, "FATAL: malloc(%zu) failed at %s:%d\n", size, file, line); - abort(); + while (true) { + void* ret = malloc(size); + if (LIKELY(ret)) { + return ret; + } + if (!lowMemoryAlarm()) { + fprintf(stderr, "FATAL: malloc(%zu) failed at %s:%d\n", size, file, line); + abort(); + } } - return ret; } #define safeMalloc(size) safeMallocFunction(size, __FILE__, __LINE__) static inline void *safeCallocFunction(size_t count, size_t size, const char *file, int line) { - void *ret = calloc(count, size); - if (!ret) { - fprintf(stderr, "FATAL: calloc(%zu, %zu) failed at %s:%d\n", count, size, file, line); - abort(); + while (true) { + void *ret = calloc(count, size); + if (LIKELY(ret)) { + return ret; + } + if (!lowMemoryAlarm()) { + fprintf(stderr, "FATAL: calloc(%zu, %zu) failed at %s:%d\n", count, size, file, line); + abort(); + } } - return ret; } #define safeCalloc(count, size) safeCallocFunction(count, size, __FILE__, __LINE__) static inline void *safeReallocFunction(void *ptr, size_t size, const char *file, int line) { - void *ret = realloc(ptr, size); - if (!ret) { - fprintf(stderr, "FATAL: realloc(%zu) failed at %s:%d\n", size, file, line); - abort(); + while (true) { + void *ret = realloc(ptr, size); + if (LIKELY(ret)) { + return ret; + } + if (!lowMemoryAlarm()) { + fprintf(stderr, "FATAL: realloc(%zu) failed at %s:%d\n", size, file, line); + abort(); + } } - return ret; } #define safeRealloc(ptr, size) safeReallocFunction(ptr, size, __FILE__, __LINE__) #ifdef PLATFORM_PS2 static inline void *safeMemalignFunction(size_t alignment, size_t size, const char *file, int line) { - void *ret = memalign(alignment, size); - if (!ret) { - fprintf(stderr, "FATAL: memalign(%zu, %zu) failed at %s:%d\n", alignment, size, file, line); - abort(); + while (true) { + void *ret = memalign(alignment, size); + if (LIKELY(ret)) { + return ret; + } + if (!lowMemoryAlarm()) { + fprintf(stderr, "FATAL: memalign(%zu, %zu) failed at %s:%d\n", alignment, size, file, line); + abort(); + } } - return ret; } #define safeMemalign(alignment, size) safeMemalignFunction(alignment, size, __FILE__, __LINE__) From de4b7bc42c231cfb5e23c7ba43b409bee8f378f2 Mon Sep 17 00:00:00 2001 From: iProgramInCpp Date: Thu, 9 Jul 2026 17:53:32 +0300 Subject: [PATCH 2/3] Actually implement the low memory callback system. --- src/low_memory.c | 21 +++++++++++++++++++-- src/utils.h | 3 ++- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/low_memory.c b/src/low_memory.c index db91bebdc..1fd256f97 100644 --- a/src/low_memory.c +++ b/src/low_memory.c @@ -1,15 +1,32 @@ #include "utils.h" +#define MAX_CALLBACKS 64 + +typedef bool(*LowMemoryAlarmCallback)(void); + +LowMemoryAlarmCallback lowMemoryAlarmCallbacks[MAX_CALLBACKS]; +int lowMemoryAlarmCallbackCount = 0; + // Call when memory is running low. This triggers low memory alarm callback // functions which evict caches from memory to free it up. bool lowMemoryAlarm() { - return false; + bool didSomething = false; + for (int i = 0; i < lowMemoryAlarmCallbackCount; i++) { + bool result = lowMemoryAlarmCallbacks[i](); + if (result) + didSomething = true; + } + return didSomething; } // Registers a low memory alarm callback. When a low memory alarm is triggered, // the function provided will be called, and it should free memory if possible. void registerLowMemoryAlarmCallback(bool(*callbackFunction)(void)) { - + if (lowMemoryAlarmCallbackCount >= MAX_CALLBACKS) { + fprintf(stderr, "registerLowMemoryAlarmCallback: Cannot register another callback, %d already registered.\n", lowMemoryAlarmCallbackCount); + return; + } + lowMemoryAlarmCallbacks[lowMemoryAlarmCallbackCount++] = callbackFunction; } diff --git a/src/utils.h b/src/utils.h index b2bd17fea..03bb765a8 100644 --- a/src/utils.h +++ b/src/utils.h @@ -93,7 +93,8 @@ static inline void* requireNotNullFunction(void* ptr, const char* file, int line bool lowMemoryAlarm(); // Registers a low memory alarm callback. When a low memory alarm is triggered, -// the function provided will be called, and it should free memory if possible. +// the function provided will be called. Your callback should return TRUE if it +// freed memory, or FALSE if nothing changed. void registerLowMemoryAlarmCallback(bool(*callbackFunction)(void)); // Safe allocation macros - check for nullptr and abort with file/line info From 6c7b63099b303bc171f5bcfcc59d2589a4997d75 Mon Sep 17 00:00:00 2001 From: iProgramInCpp Date: Thu, 9 Jul 2026 17:57:39 +0300 Subject: [PATCH 3/3] Fix web-meta build. --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 924d470fa..b4cbddb75 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -95,6 +95,7 @@ if(PLATFORM STREQUAL "web-meta") set(SOURCES src/data_win.c src/binary_reader.c + src/low_memory.c ) else() file(GLOB SOURCES src/*.c)