/** Free a memory block * * @param addr The address of the block. * */ void free(const void *addr) { if (addr == NULL) return; futex_down(&malloc_futex); /* Calculate the position of the header. */ heap_block_head_t *head = (heap_block_head_t *) (addr - sizeof(heap_block_head_t)); block_check(head); malloc_assert(!head->free); heap_area_t *area = head->area; area_check(area); malloc_assert((void *) head >= (void *) AREA_FIRST_BLOCK_HEAD(area)); malloc_assert((void *) head < area->end); /* Mark the block itself as free. */ head->free = true; /* Look at the next block. If it is free, merge the two. */ heap_block_head_t *next_head = (heap_block_head_t *) (((void *) head) + head->size); if ((void *) next_head < area->end) { block_check(next_head); if (next_head->free) block_init(head, head->size + next_head->size, true, area); } /* Look at the previous block. If it is free, merge the two. */ if ((void *) head > (void *) AREA_FIRST_BLOCK_HEAD(area)) { heap_block_foot_t *prev_foot = (heap_block_foot_t *) (((void *) head) - sizeof(heap_block_foot_t)); heap_block_head_t *prev_head = (heap_block_head_t *) (((void *) head) - prev_foot->size); block_check(prev_head); if (prev_head->free) block_init(prev_head, prev_head->size + head->size, true, area); } heap_shrink(area); futex_up(&malloc_futex); }
/** Reallocate memory block * * @param addr Already allocated memory or NULL. * @param size New size of the memory block. * * @return Reallocated memory or NULL. * */ void *realloc(const void *addr, const size_t size) { if (addr == NULL) return malloc(size); futex_down(&malloc_futex); /* Calculate the position of the header. */ heap_block_head_t *head = (heap_block_head_t *) (addr - sizeof(heap_block_head_t)); block_check(head); malloc_assert(!head->free); heap_area_t *area = head->area; area_check(area); malloc_assert((void *) head >= (void *) AREA_FIRST_BLOCK_HEAD(area)); malloc_assert((void *) head < area->end); void *ptr = NULL; bool reloc = false; size_t real_size = GROSS_SIZE(ALIGN_UP(size, BASE_ALIGN)); size_t orig_size = head->size; if (orig_size > real_size) { /* Shrink */ if (orig_size - real_size >= STRUCT_OVERHEAD) { /* * Split the original block to a full block * and a trailing free block. */ block_init((void *) head, real_size, false, area); block_init((void *) head + real_size, orig_size - real_size, true, area); heap_shrink(area); } ptr = ((void *) head) + sizeof(heap_block_head_t); } else { /* * Look at the next block. If it is free and the size is * sufficient then merge the two. Otherwise just allocate * a new block, copy the original data into it and * free the original block. */ heap_block_head_t *next_head = (heap_block_head_t *) (((void *) head) + head->size); if (((void *) next_head < area->end) && (head->size + next_head->size >= real_size) && (next_head->free)) { block_check(next_head); block_init(head, head->size + next_head->size, false, area); split_mark(head, real_size); ptr = ((void *) head) + sizeof(heap_block_head_t); next_fit = NULL; } else reloc = true; } futex_up(&malloc_futex); if (reloc) { ptr = malloc(size); if (ptr != NULL) { memcpy(ptr, addr, NET_SIZE(orig_size)); free(addr); } } return ptr; }
/* * Return an element from the heap, located at the given index */ static HeapElement * heap_delete(Heap * h,int idx) { HeapElement *he,*helast; int pidx; HeapInternCmp cmp_func; DBG(debug("heap_delete(h=%p,idx=%d)\n",h,idx)); LLOG(HSIZE(h)); if (idx < 0 || idx >= HSIZE(h)) { LLOG(idx); return NULL; } if (h->hpMode == HEAP_MAXIMIZE) cmp_func = heap_larger; else cmp_func = heap_smaller; /* Remember the current element */ he = HARRAY(h,idx); /* Remember the last element */ helast = HLAST(h); h->hpFilled--; if (idx == HSIZE(h)) /* This is the last element */ goto end_label; /* Put the last element in the position of the current */ HARRAY(h,idx) = helast; if (h->hpChgFunc) h->hpChgFunc(HARRAY(h,idx)->heData,idx); /* Heapify the new subtree. Then if the root of the subtree * is larger than its parent, propagate it up the tree until * it finds is proper location */ heap_heapify(h,idx); pidx = HPARENT(idx); LLOG(pidx); if (idx > 0) { while (cmp_func(h,HARRAY(h,idx),HARRAY(h,pidx))) { heap_swap(h,idx,pidx); idx = pidx; if (idx == 0) break; pidx = HPARENT(idx); } } end_label: if (NEEDS2SHRINK(h)) heap_shrink(h); return he; }