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