diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 09:51:24 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 09:51:24 +0000 |
commit | f7548d6d28c313cf80e6f3ef89aed16a19815df1 (patch) | |
tree | a3f6f2a3f247293bee59ecd28e8cd8ceb6ca064a /src/lib/mempool-datastack.c | |
parent | Initial commit. (diff) | |
download | dovecot-upstream.tar.xz dovecot-upstream.zip |
Adding upstream version 1:2.3.19.1+dfsg1.upstream/1%2.3.19.1+dfsg1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | src/lib/mempool-datastack.c | 190 |
1 files changed, 190 insertions, 0 deletions
diff --git a/src/lib/mempool-datastack.c b/src/lib/mempool-datastack.c new file mode 100644 index 0000000..b3c1094 --- /dev/null +++ b/src/lib/mempool-datastack.c @@ -0,0 +1,190 @@ +/* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "mempool.h" + +/* + * The datastack pool is a thin wrapper around the datastack API. It exists + * to allow datastack allocations via the pool API. + * + * Note: Do not confuse it with the *unsafe* datastack pool. + * + * Implementation + * ============== + * + * A datastack pool maintains information about the datastack frame that was + * in use when the pool was created so it can sanity check all p_new(), + * p_malloc(), and p_realloc() calls. + * + * Creation + * -------- + * + * When a datastack pool is created, a new pool structure is allocated from + * the datastack (via t_new()). The current datastack frame number is saved + * into the pool's private data (struct datastack_pool). + * + * Allocation & Reallocation + * ------------------------- + * + * After verifying that the saved datastack frame id matches the currently + * active one, the p_malloc() and p_realloc() calls get directed to + * t_malloc0() and t_try_realloc(), respectively. There is no + * per-allocation information to track. + * + * Freeing + * ------- + * + * Freeing is a no-op unless the currently active data stack frame id is + * different from the one saved during pool creation, in which case the + * process panics. + * + * Clearing + * -------- + * + * A no-op. + * + * Destruction + * ----------- + * + * Since the memory backing the pool structure itself is allocated from the + * datastack via t_new(), the pool and all allocations it made are freed + * when the datastack frame is popped. + * + * Even though the pool maintains a reference count, no memory is freed when + * it reaches zero. Once the reference count reaches zero, the state of the + * pool is undefined and none of its memory maybe be used. + */ + +static const char *pool_data_stack_get_name(pool_t pool); +static void pool_data_stack_ref(pool_t pool); +static void pool_data_stack_unref(pool_t *pool); +static void *pool_data_stack_malloc(pool_t pool, size_t size); +static void pool_data_stack_free(pool_t pool, void *mem); +static void *pool_data_stack_realloc(pool_t pool, void *mem, + size_t old_size, size_t new_size); +static void pool_data_stack_clear(pool_t pool); +static size_t pool_data_stack_get_max_easy_alloc_size(pool_t pool); + +static struct pool_vfuncs static_data_stack_pool_vfuncs = { + pool_data_stack_get_name, + + pool_data_stack_ref, + pool_data_stack_unref, + + pool_data_stack_malloc, + pool_data_stack_free, + + pool_data_stack_realloc, + + pool_data_stack_clear, + pool_data_stack_get_max_easy_alloc_size +}; + +static const struct pool static_data_stack_pool = { + .v = &static_data_stack_pool_vfuncs, + + .alloconly_pool = TRUE, + .datastack_pool = TRUE +}; + +struct datastack_pool { + struct pool pool; + int refcount; + + unsigned int data_stack_frame; +}; + +pool_t pool_datastack_create(void) +{ + struct datastack_pool *dpool; + + dpool = t_new(struct datastack_pool, 1); + dpool->pool = static_data_stack_pool; + dpool->refcount = 1; + dpool->data_stack_frame = data_stack_frame_id; + return &dpool->pool; +} + +static const char *pool_data_stack_get_name(pool_t pool ATTR_UNUSED) +{ + return "data stack"; +} + +static void pool_data_stack_ref(pool_t pool) +{ + struct datastack_pool *dpool = + container_of(pool, struct datastack_pool, pool); + + if (unlikely(dpool->data_stack_frame != data_stack_frame_id)) + i_panic("pool_data_stack_ref(): stack frame changed"); + + dpool->refcount++; +} + +static void pool_data_stack_unref(pool_t *pool) +{ + struct datastack_pool *dpool = + container_of(*pool, struct datastack_pool, pool); + + if (unlikely(dpool->data_stack_frame != data_stack_frame_id)) + i_panic("pool_data_stack_unref(): stack frame changed"); + + dpool->refcount--; + i_assert(dpool->refcount >= 0); + + *pool = NULL; +} + +static void *pool_data_stack_malloc(pool_t pool ATTR_UNUSED, size_t size) +{ + struct datastack_pool *dpool = + container_of(pool, struct datastack_pool, pool); + + if (unlikely(dpool->data_stack_frame != data_stack_frame_id)) + i_panic("pool_data_stack_malloc(): stack frame changed"); + + return t_malloc0(size); +} + +static void pool_data_stack_free(pool_t pool, void *mem ATTR_UNUSED) +{ + struct datastack_pool *dpool = + container_of(pool, struct datastack_pool, pool); + + if (unlikely(dpool->data_stack_frame != data_stack_frame_id)) + i_panic("pool_data_stack_free(): stack frame changed"); +} + +static void *pool_data_stack_realloc(pool_t pool, void *mem, + size_t old_size, size_t new_size) +{ + struct datastack_pool *dpool = + container_of(pool, struct datastack_pool, pool); + void *new_mem; + + /* @UNSAFE */ + if (unlikely(dpool->data_stack_frame != data_stack_frame_id)) + i_panic("pool_data_stack_realloc(): stack frame changed"); + + if (old_size >= new_size) + return mem; + + if (!t_try_realloc(mem, new_size)) { + new_mem = t_malloc_no0(new_size); + memcpy(new_mem, mem, old_size); + mem = new_mem; + } + + memset((char *) mem + old_size, 0, new_size - old_size); + return mem; +} + +static void pool_data_stack_clear(pool_t pool ATTR_UNUSED) +{ +} + +static size_t +pool_data_stack_get_max_easy_alloc_size(pool_t pool ATTR_UNUSED) +{ + return t_get_bytes_available(); +} |