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
*/
/*---------------------*/
/* Feature test macros */
/*---------------------*/
#define _DEFAULT_SOURCE // for sbrk
/*----------*/
/* Includes */
/*----------*/
#include "ya_block.h"
#include <unistd.h>
#include <stdio.h>
#include "ya_debug.h"
#include "ya_block.h"
/*---------*/
/* Globals */
@ -24,12 +33,15 @@ intptr_t *heap_end = NULL; // first block outside heap
#ifdef YA_DEBUG
void block_print_range(intptr_t *start, intptr_t *end) {
if (!start || !end) {
return;
}
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",
block, block_size, YA_BLK_IS_ALLOC(block));
block, size, block_is_alloc(block));
}
}
#endif
@ -42,16 +54,24 @@ 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) {
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. */
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
@ -68,46 +88,47 @@ 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) {
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;
if (prev <= heap_start || YA_BLK_IS_ALLOC(prev)) {
if (prev <= heap_start || block_is_alloc(prev)) {
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",
block, block_size, prev, prev_size, prev, prev_size + block_size);
block, size, prev, prev_size, prev, prev_size + 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_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;
}
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",
block, block_size, next, next_size, block, block_size + next_size);
block, size, next, next_size, 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);
}
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_BLK_SZ(block) - size;
intptr_t next_size = block_size(block) - size;
if (next_size < YA_BLK_MIN_SZ) {
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
* 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_find(intptr_t min_size) {
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;
}
}
// 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.


+ 30
- 11
ya_block.h View File

@ -12,6 +12,7 @@
#include <stddef.h> // for size_t
#include <stdint.h> // for intptr_t
#include <stdbool.h>
/*-----------*/
/* Constants */
@ -27,15 +28,6 @@
/* 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(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_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 */
/*--------------*/
@ -59,7 +75,7 @@ intptr_t *heap_init();
* Returns a pointer to the last (free) block or NULL in case of failure. */
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 */
void block_print_range(intptr_t *start, intptr_t *end);
#endif
@ -73,6 +89,9 @@ void block_alloc(intptr_t *block);
/* Erases the allocated bit in the block's boundary tags. */
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
* store n_bytes bytes. Takes alignment and boundary tags into account */
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
* 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_find(intptr_t min_size);
#endif

+ 26
- 28
yamalloc.c View File

@ -49,8 +49,8 @@ void ya_print_blocks() {
/* Allocates enough memory to store at least size bytes.
* 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;
}
if (heap_start == NULL || heap_end == NULL) {
@ -58,12 +58,9 @@ void *malloc(size_t size) {
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);
return block;
}
@ -73,7 +70,7 @@ void *malloc(size_t size) {
* behavior occurs. */
void free(void *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
}
block_free(block);
@ -83,12 +80,10 @@ void free(void *ptr) {
/* Allocates enough memory to store an array of nmemb elements,
* each size bytes large, and clears the memory.
* 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;
}
@ -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
* realloc, undefined behavior occurs.
* */
void *realloc(void *ptr, size_t size) {
void *realloc(void *ptr, size_t n_bytes) {
if (!ptr) {
return malloc(size);
return malloc(n_bytes);
}
if (size == 0) {
if (n_bytes == 0) {
free(ptr);
}
intptr_t *block = ptr;
if (block < heap_start) {
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) {
block_join_next(next); // coalesce the leftovers
}
block_alloc(block);
return block;
}
intptr_t *next = block + block_size;
intptr_t *next = block + size;
// try to use next free block
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_split(block, size_w); // split if possible
block_split(block, new_size); // split if possible
// no need to coalesce
block_alloc(block); // mark block as allocated
return block;
@ -134,8 +132,8 @@ void *realloc(void *ptr, size_t size) {
// 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(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];
}
free(block);


Loading…
Cancel
Save