Browse Source

Implicit list only, seems to work

main
Titouan Rigoudy 11 years ago
parent
commit
90aabccd31
2 changed files with 107 additions and 67 deletions
  1. +85
    -62
      yamalloc.c
  2. +22
    -5
      yatest.c

+ 85
- 62
yamalloc.c View File

@ -23,77 +23,95 @@
/* Macros */ /* Macros */
#define YA_IS_FREE(block) (((block)[0] & 1) == 0)
#define YA_IS_ALLOC(block) ((block)[-1] & 1)
#define YA_SZ_BLOCK(size) ((size) & -2)
#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))
/* Globals */ /* Globals */
intptr_t *heap_start = NULL;
intptr_t *heap_end = NULL;
intptr_t *heap_start = NULL; // space for 2 words before
intptr_t *heap_end = NULL; // first block outside heap
/* Local declarations */ /* Local declarations */
int heap_init();
int heap_extend();
intptr_t *heap_init();
intptr_t *heap_extend(intptr_t size);
void block_join(intptr_t *block);
intptr_t *block_join(intptr_t *block);
/* Function definitions */ /* Function definitions */
#ifdef YA_DEBUG #ifdef YA_DEBUG
void ya_print_blocks() { void ya_print_blocks() {
for (intptr_t *ptr = heap_start; ptr < heap_end; ptr += ptr[0]) {
fprintf(stderr, "Block at %p, size %ld\n", ptr, ptr[0]);
intptr_t *block;
intptr_t block_size;
for (block = heap_start; block < heap_end; block += block_size) {
block_size = YA_SZ_BLOCK(block[-1]);
fprintf(stderr, "Block at %p size = %ld alloc = %d\n",
block, block_size, YA_IS_ALLOC(block));
} }
} }
#endif #endif
void block_join_prev(intptr_t *block) {
intptr_t *prev = block - block[-1];
if (prev >= heap_start && YA_IS_FREE(prev)) {
intptr_t size = prev[0] + block[0];
prev[0] = size;
block[block[0] - 1] = size;
intptr_t *block_join_prev(intptr_t *block) {
intptr_t prev_size = YA_SZ_BLOCK(block[-2]);
intptr_t *prev = block - prev_size;
if (prev <= heap_start || YA_IS_ALLOC(prev)) {
return block;
} }
intptr_t block_size = YA_SZ_BLOCK(block[-1]);
intptr_t size = prev_size + block_size;
prev[-1] = size;
block[block_size - 2] = size;
return prev;
} }
void block_join_next(intptr_t *block) {
intptr_t *next = block + block[0];
if (next < heap_end && YA_IS_FREE(next)) {
intptr_t size = next[0] + block[0];
block[0] = size;
next[next[0] - 1] = size;
intptr_t *block_join_next(intptr_t *block) {
intptr_t block_size = YA_SZ_BLOCK(block[-1]);
intptr_t *next = block + block_size;
if (next >= heap_end || YA_IS_ALLOC(next)) {
return block;
} }
intptr_t next_size = YA_SZ_BLOCK(next[-1]);
intptr_t size = next_size + block_size;
block[-1] = size;
next[next_size - 2] = size;
return block;
} }
void block_join(intptr_t *block) {
intptr_t *block_join(intptr_t *block) {
if (block > heap_start) { if (block > heap_start) {
block_join_prev(block);
block = block_join_prev(block);
} }
block_join_next(block);
return block_join_next(block);
} }
void block_split(intptr_t *block, intptr_t size) { void block_split(intptr_t *block, intptr_t size) {
intptr_t old_size = block[0];
block[0] = size;
block[size - 1] = size;
block[size] = old_size - size;
block[old_size - 1] = old_size - size;
intptr_t old_size = YA_SZ_BLOCK(block[-1]);
block[-1] = size;
block[size - 2] = size;
block[size - 1] = old_size - size;
block[old_size - 2] = old_size - size;
} }
int heap_init() {
heap_start = sbrk(0);
if (heap_start == (void*) -1) {
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_start = NULL;
heap_end = NULL; heap_end = NULL;
return -1;
return NULL;
} }
heap_end = heap_start;
return 0;
heap_start = ptr;
heap_start += 2; // space for the first block[-1] + dword alignment
heap_end = heap_start + size_w;
heap_start[-1] = size_w;
heap_end[-2] = size_w;
return heap_start;
} }
int heap_extend(intptr_t size_w) {
intptr_t *heap_extend(intptr_t size_w) {
fprintf(stderr, "heap_extend: old heap_start = %p, heap_end = %p\n", fprintf(stderr, "heap_extend: old heap_start = %p, heap_end = %p\n",
heap_start, heap_end); heap_start, heap_end);
intptr_t size = YA_ROUND(size_w * YA_SZ_WORD, YA_SZ_CHUNK); intptr_t size = YA_ROUND(size_w * YA_SZ_WORD, YA_SZ_CHUNK);
@ -101,19 +119,14 @@ int heap_extend(intptr_t size_w) {
fprintf(stderr, "heap_extend: %ld bytes, %ld words\n", size, size_w); fprintf(stderr, "heap_extend: %ld bytes, %ld words\n", size, size_w);
void *ptr = sbrk(size); void *ptr = sbrk(size);
if (ptr == (void *) - 1) { if (ptr == (void *) - 1) {
return -1;
return NULL;
} }
fprintf(stderr, "heap_extend: %ld bytes, %ld words\n", size, size_w);
heap_end[0] = size_w;
heap_end[size_w - 1] = size_w;
fprintf(stderr, "heap_extend: heap_end = %p, heap_end + size_w = %p\n",
heap_end, heap_end + size_w);
fprintf(stderr, "heap_extend: heap_end[0] = %ld, heap_end[size_w - 1] = %ld\n",
heap_end[0], heap_end[size_w - 1]);
heap_end += size_w;
intptr_t *block = ptr; // == heap_end
heap_end = block + size_w;
block[-1] = size_w;
heap_end[-2] = size_w;
fprintf(stderr, "heap_extend: new heap_end = %p\n", heap_end); fprintf(stderr, "heap_extend: new heap_end = %p\n", heap_end);
block_join(ptr);
return 0;
return block_join(ptr);
} }
void *malloc(size_t size) { void *malloc(size_t size) {
@ -121,34 +134,44 @@ void *malloc(size_t size) {
return NULL; return NULL;
} }
if (heap_start == NULL || heap_end == NULL) { if (heap_start == NULL || heap_end == NULL) {
if (heap_init() != 0) {
if (!heap_init()) {
return NULL; return NULL;
} }
} }
intptr_t size_w = YA_ROUND_DIV(size + 2, YA_SZ_WORD); // size in words
intptr_t align_dw = YA_ROUND(size_w, 2); // round to dword
intptr_t size_w = YA_ROUND_DIV(size, YA_SZ_WORD); // size in words
fprintf(stderr, "size_w = %ld\n", size_w);
size_w = 2 + YA_ROUND(size_w, 2); // round to dword and make space for tags
fprintf(stderr, "size_w = %ld\n", size_w);
intptr_t *block; intptr_t *block;
for (block = heap_start; block < heap_end; block += block[0]) {
if (YA_IS_FREE(block) && block[0] >= align_dw) {
intptr_t block_size;
for (block = heap_start; block < heap_end; block += block_size) {
block_size = YA_SZ_BLOCK(block[-1]);
if (!YA_IS_ALLOC(block) && size_w <= block_size) {
break; break;
} }
} }
fprintf(stderr, "size_w = %ld, align_dw = %ld\n", size_w, align_dw);
if (block >= heap_end) { // could not find block, extend heap if (block >= heap_end) { // could not find block, extend heap
if (heap_extend(align_dw) != 0) {
return NULL;
}
block = heap_end - heap_end[-1];
if (!YA_IS_FREE(block) || block[0] < align_dw) {
block = heap_extend(size_w);
if (!block) {
return NULL; return NULL;
} }
block_size = YA_SZ_BLOCK(block[-1]);
} }
if (block[0] > align_dw) {
block_split(block, align_dw);
if (size_w < block_size) {
block_split(block, size_w);
} }
block[0] |= 1;
return block + 1;
block[-1] |= 1;
block[block_size - 2] |= 1;
return block;
} }
void free(void *ptr) { void free(void *ptr) {
intptr_t *block = ptr;
if (block < heap_start || block > heap_end || !YA_IS_ALLOC(block)) {
return; // TODO: provoke segfault
}
intptr_t block_size = YA_SZ_BLOCK(block[-1]);
block[-1] &= -2; // erase allocated bit
block[block_size - 2] &= -2;
block_join(block);
} }

