/**
  * 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;
}
Ejemplo n.º 3
0
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;
}