aboutsummaryrefslogtreecommitdiff
path: root/src/stdlib/builtin/lv_mem_core_builtin.c
blob: 23a218154cc3637579d0a5abfcebb4b07591a68a (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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
/**
 * @file lv_malloc_core.c
 */

/*********************
 *      INCLUDES
 *********************/
#include "../lv_mem.h"
#if LV_USE_STDLIB_MALLOC == LV_STDLIB_BUILTIN

#include "lv_tlsf.h"
#include "../lv_string.h"
#include "../../misc/lv_assert.h"
#include "../../misc/lv_log.h"
#include "../../misc/lv_ll.h"
#include "../../misc/lv_math.h"
#include "../../osal/lv_os.h"
#include "../../core/lv_global.h"

#ifdef LV_MEM_POOL_INCLUDE
    #include LV_MEM_POOL_INCLUDE
#endif

/*********************
 *      DEFINES
 *********************/
/*memset the allocated memories to 0xaa and freed memories to 0xbb (just for testing purposes)*/
#ifndef LV_MEM_ADD_JUNK
    #define LV_MEM_ADD_JUNK  0
#endif

#ifdef LV_ARCH_64
    #define MEM_UNIT         uint64_t
    #define ALIGN_MASK       0x7
#else
    #define MEM_UNIT         uint32_t
    #define ALIGN_MASK       0x3
#endif
#define state LV_GLOBAL_DEFAULT()->tlsf_state

/**********************
 *      TYPEDEFS
 **********************/

/**********************
 *  STATIC PROTOTYPES
 **********************/
static void lv_mem_walker(void * ptr, size_t size, int used, void * user);

/**********************
 *  STATIC VARIABLES
 **********************/

/**********************
 *      MACROS
 **********************/
#if LV_USE_LOG && LV_LOG_TRACE_MEM
    #define LV_TRACE_MEM(...) LV_LOG_TRACE(__VA_ARGS__)
#else
    #define LV_TRACE_MEM(...)
#endif

#define _COPY(d, s) *d = *s; d++; s++;
#define _SET(d, v) *d = v; d++;
#define _REPEAT8(expr) expr expr expr expr expr expr expr expr

/**********************
 *   GLOBAL FUNCTIONS
 **********************/

void lv_mem_init(void)
{
#if LV_USE_OS
    lv_mutex_init(&state.mutex);
#endif

#if LV_MEM_ADR == 0
#ifdef LV_MEM_POOL_ALLOC
    state.tlsf = lv_tlsf_create_with_pool((void *)LV_MEM_POOL_ALLOC(LV_MEM_SIZE), LV_MEM_SIZE);
#else
    /*Allocate a large array to store the dynamically allocated data*/
    static LV_ATTRIBUTE_LARGE_RAM_ARRAY MEM_UNIT work_mem_int[LV_MEM_SIZE / sizeof(MEM_UNIT)];
    state.tlsf = lv_tlsf_create_with_pool((void *)work_mem_int, LV_MEM_SIZE);
#endif
#else
    state.tlsf = lv_tlsf_create_with_pool((void *)LV_MEM_ADR, LV_MEM_SIZE);
#endif

    lv_ll_init(&state.pool_ll, sizeof(lv_pool_t));

    /*Record the first pool*/
    lv_pool_t * pool_p = lv_ll_ins_tail(&state.pool_ll);
    LV_ASSERT_MALLOC(pool_p);
    *pool_p = lv_tlsf_get_pool(state.tlsf);

#if LV_MEM_ADD_JUNK
    LV_LOG_WARN("LV_MEM_ADD_JUNK is enabled which makes LVGL much slower");
#endif
}

void lv_mem_deinit(void)
{
    lv_ll_clear(&state.pool_ll);
    lv_tlsf_destroy(state.tlsf);
#if LV_USE_OS
    lv_mutex_delete(&state.mutex);
#endif
}

lv_mem_pool_t lv_mem_add_pool(void * mem, size_t bytes)
{
    lv_mem_pool_t new_pool = lv_tlsf_add_pool(state.tlsf, mem, bytes);
    if(!new_pool) {
        LV_LOG_WARN("failed to add memory pool, address: %p, size: %zu", mem, bytes);
        return NULL;
    }

    lv_pool_t * pool_p = lv_ll_ins_tail(&state.pool_ll);
    LV_ASSERT_MALLOC(pool_p);
    *pool_p = new_pool;

    return new_pool;
}

void lv_mem_remove_pool(lv_mem_pool_t pool)
{
    lv_pool_t * pool_p;
    LV_LL_READ(&state.pool_ll, pool_p) {
        if(*pool_p == pool) {
            lv_ll_remove(&state.pool_ll, pool_p);
            lv_free(pool_p);
            lv_tlsf_remove_pool(state.tlsf, pool);
            return;
        }
    }
    LV_LOG_WARN("invalid pool: %p", pool);
}

void * lv_malloc_core(size_t size)
{
#if LV_USE_OS
    lv_mutex_lock(&state.mutex);
#endif
    void * p = lv_tlsf_malloc(state.tlsf, size);

    if(p) {
        state.cur_used += lv_tlsf_block_size(p);
        state.max_used = LV_MAX(state.cur_used, state.max_used);
    }

#if LV_USE_OS
    lv_mutex_unlock(&state.mutex);
#endif
    return p;
}

void * lv_realloc_core(void * p, size_t new_size)
{
#if LV_USE_OS
    lv_mutex_lock(&state.mutex);
#endif

    size_t old_size = lv_tlsf_block_size(p);
    void * p_new = lv_tlsf_realloc(state.tlsf, p, new_size);

    if(p_new) {
        state.cur_used -= old_size;
        state.cur_used += lv_tlsf_block_size(p_new);
        state.max_used = LV_MAX(state.cur_used, state.max_used);
    }
#if LV_USE_OS
    lv_mutex_unlock(&state.mutex);
#endif

    return p_new;
}

void lv_free_core(void * p)
{
#if LV_USE_OS
    lv_mutex_lock(&state.mutex);
#endif

#if LV_MEM_ADD_JUNK
    lv_memset(p, 0xbb, lv_tlsf_block_size(data));
#endif
    size_t size = lv_tlsf_block_size(p);
    lv_tlsf_free(state.tlsf, p);
    if(state.cur_used > size) state.cur_used -= size;
    else state.cur_used = 0;

#if LV_USE_OS
    lv_mutex_unlock(&state.mutex);
#endif
}

void lv_mem_monitor_core(lv_mem_monitor_t * mon_p)
{
    /*Init the data*/
    lv_memzero(mon_p, sizeof(lv_mem_monitor_t));
    LV_TRACE_MEM("begin");

    lv_pool_t * pool_p;
    LV_LL_READ(&state.pool_ll, pool_p) {
        lv_tlsf_walk_pool(*pool_p, lv_mem_walker, mon_p);
    }

    mon_p->used_pct = 100 - (uint64_t)100U * mon_p->free_size / mon_p->total_size;
    if(mon_p->free_size > 0) {
        mon_p->frag_pct = (uint64_t)mon_p->free_biggest_size * 100U / mon_p->free_size;
        mon_p->frag_pct = 100 - mon_p->frag_pct;
    }
    else {
        mon_p->frag_pct = 0; /*no fragmentation if all the RAM is used*/
    }

    mon_p->max_used = state.max_used;

    LV_TRACE_MEM("finished");
}

lv_result_t lv_mem_test_core(void)
{
#if LV_USE_OS
    lv_mutex_lock(&state.mutex);
#endif
    if(lv_tlsf_check(state.tlsf)) {
        LV_LOG_WARN("failed");
#if LV_USE_OS
        lv_mutex_unlock(&state.mutex);
#endif
        return LV_RESULT_INVALID;
    }

    lv_pool_t * pool_p;
    LV_LL_READ(&state.pool_ll, pool_p) {
        if(lv_tlsf_check_pool(*pool_p)) {
            LV_LOG_WARN("pool failed");
#if LV_USE_OS
            lv_mutex_unlock(&state.mutex);
#endif
            return LV_RESULT_INVALID;
        }
    }

    LV_TRACE_MEM("passed");
#if LV_USE_OS
    lv_mutex_unlock(&state.mutex);
#endif
    return LV_RESULT_OK;
}

/**********************
 *   STATIC FUNCTIONS
 **********************/

static void lv_mem_walker(void * ptr, size_t size, int used, void * user)
{
    LV_UNUSED(ptr);

    lv_mem_monitor_t * mon_p = user;
    mon_p->total_size += size;
    if(used) {
        mon_p->used_cnt++;
    }
    else {
        mon_p->free_cnt++;
        mon_p->free_size += size;
        if(size > mon_p->free_biggest_size)
            mon_p->free_biggest_size = size;
    }
}
#endif /*LV_STDLIB_BUILTIN*/