29#if !defined(_XOPEN_SOURCE) || (_XOPEN_SOURCE - 0) < 600
30#define _POSIX_C_SOURCE 200112L
32#define _XOPEN_SOURCE 600
35#include "hdrl_buffer.h"
36#include "hdrl_types.h"
37#include "hdrl_utils.h"
54static int hdrl_fallocate(
int fd, off_t offset, off_t len)
58 return ftruncate(fd, offset + len);
60 return posix_fallocate(fd, offset, len);
64static const size_t hdrl_pool_minsize = 2<<20;
78 hdrl_free * destructor;
90typedef hdrl_pool_base hdrl_pool;
92static void hdrl_pool_mmap_delete(
void * pool)
96 hdrl_pool_mmap * p = pool;
98 if (ftruncate(p->fd, 0)) {}
99 munmap(p->p.base, p->p.size);
103static hdrl_pool * hdrl_pool_mmap_new(
size_t pool_size)
105 hdrl_pool_mmap * pool = cpl_malloc(
sizeof(*pool));
106 pool_size = CX_MAX(pool_size, hdrl_pool_minsize);
107 pool->p.destructor = &hdrl_pool_mmap_delete;
110 char *cwd = hdrl_get_cwd();
111 int cwd_fd = hdrl_get_tempfile(cwd, CPL_TRUE);
115 int tmp_fd = hdrl_get_tempfile(NULL, CPL_TRUE);
116 if (hdrl_fallocate(tmp_fd, 0, pool_size) != 0) {
118 if (hdrl_fallocate(cwd_fd, 0, pool_size) != 0) {
121 cpl_error_set_message(cpl_func, CPL_ERROR_FILE_IO,
122 "Allocation of %zu bytes failed", pool_size);
131 pool->p.base = mmap(NULL, pool_size, PROT_READ | PROT_WRITE, MAP_SHARED,
134 if (pool->p.base == MAP_FAILED) {
137 cpl_error_set_message(cpl_func, CPL_ERROR_FILE_IO,
138 "Allocation of %zu bytes failed", pool_size);
142 pool->p.size = pool_size;
143 pool->p.free_offset = pool->p.base;
145 cpl_msg_debug(cpl_func,
"Creating mmap pool %p of size %zu",
146 (
const void*)pool, pool_size);
148 return (hdrl_pool*)pool;
151static void hdrl_pool_malloc_delete(
void * pool)
155 cpl_free(((hdrl_pool*)pool)->base);
158static hdrl_pool * hdrl_pool_malloc_new(
size_t pool_size)
160 hdrl_pool_mmap * pool = cpl_malloc(
sizeof(*pool));
161 pool->p.size = CX_MAX(pool_size, hdrl_pool_minsize);
162 pool->p.destructor = &hdrl_pool_malloc_delete;
164 pool->p.base = cpl_malloc(pool_size);
165 pool->p.free_offset = pool->p.base;
166 cpl_msg_debug(cpl_func,
"Creating malloc pool %p of size %zu",
167 (
const void*)pool, pool_size);
168 return (hdrl_pool*)pool;
171static void hdrl_pool_delete(hdrl_pool * pool)
177 cpl_msg_debug(cpl_func,
"Deleting pool %p", (
const void*)pool);
178 pool->destructor(pool);
182static size_t hdrl_pool_available(hdrl_pool * p)
184 return (p->base + p->size - p->free_offset);
187static char * hdrl_pool_alloc(hdrl_pool * p,
size_t n)
189 if (hdrl_pool_available(p) < n) {
192 char * b = p->free_offset;
194 cpl_msg_debug(cpl_func,
"Allocating %zu from pool of size %zu (%zu)",
195 n, p->size, hdrl_pool_available(p));
199static hdrl_pool * hdrl_pool_get_from_ptr(
char * HDRL_UNUSED(p))
211hdrl_buffer * hdrl_buffer_new(
void)
214 hdrl_buffer * buf = cpl_malloc(
sizeof(*buf));
215 buf->pools = cx_list_new();
216 buf->freelist = cx_list_new();
217 buf->pool_size = 128ul * (1ul << 20ul);
219 buf->malloc_thresh = 0;
235size_t hdrl_buffer_set_malloc_threshold(hdrl_buffer * buf,
size_t t)
237 size_t o = buf->malloc_thresh;
238 buf->malloc_thresh = t * (1ul << 20ul);
242void hdrl_buffer_readonly(hdrl_buffer * buf, cpl_boolean ro)
245 for (cx_list_iterator it = cx_list_begin(buf->pools);
246 it != cx_list_end(buf->pools);
247 it = cx_list_next(buf->pools, it)) {
248 hdrl_pool * pool = cx_list_get(buf->pools, it);
250 mprotect(pool->base, pool->size, PROT_READ);
253 mprotect(pool->base, pool->size, PROT_READ | PROT_WRITE);
268char * hdrl_buffer_allocate(hdrl_buffer * buf,
size_t size)
270 hdrl_pool * p = NULL;
272 for (cx_list_iterator it = cx_list_begin(buf->freelist);
273 it != cx_list_end(buf->freelist);
274 it = cx_list_next(buf->freelist, it)) {
275 hdrl_pool * _p = cx_list_get(buf->freelist, it);
276 if (hdrl_pool_available(_p) >= size) {
278 cpl_msg_debug(cpl_func,
"Found free available in pool.");
285 cx_list_empty(buf->freelist);
286 if (buf->total_size + size < buf->malloc_thresh ||
287 getenv(
"HDRL_BUFFER_MALLOC")) {
288 p = hdrl_pool_malloc_new(CX_MAX(size, buf->pool_size));
291 p = hdrl_pool_mmap_new(CX_MAX(size, buf->pool_size));
293 cx_list_push_back(buf->pools, p);
295 if (size < buf->pool_size / 2) {
296 cx_list_push_back(buf->freelist, p);
300 m = hdrl_pool_alloc(p, size);
301 buf->total_size += size;
305void hdrl_buffer_free(hdrl_buffer * HDRL_UNUSED(buf),
char * p)
307 hdrl_pool * pool = hdrl_pool_get_from_ptr(p);
321void hdrl_buffer_delete(hdrl_buffer * buf)
327 cpl_msg_debug(cpl_func,
"Deleting buffer with %zu pools",
328 cx_list_size(buf->pools));
329 cx_list_destroy(buf->pools, (hdrl_free*)&hdrl_pool_delete);
330 cx_list_delete(buf->freelist);