Browse Source

Replaced some macros with inline functions

main
Titouan Rigoudy 11 years ago
parent
commit
0c0e9e5375
3 changed files with 109 additions and 71 deletions
  1. +53
    -32
      ya_block.c
  2. +30
    -11
      ya_block.h
  3. +26
    -28
      yamalloc.c

+ 53
- 32
ya_block.c View File

@ -4,12 +4,21 @@
* Defines operations on blocks and boundary tags * Defines operations on blocks and boundary tags
*/ */
/*---------------------*/
/* Feature test macros */
/*---------------------*/
#define _DEFAULT_SOURCE // for sbrk
/*----------*/ /*----------*/
/* Includes */ /* Includes */
/*----------*/ /*----------*/
#include "ya_block.h"
#include <unistd.h>
#include <stdio.h>
#include "ya_debug.h" #include "ya_debug.h"
#include "ya_block.h"
/*---------*/ /*---------*/
/* Globals */ /* Globals */
@ -24,12 +33,15 @@ intptr_t *heap_end = NULL; // first block outside heap
#ifdef YA_DEBUG #ifdef YA_DEBUG
void block_print_range(intptr_t *start, intptr_t *end) { void block_print_range(intptr_t *start, intptr_t *end) {
if (!start || !end) {
return;
}
intptr_t *block; intptr_t *block;
intptr_t block_size;
for (block = start; block < end; block += block_size) {
block_size = YA_BLK_SZ(block);
intptr_t size;
for (block = start; block < end; block += size) {
size = block_size(block);
printf("Block at %p size = %ld alloc = %d\n", printf("Block at %p size = %ld alloc = %d\n",
block, block_size, YA_BLK_IS_ALLOC(block));
block, size, block_is_alloc(block));
} }
} }
#endif #endif
@ -42,16 +54,24 @@ void block_init(intptr_t *block, intptr_t size) {
/* Sets the allocated bit in the block's boundary tags. */ /* Sets the allocated bit in the block's boundary tags. */
void block_alloc(intptr_t *block) { void block_alloc(intptr_t *block) {
intptr_t block_size = YA_BLK_SZ(block);
block[-1] |= 1;
block[block_size-2] |= 1;
intptr_t size = block_size(block);
block[-1] |= 1;
block[size-2] |= 1;
} }
/* Erases the allocated bit in the block's boundary tags. */ /* Erases the allocated bit in the block's boundary tags. */
void block_free(intptr_t *block) { void block_free(intptr_t *block) {
intptr_t block_size = YA_BLK_SZ(block);
block[-1] &= -2;
block[block_size-2] &= -2;
intptr_t size = block_size(block);
block[-1] &= -2;
block[size-2] &= -2;
}
/* Fills block with zeros. */
void block_clear(intptr_t *block) {
intptr_t *end = block + block_size(block) - 2;
for (intptr_t *p = block; p < end; p++) {
*p = 0;
}
} }
/* Returns the size in words of the smallest block that can /* Returns the size in words of the smallest block that can
@ -68,46 +88,47 @@ intptr_t block_fit(size_t n_bytes) {
/* Tries to coalesce a block with its previous neighbor. /* Tries to coalesce a block with its previous neighbor.
* Returns a pointer to the coalesced block. */ * Returns a pointer to the coalesced block. */
intptr_t *block_join_prev(intptr_t *block) { intptr_t *block_join_prev(intptr_t *block) {
intptr_t prev_size = YA_TAG_SZ(block[-2]);
if (block < heap_start + YA_BLK_MIN_SZ) {
return block; // there cannot be a previous block
}
intptr_t prev_size = tag_size(block[-2]);
intptr_t *prev = block - prev_size; intptr_t *prev = block - prev_size;
if (prev <= heap_start || YA_BLK_IS_ALLOC(prev)) {
if (prev <= heap_start || block_is_alloc(prev)) {
return block; return block;
} }
intptr_t block_size = YA_BLK_SZ(block);
block_init(prev, prev_size + block_size);
intptr_t size = block_size(block);
block_init(prev, prev_size + size);
ya_debug("block_join_prev: joining %p:%ld and %p:%ld -> %p:%ld\n", 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);
block, size, prev, prev_size, prev, prev_size + size);
return prev; return prev;
} }
/* Tries to colesce a block with its next neighbor. /* Tries to colesce a block with its next neighbor.
* Returns the unchanged pointer to the block. */ * Returns the unchanged pointer to the block. */
intptr_t *block_join_next(intptr_t *block) { intptr_t *block_join_next(intptr_t *block) {
intptr_t block_size = YA_BLK_SZ(block);
intptr_t *next = block + block_size;
if (next >= heap_end || YA_BLK_IS_ALLOC(next)) {
intptr_t size = block_size(block);
intptr_t *next = block + size;
if (next >= heap_end || block_is_alloc(next)) {
return block; return block;
} }
intptr_t next_size = YA_BLK_SZ(next);
block_init(block, block_size + next_size);
intptr_t next_size = block_size(next);
block_init(block, size + next_size);
ya_debug("block_join_next: joining %p:%ld and %p:%ld -> %p:%ld\n", 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);
block, size, next, next_size, block, size + next_size);
return block; return block;
} }
/* Tries to coalesce a block with its previous and next neighbors. /* Tries to coalesce a block with its previous and next neighbors.
* Returns a pointer to the coalesced block. */ * Returns a pointer to the coalesced block. */
intptr_t *block_join(intptr_t *block) { intptr_t *block_join(intptr_t *block) {
if (block > heap_start) {
block = block_join_prev(block);
}
block = block_join_prev(block);
return block_join_next(block); return block_join_next(block);
} }
/* Split the block [block_size] into [size, block_size - size] if possible /* 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. */ * 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 *block_split(intptr_t *block, intptr_t size) {
intptr_t next_size = YA_BLK_SZ(block) - size;
intptr_t next_size = block_size(block) - size;
if (next_size < YA_BLK_MIN_SZ) { if (next_size < YA_BLK_MIN_SZ) {
return NULL; // not enough space to warrant a split return NULL; // not enough space to warrant a split
} }
@ -119,17 +140,17 @@ 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 /* 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. * tags. If no block is found the heap is grown adequately.
* Returns a pointer to the block or NULL in case of failure. */ * Returns a pointer to the block or NULL in case of failure. */
intptr_t *block_find(intptr_t size) {
intptr_t *block_find(intptr_t min_size) {
intptr_t *block; intptr_t *block;
intptr_t block_size;
for (block = heap_start; block < heap_end; block += block_size) {
block_size = YA_BLK_SZ(block);
if (!YA_BLK_IS_ALLOC(block) && size <= block_size) {
intptr_t size;
for (block = heap_start; block < heap_end; block += size) {
size = block_size(block);
if (!block_is_alloc(block) && min_size <= size) {
return block; return block;
} }
} }
// could not find block, extend heap // could not find block, extend heap
return heap_extend(size);
return heap_extend(min_size);
} }
/* Initializes the heap by calling sbrk to allocate some starter memory. /* Initializes the heap by calling sbrk to allocate some starter memory.


+ 30
- 11
ya_block.h View File

@ -12,6 +12,7 @@
#include <stddef.h> // for size_t #include <stddef.h> // for size_t
#include <stdint.h> // for intptr_t #include <stdint.h> // for intptr_t
#include <stdbool.h>
/*-----------*/ /*-----------*/
/* Constants */ /* Constants */
@ -27,15 +28,6 @@
/* Macros */ /* Macros */
/*--------*/ /*--------*/
#define YA_TAG_IS_ALLOC(tag) ((tag) & 1)
#define YA_TAG_SZ(tag) ((tag) & -2)
#define YA_BLK_IS_ALLOC(block) YA_TAG_IS_ALLOC((block)[-1])
#define YA_BLK_SZ(block) YA_TAG_SZ((block)[-1])
#define YA_END_IS_ALLOC(b_end) YA_TAG_IS_ALLOC((b_end)[0])
#define YA_END_SZ(b_end) YA_TAG_SZ((b_end)[0])
#define YA_ROUND_DIV(n, m) (((n) + ((m)-1)) / (m)) #define YA_ROUND_DIV(n, m) (((n) + ((m)-1)) / (m))
#define YA_ROUND(n, m) (YA_ROUND_DIV(n,m) * (m)) #define YA_ROUND(n, m) (YA_ROUND_DIV(n,m) * (m))
@ -46,6 +38,30 @@
extern intptr_t *heap_start; // with space for 2 words before extern intptr_t *heap_start; // with space for 2 words before
extern intptr_t *heap_end ; // first block outside heap extern intptr_t *heap_end ; // first block outside heap
/*---------*/
/* Inlines */
/*---------*/
/* Returns true iff the boundary tag has the allocated bit set. */
static inline bool tag_is_alloc(intptr_t tag) {
return tag & 1;
}
/* Returns true iff the block's boundary tag has the allocated bit set. */
static inline bool block_is_alloc(intptr_t *block) {
return tag_is_alloc(block[-1]);
}
/* Returns the size stored in the boundary tag. */
static inline intptr_t tag_size(intptr_t tag) {
return tag & -2;
}
/* Returns the size stored in the block's boundary tag. */
static inline intptr_t block_size(intptr_t *block) {
return tag_size(block[-1]);
}
/*--------------*/ /*--------------*/
/* Declarations */ /* Declarations */
/*--------------*/ /*--------------*/
@ -59,7 +75,7 @@ intptr_t *heap_init();
* Returns a pointer to the last (free) block or NULL in case of failure. */ * 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(intptr_t size_w);
#ifdef DEBUG
#ifdef YA_DEBUG
/* Prints each block in the range from the block at start to the one at end */ /* 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); void block_print_range(intptr_t *start, intptr_t *end);
#endif #endif
@ -73,6 +89,9 @@ void block_alloc(intptr_t *block);
/* Erases the allocated bit in the block's boundary tags. */ /* Erases the allocated bit in the block's boundary tags. */
void block_free(intptr_t *block); void block_free(intptr_t *block);
/* Fills block with zeros. */
void block_clear(intptr_t *block);
/* Returns the size in words of the smallest block that can /* Returns the size in words of the smallest block that can
* store n_bytes bytes. Takes alignment and boundary tags into account */ * store n_bytes bytes. Takes alignment and boundary tags into account */
intptr_t block_fit(size_t n_bytes); intptr_t block_fit(size_t n_bytes);
@ -96,6 +115,6 @@ 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 /* 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. * tags. If no block is found the heap is grown adequately.
* Returns a pointer to the block or NULL in case of failure. */ * Returns a pointer to the block or NULL in case of failure. */
intptr_t *block_find(intptr_t size);
intptr_t *block_find(intptr_t min_size);
#endif #endif

+ 26
- 28
yamalloc.c View File

@ -49,8 +49,8 @@ void ya_print_blocks() {
/* 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. */
void *malloc(size_t size) {
if (size == 0) {
void *malloc(size_t n_bytes) {
if (n_bytes == 0) {
return NULL; return NULL;
} }
if (heap_start == NULL || heap_end == NULL) { if (heap_start == NULL || heap_end == NULL) {
@ -58,12 +58,9 @@ void *malloc(size_t size) {
return NULL; return NULL;
} }
} }
intptr_t size_w = block_fit(size);
intptr_t *block = block_find(size_w);
intptr_t block_size = YA_BLK_SZ(block);
if (size_w < block_size) {
block_split(block, size_w);
}
intptr_t min_size = block_fit(n_bytes);
intptr_t *block = block_find(min_size);
block_split(block, min_size);
block_alloc(block); block_alloc(block);
return block; return block;
} }
@ -73,7 +70,7 @@ void *malloc(size_t size) {
* behavior occurs. */ * behavior occurs. */
void free(void *ptr) { void free(void *ptr) {
intptr_t *block = ptr; intptr_t *block = ptr;
if (block < heap_start || block > heap_end || !YA_BLK_IS_ALLOC(block)) {
if (block < heap_start || block > heap_end || !block_is_alloc(block)) {
return; // TODO: provoke segfault return; // TODO: provoke segfault
} }
block_free(block); block_free(block);
@ -83,12 +80,10 @@ void free(void *ptr) {
/* Allocates enough memory to store an array of nmemb elements, /* Allocates enough memory to store an array of nmemb elements,
* each size bytes large, and clears the memory. * each size bytes large, and clears the memory.
* Returns the pointer to the allocated memory or NULL in case of failure. */ * Returns the pointer to the allocated memory or NULL in case of failure. */
void *calloc(size_t nmemb, size_t size) {
intptr_t *block = malloc(size * nmemb);
intptr_t block_size = YA_BLK_SZ(block);
for (int i = 0; i < block_size - 2; i++) {
block[i] = 0;
}
void *calloc(size_t nmemb, size_t n_bytes) {
intptr_t *block = malloc(n_bytes * nmemb);
intptr_t size = block_size(block);
block_clear(block);
return block; return block;
} }
@ -98,34 +93,37 @@ void *calloc(size_t nmemb, size_t size) {
* If ptr does not point to memory previously allocated by malloc, calloc or * If ptr does not point to memory previously allocated by malloc, calloc or
* realloc, undefined behavior occurs. * realloc, undefined behavior occurs.
* */ * */
void *realloc(void *ptr, size_t size) {
void *realloc(void *ptr, size_t n_bytes) {
if (!ptr) { if (!ptr) {
return malloc(size);
return malloc(n_bytes);
} }
if (size == 0) {
if (n_bytes == 0) {
free(ptr); free(ptr);
} }
intptr_t *block = ptr; intptr_t *block = ptr;
if (block < heap_start) { if (block < heap_start) {
return NULL; // TODO: provoke segfault return NULL; // TODO: provoke segfault
} }
intptr_t size_w = block_fit(size);
intptr_t block_size = YA_BLK_SZ(block); // segfault if ptr after heap end
if (size_w <= block_size) {
intptr_t *next = block_split(block, size_w);
intptr_t new_size = block_fit(n_bytes);
intptr_t size = block_size(block); // segfault if ptr after heap end
if (new_size == size) {
return ptr; // don't change anything
}
if (new_size < size) {
intptr_t *next = block_split(block, new_size);
if (next) { if (next) {
block_join_next(next); // coalesce the leftovers block_join_next(next); // coalesce the leftovers
} }
block_alloc(block); block_alloc(block);
return block; return block;
} }
intptr_t *next = block + block_size;
intptr_t *next = block + size;
// try to use next free block // try to use next free block
if (next < heap_end) { if (next < heap_end) {
intptr_t next_size = YA_BLK_SZ(next);
if (!YA_BLK_IS_ALLOC(next) && size_w <= block_size + next_size) {
intptr_t next_size = block_size(next);
if (!block_is_alloc(next) && new_size <= size + next_size) {
block_join_next(block); // coalesce block_join_next(block); // coalesce
block_split(block, size_w); // split if possible
block_split(block, new_size); // split if possible
// no need to coalesce // no need to coalesce
block_alloc(block); // mark block as allocated block_alloc(block); // mark block as allocated
return block; return block;
@ -134,8 +132,8 @@ void *realloc(void *ptr, size_t size) {
// resizing failed, so allocate a whole new block and copy // resizing failed, so allocate a whole new block and copy
// could handle the case when the block is the last in the heap // 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 // a bit more gracefully and just grow the heap instead of copying
intptr_t *new_block = malloc(size);
for (int i = 0; i < block_size; i++) {
intptr_t *new_block = malloc(n_bytes);
for (int i = 0; i < size; i++) {
new_block[i] = block[i]; new_block[i] = block[i];
} }
free(block); free(block);


Loading…
Cancel
Save