aboutsummaryrefslogtreecommitdiff
path: root/teensy/mem.c
diff options
context:
space:
mode:
authoriamcheeseman <[email protected]>2026-05-08 19:30:44 -0400
committeriamcheeseman <[email protected]>2026-05-08 19:30:44 -0400
commit5625a8626fe303748b205c80f87035593cf2f561 (patch)
tree5e5a5adb6f1265358ae21ec47cd384362345df5a /teensy/mem.c
Initial commit
Diffstat (limited to 'teensy/mem.c')
-rw-r--r--teensy/mem.c171
1 files changed, 171 insertions, 0 deletions
diff --git a/teensy/mem.c b/teensy/mem.c
new file mode 100644
index 0000000..2c938a6
--- /dev/null
+++ b/teensy/mem.c
@@ -0,0 +1,171 @@
+#include "mem.h"
+
+#include "common.h"
+#include "dyn_arr.h"
+
+// Array to track temp allocations.
+void **temp_allocations;
+
+#ifdef TEENSY_DEBUG
+
+#include <execinfo.h>
+
+#define BACKTRACE_SIZE 16
+
+struct alloc {
+ void *ptr;
+ size_t size;
+ int backtrace_len;
+ char **backtrace;
+};
+
+int allocations_cap;
+int allocations_len;
+struct alloc *allocations;
+
+#endif // TODO TEENSY_DEBUG
+
+void ty_init_mem(void)
+{
+#ifdef TEENSY_DEBUG
+ allocations_len = 0;
+ allocations_cap = 8;
+ allocations = malloc(sizeof(struct alloc) * 8);
+ if (!allocations)
+ ty_log_fatal(TY_ERR_MEM, "(%s) (track) ran out of memory", __func__);
+#endif // TEENSY_DEBUG
+
+ temp_allocations = ty_list_create(void*, 0);
+}
+
+void ty_deinit_mem(void)
+{
+ ty_list_free(temp_allocations);
+#ifdef TEENSY_DEBUG
+ fprintf(stderr, "%d allocations leaked\n", allocations_len);
+ for (int i = 0; i < allocations_len; i++) {
+ struct alloc *alloc = &allocations[i];
+ fprintf(
+ stderr,
+ "leaked %zu bytes at %p\n",
+ alloc->size,
+ alloc->ptr
+ );
+ for (int j = 0; j < alloc->backtrace_len; j++) {
+ fprintf(stderr, "\t%s\n", alloc->backtrace[j]);
+ }
+ putc('\n', stderr);
+
+ free(alloc->backtrace);
+ }
+ free(allocations);
+
+ if (allocations_len > 0)
+ exit(TY_ERR_MEM_LEAK);
+#endif // TEENSY_DEBUG
+}
+
+void ty_free_temp_allocs(void)
+{
+ for (int i = 0; i < ty_list_len(temp_allocations); i++) {
+ void *temp = temp_allocations[i];
+ ty_free(temp);
+ }
+ ty_list_clear(temp_allocations);
+}
+
+void *ty_alloc(size_t size)
+{
+ void *ptr = malloc(size);
+ if (!ptr)
+ ty_log_fatal(TY_ERR_MEM, "(%s) ran out of memory", __func__);
+
+#ifdef TEENSY_DEBUG
+ // Log allocation
+ struct alloc alloc;
+ void *bt[BACKTRACE_SIZE];
+ int bt_len = backtrace(bt, BACKTRACE_SIZE);
+ char **symbols = backtrace_symbols(bt, bt_len);
+
+ alloc.ptr = ptr;
+ alloc.size = size;
+ alloc.backtrace_len = bt_len;
+ alloc.backtrace = symbols;
+
+ if (allocations_len + 1 > allocations_cap) {
+ allocations_cap *= 2;
+ allocations = realloc(
+ allocations,
+ sizeof(struct alloc) * allocations_cap
+ );
+ if (!allocations)
+ ty_log_fatal(
+ TY_ERR_MEM,
+ "(%s) (track) ran out of memory",
+ __func__
+ );
+ }
+
+ allocations[allocations_len++] = alloc;
+#endif // TEENSY_DEBUG
+
+ return ptr;
+}
+
+void *ty_realloc(void *ptr, size_t new_size)
+{
+ if (new_size == 0) {
+ ty_free(ptr);
+ return NULL;
+ }
+
+ void *new_ptr = realloc(ptr, new_size);
+ if (!new_ptr)
+ ty_log_fatal(TY_ERR_MEM, "(%s) ran out of memory", __func__);
+
+#ifdef TEENSY_DEBUG
+ for (int i = 0; i < allocations_len; i++) {
+ struct alloc *alloc = &allocations[i];
+ if (alloc->ptr == ptr) {
+ alloc->ptr = new_ptr;
+ alloc->size = new_size;
+ break;
+ }
+ }
+#endif // TEENSY_DEBUG
+
+ return new_ptr;
+}
+
+void *ty_talloc(size_t size)
+{
+ void *ptr = ty_alloc(size);
+ ty_list_append(void*, &temp_allocations, ptr);
+ return ptr;
+}
+
+void ty_free(void *ptr)
+{
+ free(ptr);
+
+#ifdef TEENSY_DEBUG
+ for (int i = 0; i < allocations_len; i++) {
+ struct alloc *alloc = &allocations[i];
+ if (alloc->ptr == ptr) {
+ free(alloc->backtrace);
+ *alloc = allocations[allocations_len - 1];
+ allocations_len--;
+ break;
+ }
+ }
+#endif // TEENSY_DEBUG
+}
+
+int ty_alloc_count(void)
+{
+#ifdef TEENSY_DEBUG
+ return allocations_len;
+#else
+ return -1;
+#endif
+}