Mercurial > dovecot > original-hg > dovecot-1.2
changeset 399:383503837741 HEAD
s/temporary memory pool/data stack/ which is the correct name for it.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Wed, 09 Oct 2002 20:44:04 +0300 |
parents | e807d88e653c |
children | f3ab97771ed8 |
files | src/lib/Makefile.am src/lib/data-stack.c src/lib/data-stack.h src/lib/lib.c src/lib/lib.h src/lib/temp-mempool.c src/lib/temp-mempool.h |
diffstat | 7 files changed, 577 insertions(+), 532 deletions(-) [+] |
line wrap: on
line diff
--- a/src/lib/Makefile.am Wed Oct 09 19:45:47 2002 +0300 +++ b/src/lib/Makefile.am Wed Oct 09 20:44:04 2002 +0300 @@ -13,6 +13,7 @@ liblib_a_SOURCES = \ base64.c \ compat.c \ + data-stack.c \ failures.c \ fdpass.c \ file-lock.c \ @@ -39,7 +40,6 @@ restrict-access.c \ sendfile-util.c \ strfuncs.c \ - temp-mempool.c \ temp-string.c \ unlink-directory.c \ unlink-lockfiles.c \ @@ -48,6 +48,7 @@ noinst_HEADERS = \ base64.h \ compat.h \ + data-stack.h \ failures.h \ fdpass.h \ file-lock.h \ @@ -72,7 +73,6 @@ restrict-access.h \ sendfile-util.h \ strfuncs.h \ - temp-mempool.h \ temp-string.h \ unlink-directory.h \ unlink-lockfiles.h \
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lib/data-stack.c Wed Oct 09 20:44:04 2002 +0300 @@ -0,0 +1,483 @@ +/* + data-stack.c : Data stack implementation + + Copyright (c) 2001-2002 Timo Sirainen + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#include "lib.h" +#include "data-stack.h" + +#include <stdlib.h> + +/* Use malloc() and free() for all memory allocations. Useful for debugging + memory corruption. */ +/* #define DISABLE_DATA_STACK */ + +#ifndef DISABLE_DATA_STACK + +/* Max. number of bytes to even try to allocate. This is done just to avoid + allocating less memory than was actually requested because of integer + overflows. */ +#define MAX_ALLOC_SIZE SSIZE_T_MAX + +/* Initial stack size - this should be kept in a size that doesn't exceed + in a normal use to avoid extra malloc()ing. */ +#define INITIAL_STACK_SIZE (1024*32) + +typedef struct _StackBlock StackBlock; +typedef struct _StackFrameBlock StackFrameBlock; + +struct _StackBlock { + StackBlock *next; + + size_t size, left; + /* unsigned char data[]; */ +}; + +#define SIZEOF_MEMBLOCK MEM_ALIGN(sizeof(StackBlock)) + +#define STACK_BLOCK_DATA(block) \ + ((char *) (block) + SIZEOF_MEMBLOCK) + +/* current_frame_block contains last t_push()ed frames. After that new + StackFrameBlock is created and it's ->prev is set to current_frame_block. */ +#define BLOCK_FRAME_COUNT 32 + +struct _StackFrameBlock { + StackFrameBlock *prev; + + StackBlock *block[BLOCK_FRAME_COUNT]; + size_t block_space_used[BLOCK_FRAME_COUNT]; + size_t last_alloc_size[BLOCK_FRAME_COUNT]; +}; + +static int frame_pos; /* current frame position current_frame_block */ +static StackFrameBlock *current_frame_block; /* current stack frame block */ +static StackFrameBlock *unused_frame_blocks; /* unused stack frames */ + +static StackBlock *current_block; /* block currently used for allocation */ +static StackBlock *unused_block; /* largest unused block is kept here */ + +static StackBlock *last_buffer_block; +static size_t last_buffer_size; + +int t_push(void) +{ + StackFrameBlock *frame_block; + + frame_pos++; + if (frame_pos == BLOCK_FRAME_COUNT) { + /* frame block full */ + frame_pos = 0; + if (unused_frame_blocks == NULL) { + /* allocate new block */ + frame_block = calloc(sizeof(StackFrameBlock), 1); + if (frame_block == NULL) + i_panic("t_push(): Out of memory"); + } else { + /* use existing unused frame_block */ + frame_block = unused_frame_blocks; + unused_frame_blocks = unused_frame_blocks->prev; + } + + frame_block->prev = current_frame_block; + current_frame_block = frame_block; + } + + /* mark our current position */ + current_frame_block->block[frame_pos] = current_block; + current_frame_block->block_space_used[frame_pos] = current_block->left; + current_frame_block->last_alloc_size[frame_pos] = 0; + + return frame_pos; +} + +static void free_blocks(StackBlock *block) +{ + /* free all the blocks, except if any of them is bigger than + unused_block, replace it */ + while (block != NULL) { + if (unused_block == NULL || block->size > unused_block->size) { + free(unused_block); + unused_block = block; + } else { + free(block); + } + + block = block->next; + } +} + +int t_pop(void) +{ + StackFrameBlock *frame_block; + int popped_frame_pos; + + if (frame_pos < 0) + i_panic("t_pop() called with empty stack"); + + /* update the current block */ + current_block = current_frame_block->block[frame_pos]; + current_block->left = current_frame_block->block_space_used[frame_pos]; + + if (current_block->next != NULL) { + /* free unused blocks */ + free_blocks(current_block->next); + current_block->next = NULL; + } + + popped_frame_pos = frame_pos; + if (frame_pos > 0) + frame_pos--; + else { + /* frame block is now unused, add it to unused list */ + frame_pos = BLOCK_FRAME_COUNT-1; + + frame_block = current_frame_block; + current_frame_block = frame_block->prev; + + frame_block->prev = unused_frame_blocks; + unused_frame_blocks = frame_block; + } + + return popped_frame_pos; +} + +static StackBlock *mem_block_alloc(size_t min_size) +{ + StackBlock *block; + size_t prev_size, alloc_size; + + prev_size = current_block == NULL ? 0 : current_block->size; + alloc_size = nearest_power(prev_size + min_size); + + block = malloc(SIZEOF_MEMBLOCK + alloc_size); + if (block == NULL) { + i_panic("mem_block_alloc(): " + "Out of memory when allocating %"PRIuSIZE_T" bytes", + alloc_size + SIZEOF_MEMBLOCK); + } + block->size = alloc_size; + block->next = NULL; + + return block; +} + +static void *t_malloc_real(size_t size, int permanent) +{ + StackBlock *block; + void *ret; + + if (size == 0) + return NULL; + + if (size > MAX_ALLOC_SIZE) + i_panic("Trying to allocate too much memory"); + + /* reset t_buffer_get() mark - not really needed but makes it easier + to notice if t_malloc() is called between t_buffer_get() and + t_buffer_alloc() */ + last_buffer_block = NULL; + + /* allocate only aligned amount of memory so alignment comes + always properly */ + size = MEM_ALIGN(size); + + /* used for t_try_grow() */ + current_frame_block->last_alloc_size[frame_pos] = size; + + if (current_block->left >= size) { + /* enough space in current block, use it */ + ret = STACK_BLOCK_DATA(current_block) + + (current_block->size - current_block->left); + if (permanent) + current_block->left -= size; + return ret; + } + + /* current block is full, see if we can use the unused_block */ + if (unused_block != NULL && unused_block->size >= size) { + block = unused_block; + unused_block = NULL; + } else { + block = mem_block_alloc(size); + } + + block->left = block->size; + if (permanent) + block->left -= size; + block->next = NULL; + + current_block->next = block; + current_block = block; + + return STACK_BLOCK_DATA(current_block); +} + +void *t_malloc(size_t size) +{ + return t_malloc_real(size, TRUE); +} + +void *t_malloc0(size_t size) +{ + void *mem; + + mem = t_malloc_real(size, TRUE); + memset(mem, 0, size); + return mem; +} + +int t_try_grow(void *mem, size_t size) +{ + size_t last_alloc_size; + + last_alloc_size = current_frame_block->last_alloc_size[frame_pos]; + + /* see if we're trying to grow the memory we allocated last */ + if (STACK_BLOCK_DATA(current_block) + + (current_block->size - current_block->left - + last_alloc_size) == mem) { + /* yeah, see if we have space to grow */ + size = MEM_ALIGN(size); + if (current_block->left >= size - last_alloc_size) { + /* just shrink the available size */ + current_block->left -= size - last_alloc_size; + current_frame_block->last_alloc_size[frame_pos] = size; + return TRUE; + } + } + + return FALSE; +} + +void *t_buffer_get(size_t size) +{ + void *ret; + + ret = t_malloc_real(size, FALSE); + + last_buffer_size = size; + last_buffer_block = current_block; + return ret; +} + +void *t_buffer_reget(void *buffer, size_t size) +{ + size_t old_size; + void *new_buffer; + + old_size = last_buffer_size; + if (size <= old_size) + return buffer; + + new_buffer = t_buffer_get(size); + if (new_buffer != buffer) + memcpy(new_buffer, buffer, old_size); + + return new_buffer; +} + +void t_buffer_alloc(size_t size) +{ + i_assert(last_buffer_block != NULL); + i_assert(last_buffer_size >= size); + i_assert(current_block->left >= size); + + /* we've already reserved the space, now we just mark it used */ + t_malloc_real(size, TRUE); +} + +void data_stack_init(void) +{ + current_block = mem_block_alloc(INITIAL_STACK_SIZE); + current_block->left = current_block->size; + current_block->next = NULL; + + current_frame_block = NULL; + unused_frame_blocks = NULL; + frame_pos = BLOCK_FRAME_COUNT-1; + + t_push(); + + last_buffer_block = NULL; + last_buffer_size = 0; +} + +void data_stack_deinit(void) +{ + t_pop(); + + if (frame_pos != BLOCK_FRAME_COUNT-1) + i_panic("Missing t_pop() call"); + + while (unused_frame_blocks != NULL) { + StackFrameBlock *frame_block = unused_frame_blocks; + unused_frame_blocks = unused_frame_blocks->prev; + + free(frame_block); + } + + free(current_block); + free(unused_block); +} + +#else + +typedef struct _StackFrame StackFrame; +typedef struct _FrameAlloc FrameAlloc; + +struct _StackFrame { + StackFrame *next; + FrameAlloc *allocs; +}; + +struct _FrameAlloc { + FrameAlloc *next; + void *mem; +}; + +static int stack_counter; +static StackFrame *current_frame; +static void *buffer_mem; + +int t_push(void) +{ + StackFrame *frame; + + frame = malloc(sizeof(StackFrame)); + frame->allocs = NULL; + + frame->next = current_frame_block; + current_frame_block = frame; + return stack_counter++; +} + +int t_pop(void) +{ + StackFrame *frame; + FrameAlloc *alloc; + + frame = current_frame_block; + current_frame_block = frame->next; + + while (frame->allocs != NULL) { + alloc = frame->allocs; + frame->allocs = alloc->next; + + free(alloc->mem); + free(alloc); + } + + free(frame); + return --stack_counter; +} + +static void add_alloc(void *mem) +{ + FrameAlloc *alloc; + + alloc = malloc(sizeof(FrameAlloc)); + alloc->mem = mem; + alloc->next = current_frame->allocs; + current_frame->allocs = alloc; + + if (buffer_mem != NULL) { + free(buffer_mem); + buffer_mem = NULL; + } +} + +void *t_malloc(size_t size) +{ + void *mem; + + mem = malloc(size); + add_alloc(mem); + return mem; +} + +void *t_malloc0(size_t size) +{ + void *mem; + + mem = calloc(size, 1); + add_alloc(mem); + return mem; +} + +int t_try_grow(void *mem, size_t size) +{ + void *new_mem; + + new_mem = realloc(mem, size); + if (new_mem == mem) + return TRUE; + + free(new_mem); + return FALSE; +} + +void *t_buffer_get(size_t size) +{ + buffer_mem = realloc(buffer_mem, size); + return buffer_mem; +} + +void *t_buffer_reget(void *buffer, size_t size) +{ + i_assert(buffer == buffer_mem); + + buffer_mem = realloc(buffer_mem, size); + return buffer_mem; +} + +void t_buffer_alloc(size_t size) +{ + void *mem; + + i_assert(buffer_mem != NULL); + + mem = buffer_mem; + buffer_mem = NULL; + + add_alloc(mem); +} + +void data_stack_init(void) +{ + stack_counter = 0; + current_frame_block = NULL; + buffer_mem = NULL; + + t_push(); +} + +void data_stack_deinit(void) +{ + t_pop(); + + if (stack_counter != 0) + i_panic("Missing t_pop() call"); +} + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lib/data-stack.h Wed Oct 09 20:44:04 2002 +0300 @@ -0,0 +1,89 @@ +#ifndef __DATA_STACK_H +#define __DATA_STACK_H + +/* Data stack makes it very easy to implement functions returning dynamic data + but without having to worry much about memory management like freeing the + result or having large enough buffers for result. + + t_ prefix was chosen to describe functions allocating memory from data + stack. "t" meaning temporary. + + Advantages over control stack: + - Functions can return a value allocated from data stack + - We can portably specify how much data we want to allocate at runtime + + Advantages over malloc(): + - FAST, most of the time allocating memory mean only updating a couple of + pointers and integers. Freeing the memory all at once also is a fast + operation. + - No need to free() each allocation resulting in prettier code + - No memory leaks + - No memory fragmentation + + Disadvantages: + - Allocating memory inside loops can accidentally allocate a lot of memory + if the loops are long and you forgot to place t_push() and t_pop() there. + - t_malloc()ed data could be accidentally stored into permanent location + and accessed after it's already been free'd. const'ing the return values + helps for most uses though (see the t_malloc() description). + - Debugging invalid memory usage requires recompilation with + -DDISABLE_DATA_STACK which then uses malloc() and free() for all + allocations and keeping track of them for stack frames making it much + slower. +*/ + +/* All t_..() allocations between t_push() and t_pop() are free'd + after t_pop() is called. Returns stack frame number which can be used + to detect missing t_pop() calls: + + x = t_push(); .. if (t_pop() != x) abort(); + + Note that the frame number wraps at some point (but t_pop() wraps it back). +*/ +int t_push(void); +int t_pop(void); + +/* WARNING: Be careful when using this functions, it's too easy to + accidentally save the returned value somewhere permanently. + + You probably should never use this function directly, rather + create functions that return 'const xxx*' types and use t_malloc() + internally in them. This is a lot safer, since usually compiler + warns if you try to place them in xxx*. See strfuncs.c for examples. */ +void *t_malloc(size_t size); +void *t_malloc0(size_t size); + +/* Try growing allocated memory. Returns TRUE if successful. Works only + for last allocated memory in current stack frame. */ +int t_try_grow(void *mem, size_t size); + +#define t_new(type, count) \ + ((type *) t_malloc0(sizeof(type) * (count))) + +/* Returns pointer to temporary buffer you can use. The buffer will be + invalid as soon as next t_malloc() is called! + + If you wish to grow the buffer, you must give the full wanted size + in the size parameter. If return value doesn't point to the same value + as last time, you need to memcpy() the data from old buffer the this + new one (or do some other trickery). See t_buffer_reget(). */ +#define t_buffer_get_type(type, size) \ + t_buffer_get(sizeof(type) * (size)) +void *t_buffer_get(size_t size); + +/* Grow the buffer, memcpy()ing the memory to new location if needed. */ +#define t_buffer_reget_type(buffer, type, size) \ + t_buffer_reget(buffer, sizeof(type) * (size)) +void *t_buffer_reget(void *buffer, size_t size); + +/* Make given t_buffer_get()ed buffer permanent. Note that size MUST be + less or equal than the size you gave with last t_buffer_get() or the + result will be undefined. */ +#define t_buffer_alloc_type(type, size) \ + t_buffer_alloc(sizeof(type) * (size)) +void t_buffer_alloc(size_t size); + +void data_stack_init(void); +void data_stack_deinit(void); + +#endif
--- a/src/lib/lib.c Wed Oct 09 19:45:47 2002 +0300 +++ b/src/lib/lib.c Wed Oct 09 20:44:04 2002 +0300 @@ -44,13 +44,13 @@ srand((unsigned int) time(NULL)); failures_init(); - temp_mempool_init(); + data_stack_init(); imem_init(); } void lib_deinit(void) { imem_deinit(); - temp_mempool_deinit(); + data_stack_deinit(); failures_deinit(); }
--- a/src/lib/lib.h Wed Oct 09 19:45:47 2002 +0300 +++ b/src/lib/lib.h Wed Oct 09 20:44:04 2002 +0300 @@ -25,8 +25,8 @@ #include "macros.h" #include "failures.h" +#include "data-stack.h" #include "mempool.h" -#include "temp-mempool.h" #include "imem.h" #include "strfuncs.h"
--- a/src/lib/temp-mempool.c Wed Oct 09 19:45:47 2002 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,476 +0,0 @@ -/* - temp-mempool.c : Memory pool for temporary memory allocations - - Copyright (c) 2001-2002 Timo Sirainen - - Permission is hereby granted, free of charge, to any person obtaining - a copy of this software and associated documentation files (the - "Software"), to deal in the Software without restriction, including - without limitation the rights to use, copy, modify, merge, publish, - distribute, sublicense, and/or sell copies of the Software, and to - permit persons to whom the Software is furnished to do so, subject to - the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - -#include "lib.h" -#include "temp-mempool.h" - -#include <stdlib.h> - -/* #define TEMP_POOL_DISABLE */ - -#ifndef TEMP_POOL_DISABLE - -/* max. number of bytes to even try to allocate. This is done just to avoid - allocating less memory than was actually requested because of integer - overflows. */ -#define MAX_ALLOC_SIZE SSIZE_T_MAX - -/* Initial pool size - this should be kept in a size that doesn't exceed - in a normal use to keep it fast. */ -#define INITIAL_POOL_SIZE (1024*32) - -typedef struct _MemBlock MemBlock; -typedef struct _MemBlockStack MemBlockStack; - -struct _MemBlock { - MemBlock *next; - - size_t size, left; - /* unsigned char data[]; */ -}; - -#define SIZEOF_MEMBLOCK MEM_ALIGN(sizeof(MemBlock)) - -#define MEM_BLOCK_DATA(block) \ - ((char *) (block) + SIZEOF_MEMBLOCK) - -/* current_stack contains last t_push()ed blocks. After that new - MemBlockStack is created and it's ->prev is set to current_stack. */ -#define MEM_LIST_BLOCK_COUNT 16 - -struct _MemBlockStack { - MemBlockStack *prev; - - MemBlock *block[MEM_LIST_BLOCK_COUNT]; - int block_space_used[MEM_LIST_BLOCK_COUNT]; - int last_alloc_size; -}; - -static int stack_pos; /* next free position in current_stack->block[] */ -static MemBlockStack *current_stack; /* current stack position */ -static MemBlockStack *unused_stack_list; /* unused stack blocks */ - -static MemBlock *current_block; /* block currently used for allocation */ -static MemBlock *unused_block; /* largest unused block is kept here */ - -static MemBlock *last_buffer_block; -static size_t last_buffer_size; - -int t_push(void) -{ - MemBlockStack *stack; - - if (stack_pos == MEM_LIST_BLOCK_COUNT) { - /* stack list full */ - stack_pos = 0; - if (unused_stack_list == NULL) { - /* allocate new stack */ - stack = calloc(sizeof(MemBlockStack), 1); - if (stack == NULL) - i_panic("t_push(): Out of memory"); - } else { - /* use existing unused stack */ - stack = unused_stack_list; - unused_stack_list = unused_stack_list->prev; - } - - stack->prev = current_stack; - current_stack = stack; - } - - /* mark our current position */ - current_stack->block[stack_pos] = current_block; - current_stack->block_space_used[stack_pos] = current_block->left; - current_stack->last_alloc_size = 0; - - return stack_pos++; -} - -static void free_blocks(MemBlock *block) -{ - /* free all the blocks, except if any of them is bigger than - unused_block, replace it */ - while (block != NULL) { - if (unused_block == NULL || block->size > unused_block->size) { - free(unused_block); - unused_block = block; - } else { - free(block); - } - - block = block->next; - } -} - -int t_pop(void) -{ - MemBlockStack *stack; - - if (stack_pos == 0) - i_panic("t_pop() called with empty stack"); - stack_pos--; - - /* update the current block */ - current_block = current_stack->block[stack_pos]; - current_block->left = current_stack->block_space_used[stack_pos]; - - if (current_block->next != NULL) { - /* free unused blocks */ - free_blocks(current_block->next); - current_block->next = NULL; - } - - if (stack_pos == 0) { - /* stack block is now unused, add it to unused list */ - stack_pos = MEM_LIST_BLOCK_COUNT; - - stack = current_stack; - current_stack = stack->prev; - - stack->prev = unused_stack_list; - unused_stack_list = stack; - } - - return stack_pos; -} - -static MemBlock *mem_block_alloc(size_t min_size) -{ - MemBlock *block; - size_t prev_size, alloc_size; - - prev_size = current_block == NULL ? 0 : current_block->size; - alloc_size = nearest_power(prev_size + min_size); - - block = malloc(SIZEOF_MEMBLOCK + alloc_size); - if (block == NULL) { - i_panic("mem_block_alloc(): " - "Out of memory when allocating %"PRIuSIZE_T" bytes", - alloc_size + SIZEOF_MEMBLOCK); - } - block->size = alloc_size; - block->next = NULL; - - return block; -} - -static void *t_malloc_real(size_t size, int permanent) -{ - MemBlock *block; - void *ret; - - if (size == 0) - return NULL; - - if (size > MAX_ALLOC_SIZE) - i_panic("Trying to allocate too much memory"); - - /* reset t_buffer_get() mark - not really needed but makes it easier - to notice if t_malloc() is called between t_buffer_get() and - t_buffer_alloc() */ - last_buffer_block = NULL; - - /* allocate only aligned amount of memory so alignment comes - always properly */ - size = MEM_ALIGN(size); - - /* used for t_try_grow() */ - current_stack->last_alloc_size = size; - - if (current_block->left >= size) { - /* enough space in current block, use it */ - ret = MEM_BLOCK_DATA(current_block) + - (current_block->size - current_block->left); - if (permanent) - current_block->left -= size; - return ret; - } - - /* current block is full, see if we can use the unused_block */ - if (unused_block != NULL && unused_block->size >= size) { - block = unused_block; - unused_block = NULL; - } else { - block = mem_block_alloc(size); - } - - block->left = block->size; - if (permanent) - block->left -= size; - block->next = NULL; - - current_block->next = block; - current_block = block; - - return MEM_BLOCK_DATA(current_block); -} - -void *t_malloc(size_t size) -{ - return t_malloc_real(size, TRUE); -} - -void *t_malloc0(size_t size) -{ - void *mem; - - mem = t_malloc_real(size, TRUE); - memset(mem, 0, size); - return mem; -} - -int t_try_grow(void *mem, size_t size) -{ - size_t grow_size; - - /* see if we want to grow the memory we allocated last */ - if (MEM_BLOCK_DATA(current_block) + - (current_block->size - current_block->left - - current_stack->last_alloc_size) == mem) { - /* yeah, see if we have space to grow */ - size = MEM_ALIGN(size); - grow_size = size - current_stack->last_alloc_size; - if (current_block->left >= grow_size) { - /* just shrink the available size */ - current_block->left -= grow_size; - current_stack->last_alloc_size = size; - return TRUE; - } - } - - return FALSE; -} - -void *t_buffer_get(size_t size) -{ - void *ret; - - ret = t_malloc_real(size, FALSE); - - last_buffer_size = size; - last_buffer_block = current_block; - return ret; -} - -void *t_buffer_reget(void *buffer, size_t size) -{ - size_t old_size; - void *new_buffer; - - old_size = last_buffer_size; - if (size <= old_size) - return buffer; - - new_buffer = t_buffer_get(size); - if (new_buffer != buffer) - memcpy(new_buffer, buffer, old_size); - - return new_buffer; -} - -void t_buffer_alloc(size_t size) -{ - i_assert(last_buffer_block != NULL); - i_assert(last_buffer_size >= size); - i_assert(current_block->left >= size); - - /* we've already reserved the space, now we just mark it used */ - t_malloc_real(size, TRUE); -} - -void temp_mempool_init(void) -{ - current_block = mem_block_alloc(INITIAL_POOL_SIZE); - current_block->left = current_block->size; - current_block->next = NULL; - - current_stack = NULL; - unused_stack_list = NULL; - stack_pos = MEM_LIST_BLOCK_COUNT; - - t_push(); - - last_buffer_block = NULL; - last_buffer_size = 0; -} - -void temp_mempool_deinit(void) -{ - t_pop(); - - if (stack_pos != MEM_LIST_BLOCK_COUNT) - i_panic("Missing t_pop() call"); - - while (unused_stack_list != NULL) { - MemBlockStack *stack = unused_stack_list; - unused_stack_list = unused_stack_list->prev; - - free(stack); - } - - free(current_block); - free(unused_block); -} - -#else - -typedef struct _Stack Stack; -typedef struct _Alloc Alloc; - -struct _Stack { - Stack *next; - Alloc *allocs; -}; - -struct _Alloc { - Alloc *next; - void *mem; -}; - -static int stack_counter; -static Stack *current_stack; -static void *buffer_mem; - -int t_push(void) -{ - Stack *stack; - - stack = malloc(sizeof(Stack)); - stack->allocs = NULL; - - stack->next = current_stack; - current_stack = stack; - return stack_counter++; -} - -int t_pop(void) -{ - Stack *stack; - Alloc *alloc; - - stack = current_stack; - current_stack = stack->next; - - while (stack->allocs != NULL) { - alloc = stack->allocs; - stack->allocs = alloc->next; - - free(alloc->mem); - free(alloc); - } - - free(stack); - return --stack_counter; -} - -static void add_alloc(void *mem) -{ - Alloc *alloc; - - alloc = malloc(sizeof(Alloc)); - alloc->mem = mem; - alloc->next = current_stack->allocs; - current_stack->allocs = alloc; - - if (buffer_mem != NULL) { - free(buffer_mem); - buffer_mem = NULL; - } -} - -void *t_malloc(size_t size) -{ - void *mem; - - mem = malloc(size); - add_alloc(mem); - return mem; -} - -void *t_malloc0(size_t size) -{ - void *mem; - - mem = calloc(size, 1); - add_alloc(mem); - return mem; -} - -int t_try_grow(void *mem, size_t size) -{ - void *new_mem; - - new_mem = realloc(mem, size); - if (new_mem == mem) - return TRUE; - - free(new_mem); - return FALSE; -} - -void *t_buffer_get(size_t size) -{ - buffer_mem = realloc(buffer_mem, size); - return buffer_mem; -} - -void *t_buffer_reget(void *buffer, size_t size) -{ - i_assert(buffer == buffer_mem); - - buffer_mem = realloc(buffer_mem, size); - return buffer_mem; -} - -void t_buffer_alloc(size_t size) -{ - void *mem; - - i_assert(buffer_mem != NULL); - - mem = buffer_mem; - buffer_mem = NULL; - - add_alloc(mem); -} - -void temp_mempool_init(void) -{ - stack_counter = 0; - current_stack = NULL; - buffer_mem = NULL; - - t_push(); -} - -void temp_mempool_deinit(void) -{ - t_pop(); - - if (stack_counter != 0) - i_panic("Missing t_pop() call"); -} - -#endif
--- a/src/lib/temp-mempool.h Wed Oct 09 19:45:47 2002 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,51 +0,0 @@ -#ifndef __TEMP_MEMPOOL_H -#define __TEMP_MEMPOOL_H - -/* temporary memory allocations. All t_..() allocations between - t_push() and t_pop() are free'd after t_pop() is called. */ -int t_push(void); -int t_pop(void); - -/* WARNING: Be careful when using this functions, it's too easy to - accidentally save the returned value somewhere permanently. - - You probably should never use this function directly, rather - create functions that return 'const xxx*' types and use t_malloc() - internally in them. This is a lot safer, since usually compiler - warns if you try to place them in xxx*. See strfuncs.c for examples. */ -void *t_malloc(size_t size); -void *t_malloc0(size_t size); - -/* Try growing allocated memory. Returns TRUE if successful. */ -int t_try_grow(void *mem, size_t size); - -#define t_new(type, count) \ - ((type *) t_malloc0((unsigned) sizeof(type) * (count))) - -/* Returns pointer to temporary buffer you can use. The buffer will be - invalid as soon as t_malloc() or t_pop() is called! - - If you wish to grow the buffer, you must give the full wanted size - in the size parameter. If return value doesn't point to the same value - as last time, you need to memcpy() the data from old buffer the this - new one (or do some other trickery). See t_buffer_reget(). */ -#define t_buffer_get_type(type, size) \ - t_buffer_get(sizeof(type) * (size)) -void *t_buffer_get(size_t size); - -/* Grow the buffer, memcpy()ing the memory to new location if needed. */ -#define t_buffer_reget_type(buffer, type, size) \ - t_buffer_reget(buffer, sizeof(type) * (size)) -void *t_buffer_reget(void *buffer, size_t size); - -/* Make given t_buffer_get()ed buffer permanent. Note that size MUST be - less or equal than the size you gave with last t_buffer_get() or the - result will be undefined. */ -#define t_buffer_alloc_type(type, size) \ - t_buffer_alloc(sizeof(type) * (size)) -void t_buffer_alloc(size_t size); - -void temp_mempool_init(void); -void temp_mempool_deinit(void); - -#endif