summaryrefslogtreecommitdiff
path: root/malloc/block_allocator/allocator.c
blob: 0cf9af62e468a53121b01da4aec3b4d01ee95e43 (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
#include "allocator.h"

#include <stdlib.h>
#include <sys/mman.h>
#include <unistd.h>

size_t align(size_t size, size_t al)
{
    size_t padding = size % al;
    if (padding)
        padding = al - padding;
    size_t res;
    if (__builtin_uaddl_overflow(size, padding, &res))
        return 0;
    return res;
}

struct blk_allocator *blka_new(void)
{
    struct blk_allocator *new = malloc(sizeof(struct blk_allocator));
    new->meta = NULL;
    return new;
}

struct blk_meta *blka_alloc(struct blk_allocator *blka, size_t size)
{
    long page_size = sysconf(_SC_PAGESIZE);
    size_t aligned_size = align(size + sizeof(struct blk_meta), page_size);
    struct blk_meta *meta = mmap(NULL, aligned_size, PROT_READ | PROT_WRITE,
                                 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
    if (meta == MAP_FAILED)
        return NULL;
    meta->size = aligned_size - sizeof(struct blk_meta);
    meta->next = blka->meta;
    blka->meta = meta;
    return meta;
}

void blka_free(struct blk_meta *blk)
{
    munmap(blk, blk->size + sizeof(struct blk_meta));
}

void blka_pop(struct blk_allocator *blka)
{
    if (blka->meta == NULL)
        return;

    struct blk_meta *meta = blka->meta;
    blka->meta = blka->meta->next;
    blka_free(meta);
}

void blka_delete(struct blk_allocator *blka)
{
    while (blka->meta)
    {
        blka_pop(blka);
    }
    free(blka);
}