summaryrefslogtreecommitdiff
path: root/src/cache/backings/memory.c
blob: 063c1c53ba9512f8128feed444732db9438d104c (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
106
107
108
109
110
111
112
113
114
115
116
#include "../range.h"

#include "memory.h"

static void ensure_allocated(struct cch_backing_memory *mem, off_t amount)
{
    if (amount > mem->expanse) mem->expanse = amount;
    if (amount > mem->alloc) {
        mem->alloc = al_next_power_of_two(amount);
        mem->data = (u8 *)al_realloc(mem->data, mem->alloc);
    }
}

static void memory_backing_lock(struct cch_backing *backing)
{
    struct cch_backing_memory *mem = (struct cch_backing_memory *)backing;
    nn_mutex_lock(&mem->mutex);
}

static void memory_backing_write(struct cch_backing *backing, u8 *buf, off_t index, size_t *count)
{
    struct cch_backing_memory *mem = (struct cch_backing_memory *)backing;
    off_t n = (off_t)*count;
    nn_mutex_lock(&mem->mutex);
    off_t size = mem->backing.size;
    if (size > 0 && index + n >= size) {
        n = MAX(size - index, (off_t)0);
    }
    if (n > 0) {
        ensure_allocated(mem, index + n);
        al_memcpy(mem->data + index, buf, n);
        cch_backing_fill_range(&mem->backing, index, n);
    }
    *count = (size_t)n;
    nn_mutex_unlock(&mem->mutex);
}

static u8 *memory_backing_get_ptr(struct cch_backing *backing, off_t index, size_t *count)
{
    struct cch_backing_memory *mem = (struct cch_backing_memory *)backing;
    off_t n = (off_t)*count;
    nn_mutex_lock(&mem->mutex);
    off_t size = mem->backing.size;
    if (size > 0 && index + n >= size) {
        n = MAX(size - index, (off_t)0);
    }
    *count = (size_t)n;
    al_assert(mem->alloc >= index + n);
    return (u8 *)(mem->data + index);
}

static void memory_backing_unlock(struct cch_backing *backing)
{
    struct cch_backing_memory *mem = (struct cch_backing_memory *)backing;
    nn_mutex_unlock(&mem->mutex);
}

static void memory_backing_set_size(struct cch_backing *backing, off_t size, bool expand_to_size)
{
    struct cch_backing_memory *mem = (struct cch_backing_memory *)backing;
    nn_mutex_lock(&mem->mutex);
    mem->backing.size = size;
    if (expand_to_size) {
        al_assert(size > 0);
        ensure_allocated(mem, size);
    }
    nn_mutex_unlock(&mem->mutex);
}

static off_t memory_backing_get_size_if_known(struct cch_backing *backing)
{
    struct cch_backing_memory *mem = (struct cch_backing_memory *)backing;
    nn_mutex_lock(&mem->mutex);
    off_t size = mem->backing.size;
    nn_mutex_unlock(&mem->mutex);
    return size;
}

static void memory_backing_finalize(struct cch_backing *backing)
{
    struct cch_backing_memory *mem = (struct cch_backing_memory *)backing;
    nn_mutex_lock(&mem->mutex);
    mem->backing.size = mem->expanse;
    nn_mutex_unlock(&mem->mutex);
}

static void memory_backing_free(struct cch_backing **backing)
{
    struct cch_backing_memory *mem = (struct cch_backing_memory *)*backing;
    al_free(mem->data);
    nn_mutex_destroy(&mem->mutex);
    al_array_free(mem->backing.available);
    al_free(mem);
    *backing = NULL;
}

struct cch_backing *cch_backing_memory_create(size_t size)
{
    struct cch_backing_memory *mem = al_alloc_object(struct cch_backing_memory);
    mem->backing.mode = CACHE_BACKING_MAPPED;
    mem->backing.size = -1;
    mem->backing.lock = memory_backing_lock;
    mem->backing.write = memory_backing_write;
    mem->backing.get_ptr = memory_backing_get_ptr;
    mem->backing.unlock = memory_backing_unlock;
    mem->backing.set_size = memory_backing_set_size;
    mem->backing.get_size_if_known = memory_backing_get_size_if_known;
    mem->backing.finalize = memory_backing_finalize;
    mem->backing.free = memory_backing_free;
    if (size > 0) mem->data = (u8 *)al_malloc(size);
    else mem->data = NULL;
    mem->alloc = size;
    nn_mutex_init(&mem->mutex);
    al_array_init(mem->backing.available);
    return (struct cch_backing *)mem;
}