/*! * \brief Add a new memory region to the heap. * * This function can be called more than once to manage non-continous * memory regions. It is automatically called by Nut/OS during * initialization. * * \param addr Start address of the memory region. * \param size Number of bytes of the memory region. */ void NutHeapRootAdd(HEAPNODE ** root, void *addr, size_t size) { HEAPNODE *node = (HEAPNODE *) NUTMEM_TOP_ALIGN((uintptr_t) addr); node->hn_size = NUTMEM_BOTTOM_ALIGN(size - ((uintptr_t) node - (uintptr_t) addr)); #ifdef NUTDEBUG_HEAP NutHeapDebugRootFree(root, PrepareUserArea(node), NULL, 0); #else NutHeapRootFree(root, PrepareUserArea(node)); #endif }
/*! * \brief Return a block to heap memory. * * This function simply calls NutHeapFree(). It overrides the function * of the runtime library, when the application is linked with nutcrt or * nutcrtf. * * \param p Points to a memory block previously allocated * through a call to malloc(). */ void dbg_free(void *p, CONST char *file, int line) { NutHeapDebugRootFree(&heapFreeList, p, file, line); }
void *NutHeapRootRealloc(HEAPNODE ** root, void *block, size_t size) #endif { HEAPNODE *node; HEAPNODE **npp; HEAPNODE *fnode; void *newmem; #ifdef NUTDEBUG_HEAP /* With NULL pointer the call is equivalent to alloc. */ if (block == NULL) { return NutHeapDebugRootAlloc(root, size, file, line); } /* With zero size the call is equivalent to free. */ if (size == 0) { if (NutHeapDebugRootFree(root, block, file, line)) { return NULL; } return block; } /* Revive our node pointer. */ fnode = (HEAPNODE *) ((uintptr_t) block - (NUT_HEAP_OVERHEAD + NUTMEM_GUARD_BYTES)); /* Sanity check. */ if (DebugValidateUserArea(fnode, file, line)) { return NULL; } #else if (block == NULL) { return NutHeapRootAlloc(root, size); } if (size == 0) { if (NutHeapRootFree(root, block)) { return NULL; } return block; } fnode = (HEAPNODE *) ((uintptr_t) block - (NUT_HEAP_OVERHEAD + NUTMEM_GUARD_BYTES)); if (ValidateUserArea(fnode)) { return NULL; } #endif /* Determine the minimum size. Add optional guard and alignment bytes. Make sure that a HEAPNODE structure fits. */ size += NUT_HEAP_OVERHEAD + NUTMEM_GUARD_BYTES * 2; if (size < sizeof(HEAPNODE)) { size = sizeof(HEAPNODE); } size = NUTMEM_TOP_ALIGN(size); /* * Expansion. */ if (size > fnode->hn_size) { size_t size_miss = size - fnode->hn_size; /* Find the free node following next. */ node = *root; npp = root; while (node && node < fnode) { npp = &node->hn_next; node = node->hn_next; } /* If we found a node and if this node is large enough and if it directly follows without a gap, then use it. */ if (node && node->hn_size >= size_miss && /* */ (uintptr_t) fnode + fnode->hn_size == (uintptr_t) node) { /* Check if the following node is large enough to be split. */ if (node->hn_size - size_miss >= NUTMEM_HEAPNODE_MIN) { /* Adjust the allocated size. */ fnode->hn_size += size_miss; /* Insert the remaining part into the free list. */ *npp = (HEAPNODE *) ((uintptr_t) node + size_miss); /* Due to possible overlapping it is important to set the pointer first, then the size. */ (*npp)->hn_next = node->hn_next; (*npp)->hn_size = node->hn_size - size_miss; PrepareUserArea(fnode); } else { /* Adjust the allocated size. */ fnode->hn_size += node->hn_size; PrepareUserArea(fnode); /* Remove the merged node from the free list. */ *npp = node->hn_next; } /* Return the original pointer. */ return block; } /* Relocate if no sufficiently large block follows. */ #ifdef NUTDEBUG_HEAP newmem = NutHeapDebugRootAlloc(root, size, file, line); #else newmem = NutHeapRootAlloc(root, size); #endif if (newmem) { memcpy(newmem, block, fnode->hn_size - NUT_HEAP_OVERHEAD - 2 * NUTMEM_GUARD_BYTES); #ifdef NUTDEBUG_HEAP NutHeapDebugRootFree(root, block, file, line); #else NutHeapRootFree(root, block); #endif } return newmem; } /* * Reduction. */ if (size < fnode->hn_size - NUTMEM_HEAPNODE_MIN) { /* Release the remaining part to the free list. */ node = (HEAPNODE *) ((uintptr_t) fnode + size); node->hn_size = fnode->hn_size - size; #ifdef NUTDEBUG_HEAP NutHeapDebugRootFree(root, PrepareUserArea(node), NULL, 0); #else NutHeapRootFree(root, PrepareUserArea(node)); #endif /* Adjust the allocated size. */ fnode->hn_size = size; PrepareUserArea(fnode); } return block; }