Browse Source

Changed plenty of stuff: fixed free list joining and splitting, better printing, better realloc, better interfaces, better stuff in general

main
Titouan Rigoudy 11 years ago
parent
commit
66dbd45fc1
5 changed files with 128 additions and 41 deletions
  1. +16
    -13
      ya_block.c
  2. +4
    -4
      ya_block.h
  3. +55
    -15
      ya_freelist.c
  4. +16
    -2
      ya_freelist.h
  5. +37
    -7
      yamalloc.c

+ 16
- 13
ya_block.c View File

@ -66,8 +66,8 @@ void block_print_range(intptr_t *start, intptr_t *end) {
intptr_t size;
for (block = start; block < end; block += size) {
size = block_size(block);
printf("Block at %p size = %ld alloc = %d\n",
block, size, block_is_alloc(block));
ya_debug("%d %p:%ld\n",
block_is_alloc(block), block, size);
}
}
#endif
@ -164,8 +164,8 @@ intptr_t *block_split(intptr_t *block, intptr_t size) {
return block + size;
}
/* Try to find a free block at least size words big by walking the boundary
* tags. If no block is found the heap is grown adequately.
/* Try to find a free block at least size min_size words large by walking the
* boundary tags. Does not grow the heap.
* Returns a pointer to the block or NULL in case of failure. */
intptr_t *block_find(intptr_t min_size) {
intptr_t *block;
@ -176,8 +176,8 @@ intptr_t *block_find(intptr_t min_size) {
return block;
}
}
// could not find block, extend heap
return heap_extend(min_size);
// could not find block
return NULL;
}
/* Initializes the heap by calling sbrk to allocate some starter memory.
@ -195,26 +195,29 @@ intptr_t *heap_init() {
heap_start += 2; // space for the first block's tags + dword alignment
heap_end = heap_start + size;
block_init(heap_start, size);
fl_set_prev(heap_start, NULL);
fl_set_next(heap_start, NULL);
fl_free(heap_start);
ya_debug("heap_init: start = %p, end = %p, size = %ld\n",
heap_start, heap_end, size);
return heap_start;
}
/* Extends the heap by at least size_w words by calling sbrk.
/* Extends the heap by at least n_bytes bytes by calling sbrk.
* Returns a pointer to the last (free) block or NULL in case of failure. */
intptr_t *heap_extend(intptr_t size) {
size = block_fit(round_to(WORD_SIZE * size, CHUNK_SIZE));
intptr_t *heap_extend(size_t n_bytes) {
// request an integer number of blocks
intptr_t size = block_fit(round_to(n_bytes, CHUNK_SIZE));
void *ptr = sbrk(WORD_SIZE * size);
if (ptr == (void *) - 1) {
if (ptr == (void *) -1) {
return NULL;
}
intptr_t *block = ptr; // == old heap_end
heap_end = block + size;
block_init(block, size);
fl_free(block);
fl_join(block);
block = block_join(block);
ya_debug("heap_extend: old end = %p, new end = %p, size = %ld\n",
block, heap_end, size);
ya_print_blocks();
return block_join(ptr);
return block;
}

+ 4
- 4
ya_block.h View File

@ -63,9 +63,9 @@ static inline intptr_t block_size(intptr_t *block) {
* Returns the pointer to the start of the heap or NULL in case of failure. */
intptr_t *heap_init();
/* Extends the heap by at least size_w words by calling sbrk.
/* Extends the heap by at least n_bytes bytes by calling sbrk.
* Returns a pointer to the last (free) block or NULL in case of failure. */
intptr_t *heap_extend(intptr_t size_w);
intptr_t *heap_extend(size_t n_bytes);
#ifdef YA_DEBUG
/* Prints each block in the range from the block at start to the one at end */
@ -104,8 +104,8 @@ intptr_t *block_join(intptr_t *block);
* Returns a pointer to the second block or NULL if no split occurred. */
intptr_t *block_split(intptr_t *block, intptr_t size);
/* Try to find a free block at least min_size words big by walking the
* boundary tags. If no block is found the heap is grown adequately.
/* Try to find a free block at least min_size words large by walking the
* boundary tags. Does not grow the heap.
* Returns a pointer to the block or NULL in case of failure. */
intptr_t *block_find(intptr_t min_size);


+ 55
- 15
ya_freelist.c View File

@ -3,15 +3,6 @@
* ya_freelist.c
*/
/* Block layout:
*
* -2 -1 0 size-4 size-3
* +------+------+-------- - - - - - - - --------+------+------+
* | prev | size | data... | size | next |
* +------+------+-------- - - - - - - - --------+------+------+
*
*/
/*----------*/
/* Includes */
/*----------*/
@ -35,7 +26,7 @@ intptr_t *fl_end = NULL; // sorted decreasing
#ifdef YA_DEBUG
void fl_debug_print() {
for (intptr_t *block = fl_start; block != NULL; block = fl_next(block)) {
printf("Free block %p:%ld\n", block, block_size(block));
ya_debug("%p:%ld\n", block, block_size(block));
}
}
#endif
@ -62,11 +53,15 @@ void fl_alloc(intptr_t *block) {
/* Adds the freed block to the appropriate in the free list, which is kept
* in sorted increasing order. */
void fl_free(intptr_t *block) {
intptr_t *next;
for (next = fl_start; next && block < next; next = fl_next(next)) {
// *whistle*
if (!fl_start && !fl_end) {
// add to empty list
fl_set_prev(block, NULL);
fl_set_next(block, NULL);
fl_start = block;
fl_end = block;
return;
}
if (next == fl_start) {
if (block < fl_start) {
// preprend block to the free list
fl_set_prev(block, NULL);
fl_set_next(block, fl_start);
@ -74,7 +69,7 @@ void fl_free(intptr_t *block) {
fl_start = block;
return;
}
if (!next) {
if (block > fl_end) {
// append block to the free list
fl_set_prev(block, fl_end);
fl_set_next(block, NULL);
@ -83,6 +78,10 @@ void fl_free(intptr_t *block) {
return;
}
// splice the block in the middle of the list
intptr_t *next;
for (next = fl_start; next && next < block; next = fl_next(next)) {
// *whistle*
}
intptr_t *prev = fl_prev(next);
fl_set_prev(block, prev);
fl_set_next(block, next);
@ -104,6 +103,47 @@ intptr_t *fl_find(intptr_t min_size) {
/* Force split of free block [block_size] into [size, block_size - size]. */
void fl_split(intptr_t *block, intptr_t size) {
fl_set_next(block, block+size);
if (block == fl_end) {
fl_end = block+size;
}
fl_set_prev(block+size, block);
}
void fl_join_next(intptr_t *block) {
intptr_t *next = block + block_size(block);
if (fl_next(block) == next) {
// skip a block
ya_debug("fl_join_next: %p:%ld + %p:%ld -> %p:%ld\n",
block, block_size(block), next, block_size(next),
block, block_size(block) + block_size(next));
fl_set_next(block, fl_next(next));
fl_set_prev(next, fl_prev(block));
if (fl_next(next) == NULL) {
fl_end = block;
}
}
}
void fl_join_prev(intptr_t *block) {
intptr_t *free_prev = fl_prev(block);
if (!free_prev) {
return;
}
// will not segfault because there is at least one block preceding
intptr_t *prev = block - block[-4];
if (prev == free_prev) {
ya_debug("fl_join_prev: %p:%ld + %p:%ld -> %p:%ld\n",
block, block_size(block), prev, block_size(prev),
prev, block_size(block) + block_size(prev));
fl_set_prev(block, fl_prev(prev));
fl_set_next(prev, fl_next(block));
if (fl_next(block) == NULL) {
fl_end = prev;
}
}
}
void fl_join(intptr_t *block) {
fl_join_next(block);
fl_join_prev(block);
}

+ 16
- 2
ya_freelist.h View File

@ -3,6 +3,15 @@
* ya_freelist.h
*/
/* Block layout:
*
* -2 -1 0 size-4 size-3
* +------+------+-------- - - - - - - - --------+------+------+
* | prev | size | data... | size | next |
* +------+------+-------- - - - - - - - --------+------+------+
*
*/
#ifndef YA_FREELIST_H
#define YA_FREELIST_H
@ -13,6 +22,7 @@
#include <stdint.h> // for intptr_t
#include "ya_block.h"
#include "ya_debug.h"
/*---------*/
/* Inlines */
@ -45,7 +55,7 @@ void fl_debug_print();
/* Splices the allocated block out of the free list. */
void fl_alloc(intptr_t *block);
/* Adds the freed block to the start of the free list. */
/* Adds the freed block to the appropriate place in free list. */
void fl_free(intptr_t *block);
/* Returns the first block in the free list at min_size words long.
@ -55,6 +65,10 @@ intptr_t *fl_find(intptr_t min_size);
/* Force split of block [block_size] into [size, block_size - size]. */
void fl_split(intptr_t *block, intptr_t size);
/* Joins are unnecessary because the pointers will still be ok after a join. */
void fl_join_prev(intptr_t *block);
void fl_join_next(intptr_t *block);
void fl_join(intptr_t *block);
#endif

+ 37
- 7
yamalloc.c View File

@ -37,10 +37,17 @@ void *malloc(size_t n_bytes) {
return NULL;
}
}
intptr_t min_size = block_fit(n_bytes);
intptr_t *block = block_find(min_size);
block_split(block, min_size);
intptr_t size = block_fit(n_bytes);
intptr_t *block = block_find(size);
if (!block) {
block = heap_extend(n_bytes);
}
if (block_split(block, size)) {
// block was indeed split, so splt it in the free list as well
fl_split(block, size);
}
block_alloc(block);
fl_alloc(block);
return block;
}
@ -53,6 +60,8 @@ void free(void *ptr) {
return; // TODO: provoke segfault
}
block_free(block);
fl_free(block);
fl_join(block);
block_join(block);
}
@ -78,6 +87,7 @@ void *realloc(void *ptr, size_t n_bytes) {
}
if (n_bytes == 0) {
free(ptr);
return NULL;
}
intptr_t *block = ptr;
if (block < heap_start) {
@ -91,26 +101,46 @@ void *realloc(void *ptr, size_t n_bytes) {
if (new_size < size) {
intptr_t *next = block_split(block, new_size);
if (next) {
fl_free(next); // add the next from the free list
fl_join_next(next);
block_join_next(next); // coalesce the leftovers
}
block_alloc(block);
// no need to remove it from the free list, it wasn't in it
return block;
}
intptr_t *next = block + size;
if (next == heap_end ||
(!block_is_alloc(next) && next + block_size(next) == heap_end)) {
// grow the heap and extend block
next = heap_extend(n_bytes);
fl_free(block);
fl_join_next(block);
block_join_next(block);
if (block_split(block, new_size)) {
fl_split(block, new_size);
}
block_alloc(block);
fl_alloc(block);
return block;
}
// try to use next free block
if (next < heap_end) {
intptr_t next_size = block_size(next);
if (!block_is_alloc(next) && new_size <= size + next_size) {
// try to split the next block at the right size
if (block_split(next, new_size - size)) {
// split successful, must split in the free list too
fl_split(block, new_size);
}
fl_alloc(next); // remove the next block from the free list
fl_join_next(block);
block_join_next(block); // coalesce
block_split(block, new_size); // split if possible
// no need to coalesce
block_alloc(block); // mark block as allocated
return block;
}
}
// resizing failed, so allocate a whole new block and copy
// could handle the case when the block is the last in the heap
// a bit more gracefully and just grow the heap instead of copying
intptr_t *new_block = malloc(n_bytes);
for (int i = 0; i < size; i++) {
new_block[i] = block[i];


Loading…
Cancel
Save