summaryrefslogtreecommitdiff
path: root/core/alloc.c
blob: 88ebb8f50a1fee9700baac08c4f300aebfd97044 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
#include <rune/core/alloc.h>
#include <rune/core/logging.h>
#include <stdlib.h>

// TODO: implement block coalescing so we can reuse freed blocks

#define DEADBLOCK       ((void*)0xDEADBEEF)

static struct mem_block first_block;

static struct mem_block* _find_free_block(size_t sz) {
        struct list_head *temp = &first_block.list;
        struct mem_block *block;
        while (temp != NULL) {
                block = (struct mem_block*)((void*)temp - offsetof(struct mem_block, list));
                if (block->sz == sz && block->free == 1)
                        return block;
                temp = temp->next;
        }
        return NULL;
}

static struct mem_block* _find_block(void *ptr) {
        struct list_head *temp = &first_block.list;
        struct mem_block *block;
        while (temp != NULL) {
                block = (struct mem_block*)((void*)temp - offsetof(struct mem_block, list));
                if (block->ptr == ptr)
                        return block;
                temp = temp->next;
        }
        return NULL;
}

void* rune_alloc(size_t sz) {
        if (sz == 0)
                return NULL;

        if (first_block.ptr == NULL) {
                first_block.ptr = DEADBLOCK;
                first_block.sz = 0;
        }

        struct mem_block *block = _find_free_block(sz);
        if (block != NULL) {
                block->free = 0;
                return block->ptr;
        }

        block = malloc(sizeof(struct mem_block));
        if (block == NULL) {
                log_output(LOG_ERROR, "Cannot allocate block of size %d", sz);
                return NULL;
        }
        block->ptr = malloc(sz);
        block->sz = sz;
        block->free = 0;
        list_add(&block->list, &first_block.list);
        log_output(LOG_DEBUG, "Alloc'd block of size %d", sz);
        return block->ptr;
}

void* rune_calloc(size_t nmemb, size_t sz) {
        void *ret = rune_alloc(sz);
        for (size_t *i = (size_t*)ret; i < (size_t*)ret+sz; i++)
                *i = nmemb;
        return ret;
}

void* rune_realloc(void *ptr, size_t sz) {
        if (ptr == NULL || sz == 0)
                return NULL;

        struct mem_block *block = _find_block(ptr);
        if (block == NULL)
                return rune_alloc(sz);
        return block->ptr;
}

void rune_free(void *ptr) {
        if (ptr == NULL)
                return;

        struct mem_block *block = _find_block(ptr);
        if (block->free == 1)
                return;
        block->free = 1;
        log_output(LOG_DEBUG, "Freed block of size %d", block->sz);
}

void rune_free_all(void) {
        struct list_head *temp = &first_block.list;
        struct mem_block *block;
        while (temp != NULL) {
                block = (struct mem_block*)((void*)temp - offsetof(struct mem_block, list));
                if (block->ptr == DEADBLOCK) {
                        temp = temp->next;
                        continue;
                }

                if (block->ptr != NULL)
                        free(block->ptr);
                temp = temp->next;
        }
}