-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathlua_pool.c
More file actions
124 lines (104 loc) · 3.39 KB
/
lua_pool.c
File metadata and controls
124 lines (104 loc) · 3.39 KB
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
#include "lua_pool.h"
#include <stdbool.h>
#include <string.h>
#include "lua/lua.h"
#include "lua/lualib.h"
#include "lua/lauxlib.h"
#include "lua_functions.h"
#include "memory.h"
typedef struct BlockHeader {
size_t size; // usable size (excluding header)
bool free;
} BlockHeader;
#define BLOCK_HDR_SIZE (sizeof(BlockHeader))
#define MIN_BLOCK_SIZE 8
static bool lua_heap_initialized = false;
static size_t lua_heap_used = 0;
static void lua_heap_init(void) {
BlockHeader *first = (BlockHeader *)tinybit_memory->lua_state;
first->size = TB_MEM_LUA_STATE_SIZE - BLOCK_HDR_SIZE;
first->free = true;
lua_heap_initialized = true;
lua_heap_used = 0;
}
static void *pool_alloc(size_t size) {
// align to pointer size
size = (size + sizeof(void*) - 1) & ~(sizeof(void*) - 1);
uint8_t *pos = tinybit_memory->lua_state;
while (pos < tinybit_memory->lua_state + TB_MEM_LUA_STATE_SIZE) {
BlockHeader *hdr = (BlockHeader *)pos;
if (hdr->free && hdr->size >= size) {
// split if remaining space is large enough
if (hdr->size >= size + BLOCK_HDR_SIZE + MIN_BLOCK_SIZE) {
BlockHeader *next = (BlockHeader *)(pos + BLOCK_HDR_SIZE + size);
next->size = hdr->size - size - BLOCK_HDR_SIZE;
next->free = true;
hdr->size = size;
}
hdr->free = false;
lua_heap_used += hdr->size;
return pos + BLOCK_HDR_SIZE;
}
pos += BLOCK_HDR_SIZE + hdr->size;
}
return NULL; // out of memory
}
static void pool_free(void *ptr) {
if (!ptr) return;
BlockHeader *hdr = (BlockHeader *)((uint8_t *)ptr - BLOCK_HDR_SIZE);
hdr->free = true;
lua_heap_used -= hdr->size;
// coalesce with next block
uint8_t *next_pos = (uint8_t *)ptr + hdr->size;
if (next_pos < tinybit_memory->lua_state + TB_MEM_LUA_STATE_SIZE) {
BlockHeader *next = (BlockHeader *)next_pos;
if (next->free) {
hdr->size += BLOCK_HDR_SIZE + next->size;
}
}
// coalesce with previous block (scan from start)
uint8_t *pos = tinybit_memory->lua_state;
while (pos < (uint8_t *)hdr) {
BlockHeader *prev = (BlockHeader *)pos;
uint8_t *prev_end = pos + BLOCK_HDR_SIZE + prev->size;
if (prev_end == (uint8_t *)hdr && prev->free) {
prev->size += BLOCK_HDR_SIZE + hdr->size;
break;
}
pos = prev_end;
}
}
static void *l_alloc_pool(void *ud, void *ptr, size_t osize, size_t nsize) {
(void)ud;
if (!lua_heap_initialized) {
lua_heap_init();
}
if (nsize == 0) {
pool_free(ptr);
return NULL;
}
if (ptr == NULL) {
return pool_alloc(nsize);
}
// realloc: allocate new block, copy, free old
void *new_ptr = pool_alloc(nsize);
if (new_ptr) {
memcpy(new_ptr, ptr, osize < nsize ? osize : nsize);
pool_free(ptr);
}
return new_ptr;
}
lua_State* lua_pool_newstate(void) {
lua_State *L = lua_newstate(l_alloc_pool, NULL);
if (L) {
lua_setup(L);
// Tune GC for small 256KB memory pool:
// - pause=120: (default 100) start new cycle when memory is 120% of last cycle
// - stepmul=200: (default 100) do 2x more work per step
lua_gc(L, LUA_GCINC, 120, 200, 0);
}
return L;
}
size_t lua_pool_get_used(void) {
return lua_heap_used;
}