37#include <emscripten.h>
43#include <sys/resource.h>
51#if defined(__x86_64__) || defined(_M_X64) || defined(__ppc64__) || defined(__LP64__)
54#define struct_align 16
62typedef struct __attribute__((aligned(struct_align))) sfpool_t {
67 uint32_t total_blocks;
82static_assert(
sizeof(ptr_t) ==
sizeof(
void*),
"Unknown memory pointer size detected");
84static inline bool _is_in_pool(sfpool_t *pool,
const void *ptr) {
85 volatile ptr_t p = (ptr_t)ptr;
86 return(p >= (ptr_t)pool->data
87 && p < (ptr_t)(pool->data + pool->total_bytes));
103static inline void sfutil_zero(
void *ptr, uint32_t size) {
104 volatile uint8_t *p = (
volatile uint8_t*)ptr;
105 while (size--) *p++ = 0;
116static inline void *sfutil_memalign(
const void* ptr) {
117 register ptr_t mask = ptr_align - 1;
118 ptr_t aligned = ((ptr_t)ptr + mask) & ~mask;
119 return (
void*)aligned;
130static inline void *sfutil_secalloc(
size_t size) {
132 size_t alloc_size = size + ptr_align;
134#if defined(__EMSCRIPTEN__)
135 res = (uint8_t *)malloc(alloc_size);
137 res = VirtualAlloc(NULL, alloc_size,
138 MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
139#elif defined(__APPLE__)
140 int flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE;
141 res = mmap(NULL, alloc_size, PROT_READ | PROT_WRITE, flags, -1, 0);
142 if (res == MAP_FAILED)
return NULL;
143 mlock(res, alloc_size);
145 int flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE;
147 if (getrlimit(RLIMIT_MEMLOCK, &rl) == 0)
148 if(alloc_size<=rl.rlim_cur) flags |= MAP_LOCKED;
149 res = mmap(NULL, alloc_size, PROT_READ | PROT_WRITE, flags, -1, 0);
150 if (res == MAP_FAILED)
return NULL;
163static inline void sfutil_secfree(
void *ptr,
size_t size) {
164 size_t alloc_size = size + ptr_align;
165#if defined(__EMSCRIPTEN__)
168 VirtualFree(ptr, 0, MEM_RELEASE);
170 munmap(ptr, alloc_size);
193static inline size_t sfpool_init(sfpool_t *pool,
size_t nmemb,
size_t blocksize) {
194 if (pool == NULL)
return 0;
195 memset(pool, 0,
sizeof(sfpool_t));
196 if (nmemb == 0)
return 0;
197 if (blocksize <
sizeof(
void*))
return 0;
198 if((blocksize & (blocksize - 1)) != 0)
return 0;
199 if (nmemb > (SIZE_MAX / blocksize))
return 0;
201 size_t totalsize = nmemb * blocksize;
202 pool->buffer = sfutil_secalloc(totalsize);
203 if (pool->buffer == NULL)
return 0;
205 pool->data = sfutil_memalign(pool->buffer);
206 if (pool->data == NULL)
return 0;
208 pool->total_bytes = totalsize;
209 pool->total_blocks = nmemb;
210 pool->block_size = blocksize;
212 pool->free_list = pool->data;
213 register uint32_t i, bi;
214 for (i = 0; i < pool->total_blocks - 1; ++i) {
216 *(uint8_t **)(pool->data + bi) =
217 pool->data + bi + blocksize;
219 pool->free_count = pool->total_blocks;
221 (pool->data + (pool->total_blocks - 1) * blocksize) = NULL;
223 pool->miss_total = pool->miss_bytes = 0;
224 pool->hits_total = pool->hits_bytes = 0;
225 pool->alloc_total = 0;
238static inline void sfpool_teardown(sfpool_t *restrict pool) {
240 sfutil_secfree(pool->buffer, pool->total_bytes);
242 pool->miss_total = pool->miss_bytes = 0;
243 pool->hits_total = pool->hits_bytes = 0;
244 pool->alloc_total = 0;
258static inline void *sfpool_malloc(
void *restrict opaque,
const size_t size) {
259 sfpool_t *pool = (sfpool_t*)opaque;
261 if (size <= pool->block_size
262 && pool->free_list != NULL) {
265 pool->hits_bytes+=size;
266 pool->alloc_total+=size;
269 uint8_t *block = pool->free_list;
270 pool->free_list = *(uint8_t **)block;
276 if(ptr == NULL) perror(
"system malloc error");
279 pool->miss_bytes+=size;
280 pool->alloc_total+=size;
295static inline void sfpool_free(
void *restrict opaque,
void *ptr) {
296 sfpool_t *pool = (sfpool_t*)opaque;
297 if (ptr == NULL)
return;
298 if (_is_in_pool(pool,ptr)) {
301 sfutil_zero(ptr, pool->block_size);
304 *(uint8_t **)ptr = pool->free_list;
305 pool->free_list = (uint8_t *)ptr;
326static inline void *sfpool_realloc(
void *restrict opaque,
void *ptr,
const size_t size) {
327 sfpool_t *pool = (sfpool_t*)opaque;
329 return sfpool_malloc(pool, size);
332 sfpool_free(pool, ptr);
335 if (_is_in_pool((sfpool_t*)pool,ptr)) {
336 if (size <= pool->block_size) {
339 pool->hits_bytes+=size;
340 pool->alloc_total+=size;
344 void *new_ptr = malloc(size);
345 if (new_ptr == NULL)
return NULL;
346 memcpy(new_ptr, ptr, pool->block_size);
349 sfutil_zero(ptr, pool->block_size);
352 *(uint8_t **)ptr = pool->free_list;
353 pool->free_list = (uint8_t *)ptr;
357 pool->miss_bytes+=size;
358 pool->alloc_total+=size;
364 return realloc(ptr, size);
367 pool->miss_bytes+=size;
368 pool->alloc_total+=size;
382static inline int sfpool_contains(
void *restrict opaque,
const void *ptr) {
383 sfpool_t *pool = (sfpool_t*)opaque;
385 if( _is_in_pool(pool,ptr) ) res = 1;
398static inline void sfpool_status(sfpool_t *restrict p) {
399 fprintf(stderr,
"\nš sfpool: %u blocks %u B each\n",
400 p->total_blocks, p->block_size);
402 fprintf(stderr,
"š Total: %lu K\n",
403 p->alloc_total/1024);
404 fprintf(stderr,
"š Misses: %lu K (%u calls)\n",p->miss_bytes/1024,p->miss_total);
405 fprintf(stderr,
"š Hits: %lu K (%u calls)\n",p->hits_bytes/1024,p->hits_total);