/** * 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; }
/** * Attempt to allocate a given amount of memory from any of our configured heap areas. * * @param size The amount of memory, in bytes, to allocate. * * @return A pointer to the allocated memory, or NULL if insufficient memory is available. */ void *microbit_malloc(size_t size) { void *p; // Assign the memory from the first heap created that has space. for (int i=0; i < heap_count; i++) { p = microbit_malloc(size, heap[i]); if (p != NULL) { #if CONFIG_ENABLED(MICROBIT_DBG) && CONFIG_ENABLED(MICROBIT_HEAP_DBG) if(SERIAL_DEBUG) SERIAL_DEBUG->printf("microbit_malloc: ALLOCATED: %d [%p]\n", size, p); #endif return p; } } // If we reach here, then either we have no memory available, or our heap spaces // haven't been initialised. Either way, we try the native allocator. p = native_malloc(size); if (p != NULL) { #if CONFIG_ENABLED(MICROBIT_DBG) && CONFIG_ENABLED(MICROBIT_HEAP_DBG) // Keep everything trasparent if we've not been initialised yet if (heap_count > 0) if(SERIAL_DEBUG) SERIAL_DEBUG->printf("microbit_malloc: NATIVE ALLOCATED: %d [%p]\n", size, p); #endif return p; } // We're totally out of options (and memory!). #if CONFIG_ENABLED(MICROBIT_DBG) && CONFIG_ENABLED(MICROBIT_HEAP_DBG) // Keep everything transparent if we've not been initialised yet if (heap_count > 0) if(SERIAL_DEBUG) SERIAL_DEBUG->printf("microbit_malloc: OUT OF MEMORY [%d]\n", size); #endif #if CONFIG_ENABLED(MICROBIT_PANIC_HEAP_FULL) microbit_panic(MICROBIT_OOM); #endif return NULL; }
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; }