void esif_memtrace_free(void *mem_ptr) { struct memalloc_s *mem = NULL; struct memalloc_s **last = NULL; esif_ccb_write_lock(&g_memtrace.lock); mem = g_memtrace.allocated; last = &g_memtrace.allocated; while (mem) { if (mem_ptr == mem->mem_ptr) { *last = mem->next; native_free(mem); goto exit; } last = &mem->next; mem = mem->next; } exit: esif_ccb_write_unlock(&g_memtrace.lock); if (mem_ptr) { native_free(mem_ptr); atomic_inc(&g_memtrace.frees); } }
/** * Release a given area of memory from the heap. * * @param mem The memory area to release. */ void microbit_free(void *mem) { uint32_t *memory = (uint32_t *)mem; uint32_t *cb = memory-1; #if CONFIG_ENABLED(MICROBIT_DBG) && CONFIG_ENABLED(MICROBIT_HEAP_DBG) if (heap_count > 0) if(SERIAL_DEBUG) SERIAL_DEBUG->printf("microbit_free: %p\n", mem); #endif // Sanity check. if (memory == NULL) return; // If this memory was created from a heap registered with us, free it. for (int i=0; i < heap_count; i++) { if(memory > heap[i].heap_start && memory < heap[i].heap_end) { // The memory block given is part of this heap, so we can simply // flag that this memory area is now free, and we're done. *cb |= MICROBIT_HEAP_BLOCK_FREE; return; } } // If we reach here, then the memory is not part of any registered heap. // Forward it to the native heap allocator, and let nature take its course... native_free(mem); }
void esif_memtrace_exit() { struct memalloc_s *mem = NULL; char tracefile[MAX_PATH] = {0}; FILE *tracelog = NULL; esif_build_path(tracefile, sizeof(tracefile), ESIF_PATHTYPE_LOG, "memtrace.txt", NULL); esif_pathlist_exit(); esif_ccb_write_lock(&g_memtrace.lock); mem = g_memtrace.allocated; g_memtrace.allocated = NULL; esif_ccb_write_unlock(&g_memtrace.lock); CMD_OUT("MemTrace: Allocs=" ATOMIC_FMT " Frees=" ATOMIC_FMT "\n", atomic_read(&g_memtrace.allocs), atomic_read(&g_memtrace.frees)); if (!mem) { goto exit; } CMD_OUT("\n*** MEMORY LEAKS DETECTED ***\nFor details see %s\n", tracefile); esif_ccb_fopen(&tracelog, tracefile, "a"); if (tracelog) { time_t now = time(NULL); char timestamp[MAX_CTIME_LEN] = {0}; esif_ccb_ctime(timestamp, sizeof(timestamp), &now); fprintf(tracelog, "\n*** %.24s: MEMORY LEAKS DETECTED (%s) ***\n", timestamp, ESIF_UF_VERSION); } while (mem) { struct memalloc_s *node = mem; if (tracelog) { fprintf(tracelog, "[%s @%s:%d]: (%lld bytes) %p\n", mem->func, mem->file, mem->line, (long long)mem->size, mem->mem_ptr); } mem = mem->next; native_free(node->mem_ptr); native_free(node); } if (tracelog) { esif_ccb_fclose(tracelog); } exit: esif_ccb_lock_uninit(&g_memtrace.lock); }
void esif_memtrace_init() { struct memalloc_s *mem = NULL; esif_ccb_lock_init(&g_memtrace.lock); esif_ccb_write_lock(&g_memtrace.lock); mem = g_memtrace.allocated; // Ignore any allocations made before this function was called while (mem) { struct memalloc_s *node = mem; mem = mem->next; native_free(node); } g_memtrace.allocated = NULL; esif_ccb_write_unlock(&g_memtrace.lock); ESIF_TRACE_EXIT_INFO(); }
/** * Create and initialise a heap region within the current the heap region specified * by the linker script. * * If the requested amount is not available, then the amount requested will be reduced * automatically to fit the space available. * * @param ratio The proportion of the underlying heap to allocate. * * @return MICROBIT_OK on success, or MICROBIT_NO_RESOURCES if the heap could not be allocated. */ int microbit_create_nested_heap(float ratio) { uint32_t length; void *p; if (ratio <= 0.0 || ratio > 1.0) return MICROBIT_INVALID_PARAMETER; // Snapshot something at the top of the main heap. p = native_malloc(sizeof(uint32_t)); // Estimate the size left in our heap, taking care to ensure it lands on a word boundary. length = (uint32_t) (((float)(MICROBIT_HEAP_END - (uint32_t)p)) * ratio); length &= 0xFFFFFFFC; // Release our reference pointer. native_free(p); p = NULL; // Allocate memory for our heap. // We iteratively reduce the size of memory are allocate until it fits within available space. while (p == NULL) { p = native_malloc(length); if (p == NULL) { length -= 32; if (length <= 0) return MICROBIT_NO_RESOURCES; } } uint32_t start = (uint32_t) p; microbit_create_heap(start, start + length); return MICROBIT_OK; }
void *esif_memtrace_alloc( void *old_ptr, size_t size, const char *func, const char *file, int line ) { struct memalloc_s *mem = NULL; struct memalloc_s **last = NULL; void *mem_ptr = NULL; esif_ccb_write_lock(&g_memtrace.lock); mem = g_memtrace.allocated; last = &g_memtrace.allocated; if (file) { const char *slash = strrchr(file, *ESIF_PATH_SEP); if (slash) { file = slash + 1; } } if (old_ptr) { mem_ptr = native_realloc(old_ptr, size); // realloc(ptr, size) leaves ptr unaffected if realloc fails and size is nonzero if (!mem_ptr && size > 0) { goto exit; } while (mem) { if (old_ptr == mem->mem_ptr) { // realloc(ptr, 0) behaves like free(ptr) if (size == 0) { *last = mem->next; native_free(mem); } else { mem->mem_ptr = mem_ptr; mem->size = size; mem->func = func; mem->file = file; mem->line = line; } goto exit; } last = &mem->next; mem = mem->next; } } else { mem_ptr = native_malloc(size); if (mem_ptr) { esif_ccb_memset(mem_ptr, 0, size); atomic_inc(&g_memtrace.allocs); } } mem = (struct memalloc_s *)native_malloc(sizeof(*mem)); if (!mem) { goto exit; } esif_ccb_memset(mem, 0, sizeof(*mem)); mem->mem_ptr = mem_ptr; mem->size = size; mem->func = func; mem->file = file; mem->line = line; mem->next = g_memtrace.allocated; g_memtrace.allocated = mem; exit: esif_ccb_write_unlock(&g_memtrace.lock); return mem_ptr; }