+ 22
- 5
yatest.c View File

@ -10,17 +10,34 @@
void *print_malloc(size_t size) { void *print_malloc(size_t size) {
void *ptr = malloc(size); void *ptr = malloc(size);
printf("malloc(%ld) = %p\n", size, ptr);
fprintf(stderr, "malloc(%ld) = %p\n", size, ptr);
return ptr; return ptr;
} }
void print_free(void *ptr) {
fprintf(stderr, "free(%p)\n", ptr);
free(ptr);
}
int main(int argc, char **argv) { int main(int argc, char **argv) {
void *a, *b, *c, *d;
ya_print_blocks();
a = print_malloc(4);
ya_print_blocks();
b = print_malloc(10);
ya_print_blocks();
c = print_malloc(10000);
ya_print_blocks();
d = print_malloc(2000);
ya_print_blocks();
print_free(a);
ya_print_blocks();
print_free(c);
ya_print_blocks(); ya_print_blocks();
print_malloc(4);
print_malloc(10);
c = print_malloc(100);
ya_print_blocks(); ya_print_blocks();
print_malloc(10000);
a = print_malloc(2);
ya_print_blocks(); ya_print_blocks();
print_malloc(2000);
print_free(d);
ya_print_blocks(); ya_print_blocks();
} }

Loading…
Cancel
Save