mempool-alloconly.c revision 7e80c968cd8cb63e874b9a5ad9e39bd510005a57
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch/* Copyright (c) 2002-2003 Timo Sirainen */
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch/* @UNSAFE: whole file */
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch#include "lib.h"
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch#include "mempool.h"
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch#include <stdlib.h>
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch#ifdef HAVE_GC_GC_H
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch# include <gc/gc.h>
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch#elif defined (HAVE_GC_H)
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch# include <gc.h>
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch#endif
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch#define MAX_ALLOC_SIZE SSIZE_T_MAX
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Boschstruct alloconly_pool {
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch struct pool pool;
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch int refcount;
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch size_t base_size;
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch struct pool_block *block;
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch#ifdef DEBUG
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch const char *name;
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch#endif
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch};
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Boschstruct pool_block {
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch struct pool_block *prev;
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch size_t size;
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch size_t left;
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch size_t last_alloc_size;
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch /* unsigned char data[]; */
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch};
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch#define SIZEOF_POOLBLOCK (MEM_ALIGN(sizeof(struct pool_block)))
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch#define POOL_BLOCK_DATA(block) \
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch ((char *) (block) + SIZEOF_POOLBLOCK)
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Boschstatic const char *pool_alloconly_get_name(pool_t pool);
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Boschstatic void pool_alloconly_ref(pool_t pool);
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Boschstatic void pool_alloconly_unref(pool_t pool);
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Boschstatic void *pool_alloconly_malloc(pool_t pool, size_t size);
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Boschstatic void pool_alloconly_free(pool_t pool, void *mem);
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Boschstatic void *pool_alloconly_realloc(pool_t pool, void *mem,
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch size_t old_size, size_t new_size);
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Boschstatic void pool_alloconly_clear(pool_t pool);
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Boschstatic size_t pool_alloconly_get_max_easy_alloc_size(pool_t pool);
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Boschstatic void block_alloc(struct alloconly_pool *pool, size_t size);
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Boschstatic struct pool static_alloconly_pool = {
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch pool_alloconly_get_name,
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch pool_alloconly_ref,
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch pool_alloconly_unref,
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch pool_alloconly_malloc,
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch pool_alloconly_free,
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch pool_alloconly_realloc,
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch pool_alloconly_clear,
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch pool_alloconly_get_max_easy_alloc_size,
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch TRUE,
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch FALSE
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch};
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Boschpool_t pool_alloconly_create(const char *name __attr_unused__, size_t size)
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch{
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch struct alloconly_pool apool, *new_apool;
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch size_t min_alloc = sizeof(struct alloconly_pool) + SIZEOF_POOLBLOCK;
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch#ifdef DEBUG
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch min_alloc += strlen(name) + 1;
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch#endif
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch /* create a fake alloconly_pool so we can call block_alloc() */
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch memset(&apool, 0, sizeof(apool));
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch apool.pool = static_alloconly_pool;
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch apool.refcount = 1;
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch if (size < min_alloc)
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch size = nearest_power(size + min_alloc);
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch block_alloc(&apool, size);
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch /* now allocate the actual alloconly_pool from the created block */
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch new_apool = p_new(&apool.pool, struct alloconly_pool, 1);
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch *new_apool = apool;
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch#ifdef DEBUG
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen new_apool->name = p_strdup(&new_apool->pool, name);
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch#endif
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch /* set base_size so p_clear() doesn't trash alloconly_pool structure. */
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch new_apool->base_size = new_apool->block->size - new_apool->block->left;
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch new_apool->block->last_alloc_size = 0;
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch return &new_apool->pool;
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch}
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Boschstatic void pool_alloconly_destroy(struct alloconly_pool *apool)
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch{
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch void *block;
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch /* destroy all but the last block */
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch pool_alloconly_clear(&apool->pool);
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch /* destroy the last block */
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch block = apool->block;
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch#ifdef DEBUG
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch memset(block, 0xde, SIZEOF_POOLBLOCK + apool->block->size);
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch#endif
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch#ifndef USE_GC
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch free(block);
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch#endif
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch}
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Boschstatic const char *pool_alloconly_get_name(pool_t pool __attr_unused__)
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch{
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch#ifdef DEBUG
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch struct alloconly_pool *apool = (struct alloconly_pool *) pool;
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch return apool->name;
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch#else
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch return "alloconly";
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch#endif
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch}
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Boschstatic void pool_alloconly_ref(pool_t pool)
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch{
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch struct alloconly_pool *apool = (struct alloconly_pool *) pool;
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch apool->refcount++;
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch}
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Boschstatic void pool_alloconly_unref(pool_t pool)
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch{
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch struct alloconly_pool *apool = (struct alloconly_pool *) pool;
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch if (--apool->refcount == 0)
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch pool_alloconly_destroy(apool);
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch}
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Boschstatic void block_alloc(struct alloconly_pool *apool, size_t size)
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch{
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch struct pool_block *block;
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch i_assert(size > SIZEOF_POOLBLOCK);
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch if (apool->block != NULL) {
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch /* each block is at least twice the size of the previous one */
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch if (size <= apool->block->size)
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch size += apool->block->size;
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch size = nearest_power(size);
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch#ifdef DEBUG
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch i_warning("Growing pool '%s' with: %"PRIuSIZE_T,
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch apool->name, size);
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch#endif
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch }
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch#ifndef USE_GC
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch block = calloc(size, 1);
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch#else
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch block = GC_malloc(size);
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch memset(block, 0, size);
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch#endif
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch if (block == NULL)
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch i_fatal_status(FATAL_OUTOFMEM, "block_alloc(): Out of memory");
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch block->prev = apool->block;
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch apool->block = block;
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch block->size = size - SIZEOF_POOLBLOCK;
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch block->left = block->size;
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch}
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Boschstatic void *pool_alloconly_malloc(pool_t pool, size_t size)
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch{
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch struct alloconly_pool *apool = (struct alloconly_pool *) pool;
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch void *mem;
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch if (size == 0 || size > SSIZE_T_MAX)
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch i_panic("Trying to allocate %"PRIuSIZE_T" bytes", size);
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch size = MEM_ALIGN(size);
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch if (apool->block->left < size) {
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch /* we need a new block */
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch block_alloc(apool, size + SIZEOF_POOLBLOCK);
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch }
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch mem = POOL_BLOCK_DATA(apool->block) +
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch (apool->block->size - apool->block->left);
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch apool->block->left -= size;
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch apool->block->last_alloc_size = size;
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch return mem;
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch}
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Boschstatic void pool_alloconly_free(pool_t pool, void *mem)
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch{
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch struct alloconly_pool *apool = (struct alloconly_pool *) pool;
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch /* we can free only the last allocation */
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch if (POOL_BLOCK_DATA(apool->block) +
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch (apool->block->size - apool->block->left -
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch apool->block->last_alloc_size) == mem) {
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch memset(mem, 0, apool->block->last_alloc_size);
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch apool->block->left += apool->block->last_alloc_size;
639bb36b12b9f9bb54c8bb1be50eac623622f8a0Timo Sirainen apool->block->last_alloc_size = 0;
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch }
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch}
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Boschstatic int pool_try_grow(struct alloconly_pool *apool, void *mem, size_t size)
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch{
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch /* see if we want to grow the memory we allocated last */
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch if (POOL_BLOCK_DATA(apool->block) +
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch (apool->block->size - apool->block->left -
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch apool->block->last_alloc_size) == mem) {
639bb36b12b9f9bb54c8bb1be50eac623622f8a0Timo Sirainen /* yeah, see if we can grow */
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch if (apool->block->left >= size-apool->block->last_alloc_size) {
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch /* just shrink the available size */
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch apool->block->left -=
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch size - apool->block->last_alloc_size;
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch apool->block->last_alloc_size = size;
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch return TRUE;
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch }
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch }
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch return FALSE;
639bb36b12b9f9bb54c8bb1be50eac623622f8a0Timo Sirainen}
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch
639bb36b12b9f9bb54c8bb1be50eac623622f8a0Timo Sirainenstatic void *pool_alloconly_realloc(pool_t pool, void *mem,
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch size_t old_size, size_t new_size)
639bb36b12b9f9bb54c8bb1be50eac623622f8a0Timo Sirainen{
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch struct alloconly_pool *apool = (struct alloconly_pool *) pool;
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch unsigned char *new_mem;
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch if (new_size == 0 || new_size > SSIZE_T_MAX)
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch i_panic("Trying to allocate %"PRIuSIZE_T" bytes", new_size);
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch if (mem == NULL)
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch return pool_alloconly_malloc(pool, new_size);
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch if (new_size <= old_size)
639bb36b12b9f9bb54c8bb1be50eac623622f8a0Timo Sirainen return mem;
4351efdddced25735d629496f6c68c9d0cfb896aTimo Sirainen
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch new_size = MEM_ALIGN(new_size);
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch /* see if we can directly grow it */
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch if (!pool_try_grow(apool, mem, new_size)) {
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch /* slow way - allocate + copy */
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch new_mem = pool_alloconly_malloc(pool, new_size);
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch memcpy(new_mem, mem, old_size);
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch mem = new_mem;
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch }
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch return mem;
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch}
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Boschstatic void pool_alloconly_clear(pool_t pool)
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch{
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch struct alloconly_pool *apool = (struct alloconly_pool *) pool;
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch struct pool_block *block;
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch size_t avail_size;
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch /* destroy all blocks but the oldest, which contains the
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch struct alloconly_pool allocation. */
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch while (apool->block->prev != NULL) {
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch block = apool->block;
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch apool->block = block->prev;
639bb36b12b9f9bb54c8bb1be50eac623622f8a0Timo Sirainen
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch#ifdef DEBUG
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch memset(block, 0xde, SIZEOF_POOLBLOCK + block->size);
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch#endif
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch#ifndef USE_GC
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch free(block);
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch#endif
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch }
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch /* clear the first block */
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch avail_size = apool->block->size - apool->base_size;
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch memset(PTR_OFFSET(POOL_BLOCK_DATA(apool->block), apool->base_size), 0,
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch avail_size - apool->block->left);
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch apool->block->left = avail_size;
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch apool->block->last_alloc_size = 0;
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch}
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Boschstatic size_t pool_alloconly_get_max_easy_alloc_size(pool_t pool)
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch{
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch struct alloconly_pool *apool = (struct alloconly_pool *) pool;
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch return apool->block->left;
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch}
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch