Browse Source

Moved heap and block management to ya_block.c

main
Titouan Rigoudy 11 years ago
parent
commit
e111b226d8
5 changed files with 290 additions and 170 deletions
  1. +1
    -1
      Makefile
  2. +172
    -0
      ya_block.c
  3. +101
    -0
      ya_block.h
  4. +15
    -168
      yamalloc.c
  5. +1
    -1
      yamalloc.h

+ 1
- 1
Makefile View File

@ -10,7 +10,7 @@ test: yatest
%.o: %.c %.o: %.c
$(CC) -c $^ $(CPPFLAGS) $(CFLAGS) $(CC) -c $^ $(CPPFLAGS) $(CFLAGS)
yatest: yatest.o yamalloc.o
yatest: yatest.o yamalloc.o ya_block.o
$(CC) -o $@ $^ $(CFLAGS) $(CC) -o $@ $^ $(CFLAGS)
clean: clean:


+ 172
- 0
ya_block.c View File

@ -0,0 +1,172 @@
/*
* Yet Another Malloc
* ya_block.c
* Defines operations on blocks and boundary tags
*/
/*----------*/
/* Includes */
/*----------*/
#include "ya_block.h"
#include "ya_debug.h"
/*---------*/
/* Globals */
/*---------*/
intptr_t *heap_start = NULL; // with space for 2 words before
intptr_t *heap_end = NULL; // first block outside heap
/*----------------------*/
/* Function definitions */
/*----------------------*/
#ifdef YA_DEBUG
void block_print_range(intptr_t *start, intptr_t *end) {
intptr_t *block;
intptr_t block_size;
for (block = start; block < end; block += block_size) {
block_size = YA_SZ_BLK(block);
printf("Block at %p size = %ld alloc = %d\n",
block, block_size, YA_IS_ALLOC_BLK(block));
}
}
#endif
/* Initializes the block's boundary tags. */
void block_init(intptr_t *block, intptr_t size) {
block[-1] = size;
block[size - 2] = size;
}
/* Sets the allocated bit in the block's boundary tags. */
void block_alloc(intptr_t *block) {
intptr_t block_size = YA_SZ_BLK(block);
block[-1] |= 1;
block[block_size-2] |= 1;
}
/* Erases the allocated bit in the block's boundary tags. */
void block_free(intptr_t *block) {
intptr_t block_size = YA_SZ_BLK(block);
block[-1] &= -2;
block[block_size-2] &= -2;
}
/* Returns the size in words of the smallest block that can
* store n_bytes bytes. Takes alignment and boundary tags into account */
intptr_t block_fit(size_t n_bytes) {
intptr_t n_words = YA_ROUND_DIV(n_bytes, YA_SZ_WORD); // size in words
// round to dword and make space for tags
intptr_t size = 2 + YA_ROUND(n_words, 2);
ya_debug("block_fit: requested = %ld, allocating = %ld * %ld = %ld\n",
n_bytes, size, YA_SZ_WORD, size * YA_SZ_WORD);
return size;
}
/* Tries to coalesce a block with its previous neighbor.
* Returns a pointer to the coalesced block. */
intptr_t *block_join_prev(intptr_t *block) {
intptr_t prev_size = YA_SZ_TAG(block[-2]);
intptr_t *prev = block - prev_size;
if (prev <= heap_start || YA_IS_ALLOC_BLK(prev)) {
return block;
}
intptr_t block_size = YA_SZ_BLK(block);
block_init(prev, prev_size + block_size);
ya_debug("block_join_prev: joining %p:%ld and %p:%ld -> %p:%ld\n",
block, block_size, prev, prev_size, prev, prev_size + block_size);
return prev;
}
/* Tries to colesce a block with its next neighbor.
* Returns the unchanged pointer to the block. */
intptr_t *block_join_next(intptr_t *block) {
intptr_t block_size = YA_SZ_BLK(block);
intptr_t *next = block + block_size;
if (next >= heap_end || YA_IS_ALLOC_BLK(next)) {
return block;
}
intptr_t next_size = YA_SZ_BLK(next);
block_init(block, block_size + next_size);
ya_debug("block_join_next: joining %p:%ld and %p:%ld -> %p:%ld\n",
block, block_size, next, next_size, block, block_size + next_size);
return block;
}
/* Tries to coalesce a block with its previous and next neighbors.
* Returns a pointer to the coalesced block. */
intptr_t *block_join(intptr_t *block) {
if (block > heap_start) {
block = block_join_prev(block);
}
return block_join_next(block);
}
/* Split the block [block_size] into [size, block_size - size] if possible
* Returns a pointer to the second block or NULL if no split occurred. */
intptr_t *block_split(intptr_t *block, intptr_t size) {
intptr_t next_size = YA_SZ_BLK(block) - size;
if (next_size < YA_MIN_SZ_BLK) {
return NULL; // not enough space to warrant a split
}
block_init(block, size);
block_init(block + size, next_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.
* Returns a pointer to the block or NULL in case of failure. */
intptr_t *block_find(intptr_t size) {
intptr_t *block;
intptr_t block_size;
for (block = heap_start; block < heap_end; block += block_size) {
block_size = YA_SZ_BLK(block);
if (!YA_IS_ALLOC_BLK(block) && size <= block_size) {
return block;
}
}
// could not find block, extend heap
return heap_extend(size);
}
/* Initializes the heap by calling sbrk to allocate some starter memory.
* Sets heap_start and heap_end to their appropriate values.
* Returns the pointer to the start of the heap or NULL in case of failure. */
intptr_t *heap_init() {
intptr_t size_w = YA_SZ_CHUNK / YA_SZ_WORD;
void *ptr = sbrk(YA_SZ_WORD * (size_w + 2));
if (ptr == (void*) -1) {
heap_start = NULL;
heap_end = NULL;
return NULL;
}
heap_start = ptr; // cast to intptr_t *
heap_start += 2; // space for the first block[-1] + dword alignment
heap_end = heap_start + size_w;
block_init(heap_start, size_w);
ya_debug("heap_init: start = %p, end = %p, size_w = %ld\n",
heap_start, heap_end, size_w);
return heap_start;
}
/* Extends the heap by at least size_w words 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 size = YA_ROUND(size_w * YA_SZ_WORD, YA_SZ_CHUNK);
size_w = size / YA_SZ_WORD;
ya_debug("heap_extend: size_w = %ld\n", size_w);
void *ptr = sbrk(size);
if (ptr == (void *) - 1) {
return NULL;
}
intptr_t *block = ptr; // == old heap_end
heap_end = block + size_w;
block_init(block, size_w);
ya_debug("heap_extend: old end = %p, new end = %p, size_w = %ld\n",
block, heap_end, size_w);
ya_print_blocks();
return block_join(ptr);
}

+ 101
- 0
ya_block.h View File

@ -0,0 +1,101 @@
/*
* Yet Another Malloc
* ya_block.h
*/
#ifndef YA_BLOCK_H
#define YA_BLOCK_H
/*----------*/
/* Includes */
/*----------*/
#include <stddef.h> // for size_t
#include <stdint.h> // for intptr_t
/*-----------*/
/* Constants */
/*-----------*/
#define YA_SZ_WORD (sizeof(intptr_t)) // big enough to hold a pointer
#define YA_SZ_DWORD (2 * YA_SZ_WORD) // storage is aligned to a dword
#define YA_SZ_CHUNK 8192 // request memory 8k by 8k from OS
#define YA_MIN_SZ_BLK 4 // smallest block: dword-aligned with two boundary tags
/*--------*/
/* Macros */
/*--------*/
#define YA_IS_ALLOC_TAG(tag) ((tag) & 1)
#define YA_SZ_TAG(tag) ((tag) & -2)
#define YA_IS_ALLOC_BLK(block) YA_IS_ALLOC_TAG((block)[-1])
#define YA_SZ_BLK(block) YA_SZ_TAG((block)[-1])
#define YA_IS_ALLOC_END(b_end) YA_IS_ALLOC_TAG((b_end)[0])
#define YA_SZ_END(b_end) YA_SZ_TAG((b_end)[0])
#define YA_ROUND_DIV(n, m) (((n) + ((m)-1)) / (m))
#define YA_ROUND(n, m) (YA_ROUND_DIV(n,m) * (m))
/*---------*/
/* Globals */
/*---------*/
extern intptr_t *heap_start; // with space for 2 words before
extern intptr_t *heap_end ; // first block outside heap
/*--------------*/
/* Declarations */
/*--------------*/
/* Initializes the heap by calling sbrk to allocate some starter memory.
* Sets heap_start and heap_end to their appropriate values.
* 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.
* Returns a pointer to the last (free) block or NULL in case of failure. */
intptr_t *heap_extend(intptr_t size_w);
#ifdef YA_DEBUG
/* Prints each block in the range from the block at start to the one at end */
void block_print_range(intptr_t *start, intptr_t *end);
#endif
/* Initializes the block's boundary tags. */
void block_init(intptr_t *block, intptr_t size);
/* Sets the allocated bit in the block's boundary tags. */
void block_alloc(intptr_t *block);
/* Erases the allocated bit in the block's boundary tags. */
void block_free(intptr_t *block);
/* Returns the size in words of the smallest block that can
* store n_bytes bytes. Takes alignment and boundary tags into account */
intptr_t block_fit(size_t n_bytes);
/* Tries to coalesce a block with its previous neighbor.
* Returns a pointer to the coalesced block. */
intptr_t *block_join_prev(intptr_t *block);
/* Tries to colesce a block with its next neighbor.
* Returns the unchanged pointer to the block. */
intptr_t *block_join_next(intptr_t *block);
/* Tries to coalesce a block with its previous and next neighbors.
* Returns a pointer to the coalesced block. */
intptr_t *block_join(intptr_t *block);
/* Split the block [block_size] into [size, block_size - size] if possible
* 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 size words big by walking the boundary
* tags. If no block is found the heap is grown adequately.
* Returns a pointer to the block or NULL in case of failure. */
intptr_t *block_find(intptr_t size);
#endif

+ 15
- 168
yamalloc.c View File

@ -3,11 +3,15 @@
* yamalloc.c * yamalloc.c
*/ */
/*---------------------*/
/* Feature test macros */ /* Feature test macros */
/*---------------------*/
#define _DEFAULT_SOURCE // for sbrk #define _DEFAULT_SOURCE // for sbrk
/*----------*/
/* Includes */ /* Includes */
/*----------*/
#include <unistd.h> #include <unistd.h>
#include <stdio.h> #include <stdio.h>
@ -15,193 +19,36 @@
#include "yamalloc.h" #include "yamalloc.h"
#include "ya_debug.h" #include "ya_debug.h"
#include "ya_block.h"
/*-----------*/
/* Constants */ /* Constants */
/*-----------*/
#define YA_SZ_WORD (sizeof(intptr_t)) // big enough to hold a pointer
#define YA_SZ_DWORD (2 * YA_SZ_WORD) // storage is aligned to a dword
#define YA_SZ_CHUNK 8192 // request memory 8k by 8k from OS
#define YA_MIN_SZ_BLK 4 // smallest block: dword-aligned with two boundary tags
/*--------*/
/* Macros */ /* Macros */
/*--------*/
#define YA_IS_ALLOC_TAG(tag) ((tag) & 1)
#define YA_SZ_TAG(tag) ((tag) & -2)
#define YA_IS_ALLOC_BLK(block) YA_IS_ALLOC_TAG((block)[-1])
#define YA_SZ_BLK(block) YA_SZ_TAG((block)[-1])
#define YA_IS_ALLOC_END(b_end) YA_IS_ALLOC_TAG((b_end)[0])
#define YA_SZ_END(b_end) YA_SZ_TAG((b_end)[0])
#define YA_ROUND_DIV(n, m) (((n) + ((m)-1)) / (m))
#define YA_ROUND(n, m) (YA_ROUND_DIV(n,m) * (m))
/* Globals */
intptr_t *heap_start = NULL; // space for 2 words before
intptr_t *heap_end = NULL; // first block outside heap
/*--------------------*/
/* Local declarations */ /* Local declarations */
/*--------------------*/
intptr_t *heap_init(); intptr_t *heap_init();
intptr_t *heap_extend(intptr_t size); intptr_t *heap_extend(intptr_t size);
intptr_t *block_join(intptr_t *block);
intptr_t *block_split(intptr_t *block, intptr_t size);
intptr_t *block_find(intptr_t size);
/*----------------------*/
/* Function definitions */ /* Function definitions */
/*----------------------*/
#ifdef YA_DEBUG #ifdef YA_DEBUG
/* Print all blocks in the heap */
void ya_print_blocks() { void ya_print_blocks() {
intptr_t *block;
intptr_t block_size;
for (block = heap_start; block < heap_end; block += block_size) {
block_size = YA_SZ_BLK(block);
printf("Block at %p size = %ld alloc = %d\n",
block, block_size, YA_IS_ALLOC_BLK(block));
}
block_print_range(heap_start, heap_end);
} }
#endif #endif
/* Initializes the block's boundary tags. */
void block_init(intptr_t *block, intptr_t size) {
block[-1] = size;
block[size - 2] = size;
}
/* Sets the allocated bit in the block's boundary tags. */
void block_alloc(intptr_t *block) {
intptr_t block_size = YA_SZ_BLK(block);
block[-1] |= 1;
block[block_size-2] |= 1;
}
/* Erases the allocated bit in the block's boundary tags. */
void block_free(intptr_t *block) {
intptr_t block_size = YA_SZ_BLK(block);
block[-1] &= -2;
block[block_size-2] &= -2;
}
/* Returns the size in words of the smallest block that can
* store n_bytes bytes. Takes alignment and boundary tags into account */
intptr_t block_fit(size_t n_bytes) {
intptr_t n_words = YA_ROUND_DIV(n_bytes, YA_SZ_WORD); // size in words
// round to dword and make space for tags
intptr_t size = 2 + YA_ROUND(n_words, 2);
ya_debug("block_fit: requested = %ld, allocating = %ld * %ld = %ld\n",
n_bytes, size, YA_SZ_WORD, size * YA_SZ_WORD);
return size;
}
/* Tries to coalesce a block with its previous neighbor.
* Returns a pointer to the coalesced block. */
intptr_t *block_join_prev(intptr_t *block) {
intptr_t prev_size = YA_SZ_TAG(block[-2]);
intptr_t *prev = block - prev_size;
if (prev <= heap_start || YA_IS_ALLOC_BLK(prev)) {
return block;
}
intptr_t block_size = YA_SZ_BLK(block);
block_init(prev, prev_size + block_size);
ya_debug("block_join_prev: joining %p:%ld and %p:%ld -> %p:%ld\n",
block, block_size, prev, prev_size, prev, prev_size + block_size);
return prev;
}
/* Tries to colesce a block with its next neighbor.
* Returns the unchanged pointer to the block. */
intptr_t *block_join_next(intptr_t *block) {
intptr_t block_size = YA_SZ_BLK(block);
intptr_t *next = block + block_size;
if (next >= heap_end || YA_IS_ALLOC_BLK(next)) {
return block;
}
intptr_t next_size = YA_SZ_BLK(next);
block_init(block, block_size + next_size);
ya_debug("block_join_next: joining %p:%ld and %p:%ld -> %p:%ld\n",
block, block_size, next, next_size, block, block_size + next_size);
return block;
}
/* Tries to coalesce a block with its previous and next neighbors.
* Returns a pointer to the coalesced block. */
intptr_t *block_join(intptr_t *block) {
if (block > heap_start) {
block = block_join_prev(block);
}
return block_join_next(block);
}
/* Split the block [block_size] into [size, block_size - size] if possible
* Returns a pointer to the second block or NULL if no split occurred. */
intptr_t *block_split(intptr_t *block, intptr_t size) {
intptr_t next_size = YA_SZ_BLK(block) - size;
if (next_size < YA_MIN_SZ_BLK) {
return NULL; // not enough space to warrant a split
}
block_init(block, size);
block_init(block + size, next_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.
* Returns a pointer to the block or NULL in case of failure. */
intptr_t *block_find(intptr_t size) {
intptr_t *block;
intptr_t block_size;
for (block = heap_start; block < heap_end; block += block_size) {
block_size = YA_SZ_BLK(block);
if (!YA_IS_ALLOC_BLK(block) && size <= block_size) {
return block;
}
}
// could not find block, extend heap
return heap_extend(size);
}
/* Initializes the heap by calling sbrk to allocate some starter memory.
* Sets heap_start and heap_end to their appropriate values.
* Returns the pointer to the start of the heap or NULL in case of failure. */
intptr_t *heap_init() {
intptr_t size_w = YA_SZ_CHUNK / YA_SZ_WORD;
void *ptr = sbrk(YA_SZ_WORD * (size_w + 2));
if (ptr == (void*) -1) {
heap_start = NULL;
heap_end = NULL;
return NULL;
}
heap_start = ptr; // cast to intptr_t *
heap_start += 2; // space for the first block[-1] + dword alignment
heap_end = heap_start + size_w;
block_init(heap_start, size_w);
ya_debug("heap_init: start = %p, end = %p, size_w = %ld\n",
heap_start, heap_end, size_w);
return heap_start;
}
/* Extends the heap by at least size_w words 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 size = YA_ROUND(size_w * YA_SZ_WORD, YA_SZ_CHUNK);
size_w = size / YA_SZ_WORD;
ya_debug("heap_extend: size_w = %ld\n", size_w);
void *ptr = sbrk(size);
if (ptr == (void *) - 1) {
return NULL;
}
intptr_t *block = ptr; // == old heap_end
heap_end = block + size_w;
block_init(block, size_w);
ya_debug("heap_extend: old end = %p, new end = %p, size_w = %ld\n",
block, heap_end, size_w);
ya_print_blocks();
return block_join(ptr);
}
/* Allocates enough memory to store at least size bytes. /* Allocates enough memory to store at least size bytes.
* Returns a dword-aligned pointer to the memory or NULL in case of failure. */ * Returns a dword-aligned pointer to the memory or NULL in case of failure. */


+ 1
- 1
yamalloc.h View File

@ -6,7 +6,7 @@
#ifndef YAMALLOC_H #ifndef YAMALLOC_H
#define YAMALLOC_H #define YAMALLOC_H
#include <stddef.h>
#include <stddef.h> // for size_t
void *malloc(size_t size); void *malloc(size_t size);


Loading…
Cancel
Save