data-stack.c revision c438c40313ec4ccd348e5c3d199c2927cdce8906
e59faf65ce864fe95dc00f5d52b8323cdbd0608aTimo Sirainen/* Copyright (c) 2002-2008 Dovecot authors, see the included COPYING file */
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen/* @UNSAFE: whole file */
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen#include "lib.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "data-stack.h"
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
137ea7ca34005345aa2304a940149b7f3774d727Timo Sirainen#include <stdlib.h>
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen#ifdef HAVE_GC_GC_H
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen# include <gc/gc.h>
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen#elif defined (HAVE_GC_H)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen# include <gc.h>
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen#endif
137ea7ca34005345aa2304a940149b7f3774d727Timo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen/* Initial stack size - this should be kept in a size that doesn't exceed
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen in a normal use to avoid extra malloc()ing. */
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen#ifdef DEBUG
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen# define INITIAL_STACK_SIZE (1024*10)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen#else
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen# define INITIAL_STACK_SIZE (1024*32)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen#endif
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen#ifdef DEBUG
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen# define CLEAR_CHR 0xde
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen# define SENTRY_COUNT (4*8)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen#else
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen# define CLEAR_CHR 0
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen#endif
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenstruct stack_block {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen struct stack_block *next;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen size_t size, left, lowwater;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen /* unsigned char data[]; */
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen};
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen#define SIZEOF_MEMBLOCK MEM_ALIGN(sizeof(struct stack_block))
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen#define STACK_BLOCK_DATA(block) \
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen ((unsigned char *) (block) + SIZEOF_MEMBLOCK)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen/* current_frame_block contains last t_push()ed frames. After that new
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen stack_frame_block is created and it's ->prev is set to
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen current_frame_block. */
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen#define BLOCK_FRAME_COUNT 32
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenstruct stack_frame_block {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen struct stack_frame_block *prev;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen struct stack_block *block[BLOCK_FRAME_COUNT];
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen size_t block_space_used[BLOCK_FRAME_COUNT];
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen size_t last_alloc_size[BLOCK_FRAME_COUNT];
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen};
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenunsigned int data_stack_frame = 0;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenstatic int frame_pos = BLOCK_FRAME_COUNT-1; /* in current_frame_block */
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenstatic struct stack_frame_block *current_frame_block;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenstatic struct stack_frame_block *unused_frame_blocks;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenstatic struct stack_block *current_block; /* block now used for allocation */
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenstatic struct stack_block *unused_block; /* largest unused block is kept here */
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenstatic struct stack_block *last_buffer_block;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenstatic size_t last_buffer_size;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenstatic bool clean_after_pop = FALSE;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenstatic bool outofmem = FALSE;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenunion {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen struct stack_block block;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen unsigned char data[128];
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen} outofmem_area;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenstatic void data_stack_last_buffer_reset(void)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen{
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (last_buffer_block != NULL) {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen#ifdef DEBUG
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen const unsigned char *p;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen unsigned int i;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen p = STACK_BLOCK_DATA(current_block) +
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen (current_block->size - current_block->left) +
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen MEM_ALIGN(sizeof(size_t)) + MEM_ALIGN(last_buffer_size);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen#endif
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen /* reset t_buffer_get() mark - not really needed but makes it
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen easier to notice if t_malloc()/t_push()/t_pop() is called
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen between t_buffer_get() and t_buffer_alloc().
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen do this before we get to i_panic() to avoid recursive
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen panics. */
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen last_buffer_block = NULL;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen#ifdef DEBUG
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen for (i = 0; i < SENTRY_COUNT; i++) {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (p[i] != CLEAR_CHR)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen i_panic("t_buffer_get(): buffer overflow");
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen }
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen#endif
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen }
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen}
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenunsigned int t_push(void)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen{
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen struct stack_frame_block *frame_block;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen frame_pos++;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (frame_pos == BLOCK_FRAME_COUNT) {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen /* frame block full */
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (data_stack_frame == 0) {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen /* kludgy, but allow this before initialization */
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen frame_pos = 0;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen data_stack_init();
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen return t_push();
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen }
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen frame_pos = 0;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (unused_frame_blocks == NULL) {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen /* allocate new block */
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen#ifndef USE_GC
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen frame_block = calloc(sizeof(*frame_block), 1);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen#else
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen frame_block = GC_malloc(sizeof(*frame_block));
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen#endif
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (frame_block == NULL) {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen i_fatal_status(FATAL_OUTOFMEM,
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen "t_push(): Out of memory");
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen }
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen } else {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen /* use existing unused frame_block */
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen frame_block = unused_frame_blocks;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen unused_frame_blocks = unused_frame_blocks->prev;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen }
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen frame_block->prev = current_frame_block;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen current_frame_block = frame_block;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen }
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen data_stack_last_buffer_reset();
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen /* mark our current position */
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen current_frame_block->block[frame_pos] = current_block;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen current_frame_block->block_space_used[frame_pos] = current_block->left;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen current_frame_block->last_alloc_size[frame_pos] = 0;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen return data_stack_frame++;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen}
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenstatic void free_blocks(struct stack_block *block)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen{
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen struct stack_block *next;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen /* free all the blocks, except if any of them is bigger than
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen unused_block, replace it */
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen while (block != NULL) {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen next = block->next;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (clean_after_pop)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen memset(STACK_BLOCK_DATA(block), CLEAR_CHR, block->size);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (unused_block == NULL || block->size > unused_block->size) {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen#ifndef USE_GC
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen free(unused_block);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen#endif
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen unused_block = block;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen } else {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen#ifndef USE_GC
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen free(block);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen#endif
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen }
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen block = next;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#ifdef DEBUG
16f816d3f3c32ae3351834253f52ddd0212bcbf3Timo Sirainenstatic void t_pop_verify(void)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct stack_block *block;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen unsigned char *p;
4dc8837ab37c1a606add1067e21ed868754db4e3Timo Sirainen size_t pos, max_pos, used_size, alloc_size;
8e5fedd9ada47735be8ac0f8af2a66e8528bd776Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen block = current_frame_block->block[frame_pos];
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen pos = block->size - current_frame_block->block_space_used[frame_pos];
e8bdf1be00aec45d0c6dd72ad9c8be02a3dfc778Timo Sirainen while (block != NULL) {
5fb3bff645380804c9db2510940c41db6b8fdb01Timo Sirainen used_size = block->size - block->left;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen p = STACK_BLOCK_DATA(block);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen while (pos < used_size) {
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen alloc_size = *(size_t *)(p + pos);
2abfef71398a61e5ed97c23a1ceb71461933ccb8Timo Sirainen if (used_size - pos < alloc_size)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_panic("data stack: saved alloc size broken");
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen pos += MEM_ALIGN(sizeof(alloc_size));
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen max_pos = pos + MEM_ALIGN(alloc_size + SENTRY_COUNT);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen pos += alloc_size;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen for (; pos < max_pos; pos++) {
b66a7b7ab0db2c9ad425912d3f21a36fcf76d876Timo Sirainen if (p[pos] != CLEAR_CHR)
b66a7b7ab0db2c9ad425912d3f21a36fcf76d876Timo Sirainen i_panic("data stack: buffer overflow");
b66a7b7ab0db2c9ad425912d3f21a36fcf76d876Timo Sirainen }
b66a7b7ab0db2c9ad425912d3f21a36fcf76d876Timo Sirainen }
b66a7b7ab0db2c9ad425912d3f21a36fcf76d876Timo Sirainen
b66a7b7ab0db2c9ad425912d3f21a36fcf76d876Timo Sirainen /* we could verify here that the rest of the buffer contains
b66a7b7ab0db2c9ad425912d3f21a36fcf76d876Timo Sirainen CLEAR_CHRs, but it would slow us down a bit too much. */
b66a7b7ab0db2c9ad425912d3f21a36fcf76d876Timo Sirainen max_pos = block->size - pos < SENTRY_COUNT ?
cbf7138b49d32fce0645dc6523fbb42cc07cb2faTimo Sirainen block->size - pos : SENTRY_COUNT;
cbf7138b49d32fce0645dc6523fbb42cc07cb2faTimo Sirainen for (; pos < max_pos; pos++) {
b9b48aaaebf6f72dfab567cda073cde8a7b26598Timo Sirainen if (p[pos] != CLEAR_CHR)
b9b48aaaebf6f72dfab567cda073cde8a7b26598Timo Sirainen i_panic("data stack: buffer overflow");
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen }
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen block = block->next;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen pos = 0;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#endif
e30b748edcef3cf3352478bf21fa8f785bdc773aTimo Sirainen
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainenunsigned int t_pop(void)
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen{
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen struct stack_frame_block *frame_block;
1582b4d531679849bba299c17b6ec9402b7df67dTimo Sirainen int popped_frame_pos;
1582b4d531679849bba299c17b6ec9402b7df67dTimo Sirainen
1582b4d531679849bba299c17b6ec9402b7df67dTimo Sirainen if (unlikely(frame_pos < 0))
1582b4d531679849bba299c17b6ec9402b7df67dTimo Sirainen i_panic("t_pop() called with empty stack");
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#ifdef DEBUG
9c7e765845357342923e16351181091028e5930fTimo Sirainen t_pop_verify();
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen#endif
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen data_stack_last_buffer_reset();
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen
6bf1543bb7af03324c04e8f9ac8e430f395989aeTimo Sirainen /* update the current block */
6bf1543bb7af03324c04e8f9ac8e430f395989aeTimo Sirainen current_block = current_frame_block->block[frame_pos];
6bf1543bb7af03324c04e8f9ac8e430f395989aeTimo Sirainen if (clean_after_pop) {
6bf1543bb7af03324c04e8f9ac8e430f395989aeTimo Sirainen size_t pos, used_size;
6bf1543bb7af03324c04e8f9ac8e430f395989aeTimo Sirainen
6bf1543bb7af03324c04e8f9ac8e430f395989aeTimo Sirainen pos = current_block->size -
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen current_frame_block->block_space_used[frame_pos];
b00787191c3c31bebb939c3d00f1fcdb67356c69Timo Sirainen used_size = current_block->size - current_block->lowwater;
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen memset(STACK_BLOCK_DATA(current_block) + pos, CLEAR_CHR,
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen used_size - pos);
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen }
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen current_block->left = current_frame_block->block_space_used[frame_pos];
d22301419109ed4a38351715e6760011421dadecTimo Sirainen current_block->lowwater = current_block->left;
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen
ee116df08d0fdab703483e18fe8076b2ef9fd9d7Timo Sirainen if (current_block->next != NULL) {
ee116df08d0fdab703483e18fe8076b2ef9fd9d7Timo Sirainen /* free unused blocks */
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen free_blocks(current_block->next);
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen current_block->next = NULL;
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen }
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen popped_frame_pos = frame_pos;
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen if (frame_pos > 0)
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen frame_pos--;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen else {
e30b748edcef3cf3352478bf21fa8f785bdc773aTimo Sirainen /* frame block is now unused, add it to unused list */
e30b748edcef3cf3352478bf21fa8f785bdc773aTimo Sirainen frame_pos = BLOCK_FRAME_COUNT-1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen frame_block = current_frame_block;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen current_frame_block = frame_block->prev;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen frame_block->prev = unused_frame_blocks;
d22301419109ed4a38351715e6760011421dadecTimo Sirainen unused_frame_blocks = frame_block;
d22301419109ed4a38351715e6760011421dadecTimo Sirainen }
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen return --data_stack_frame;
e30b748edcef3cf3352478bf21fa8f785bdc773aTimo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid t_pop_check(unsigned int *id)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (unlikely(t_pop() != *id))
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_panic("Leaked t_pop() call");
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen *id = 0;
aa62d8779ce53900c2f09bf2ff6fa790bc9f6a89Timo Sirainen}
ea9fd7f876643e985946a2563140359064819b8eTimo Sirainen
ea9fd7f876643e985946a2563140359064819b8eTimo Sirainenstatic struct stack_block *mem_block_alloc(size_t min_size)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct stack_block *block;
4b43f50117630aa12b3cfd0cbd05ae22ba27fec1Timo Sirainen size_t prev_size, alloc_size;
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen prev_size = current_block == NULL ? 0 : current_block->size;
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen alloc_size = nearest_power(prev_size + min_size);
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen#ifndef USE_GC
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen block = malloc(SIZEOF_MEMBLOCK + alloc_size);
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen#else
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen block = GC_malloc(SIZEOF_MEMBLOCK + alloc_size);
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen#endif
4b43f50117630aa12b3cfd0cbd05ae22ba27fec1Timo Sirainen if (unlikely(block == NULL)) {
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen if (outofmem) {
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen if (min_size > outofmem_area.block.left)
4b43f50117630aa12b3cfd0cbd05ae22ba27fec1Timo Sirainen abort();
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen return &outofmem_area.block;
4b43f50117630aa12b3cfd0cbd05ae22ba27fec1Timo Sirainen }
4b43f50117630aa12b3cfd0cbd05ae22ba27fec1Timo Sirainen outofmem = TRUE;
4b43f50117630aa12b3cfd0cbd05ae22ba27fec1Timo Sirainen i_panic("data stack: Out of memory when allocating %"
4b43f50117630aa12b3cfd0cbd05ae22ba27fec1Timo Sirainen PRIuSIZE_T" bytes", alloc_size + SIZEOF_MEMBLOCK);
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen }
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen block->size = alloc_size;
cbf7138b49d32fce0645dc6523fbb42cc07cb2faTimo Sirainen block->left = 0;
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen block->lowwater = block->size;
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen block->next = NULL;
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen#ifdef DEBUG
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen memset(STACK_BLOCK_DATA(block), CLEAR_CHR, alloc_size);
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen#endif
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen return block;
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen}
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainenstatic void *t_malloc_real(size_t size, bool permanent)
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen{
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen struct stack_block *block;
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen void *ret;
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen size_t alloc_size;
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen#ifdef DEBUG
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen bool warn = FALSE;
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen#endif
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen if (unlikely(size == 0 || size > SSIZE_T_MAX))
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen i_panic("Trying to allocate %"PRIuSIZE_T" bytes", size);
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen if (unlikely(data_stack_frame == 0)) {
4b43f50117630aa12b3cfd0cbd05ae22ba27fec1Timo Sirainen /* kludgy, but allow this before initialization */
4b43f50117630aa12b3cfd0cbd05ae22ba27fec1Timo Sirainen data_stack_init();
4b43f50117630aa12b3cfd0cbd05ae22ba27fec1Timo Sirainen }
538303a216166f3526c0ae9658c9978275cfa100Timo Sirainen
d22301419109ed4a38351715e6760011421dadecTimo Sirainen data_stack_last_buffer_reset();
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen /* allocate only aligned amount of memory so alignment comes
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen always properly */
a87e5f15283e057c7dc26dd9db7b616268c95ca7Timo Sirainen#ifndef DEBUG
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen alloc_size = MEM_ALIGN(size);
c93cd163f9c1d4b0ca29f49cbfdbf474caeef5bfTimo Sirainen#else
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen alloc_size = MEM_ALIGN(sizeof(size)) + MEM_ALIGN(size + SENTRY_COUNT);
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen#endif
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen /* used for t_try_realloc() */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen current_frame_block->last_alloc_size[frame_pos] = alloc_size;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
8e5fedd9ada47735be8ac0f8af2a66e8528bd776Timo Sirainen if (current_block->left >= alloc_size) {
8e5fedd9ada47735be8ac0f8af2a66e8528bd776Timo Sirainen /* enough space in current block, use it */
8e5fedd9ada47735be8ac0f8af2a66e8528bd776Timo Sirainen ret = STACK_BLOCK_DATA(current_block) +
d22301419109ed4a38351715e6760011421dadecTimo Sirainen (current_block->size - current_block->left);
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen if (current_block->left - alloc_size <
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen current_block->lowwater) {
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen current_block->lowwater =
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen current_block->left - alloc_size;
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen }
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen if (permanent)
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen current_block->left -= alloc_size;
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen } else {
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen /* current block is full, see if we can use the unused_block */
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen if (unused_block != NULL && unused_block->size >= alloc_size) {
8e5fedd9ada47735be8ac0f8af2a66e8528bd776Timo Sirainen block = unused_block;
8e5fedd9ada47735be8ac0f8af2a66e8528bd776Timo Sirainen unused_block = NULL;
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen } else {
8e5fedd9ada47735be8ac0f8af2a66e8528bd776Timo Sirainen block = mem_block_alloc(alloc_size);
8e5fedd9ada47735be8ac0f8af2a66e8528bd776Timo Sirainen#ifdef DEBUG
8e5fedd9ada47735be8ac0f8af2a66e8528bd776Timo Sirainen warn = TRUE;
38df0cacce475112991e60d796f8f2105c616f01Timo Sirainen#endif
38df0cacce475112991e60d796f8f2105c616f01Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
ccc895c0358108d2304239063e940b7d75f364abTimo Sirainen block->left = block->size;
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen if (block->left - alloc_size < block->lowwater)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen block->lowwater = block->left - alloc_size;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (permanent)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen block->left -= alloc_size;
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen block->next = NULL;
b66a7b7ab0db2c9ad425912d3f21a36fcf76d876Timo Sirainen
b60baf6af900a610b2b2ddd24a46f8311acc3386Timo Sirainen current_block->next = block;
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen current_block = block;
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen
8bb360f9e5de1c25e4f875205bb06e8bf15dae14Timo Sirainen ret = STACK_BLOCK_DATA(current_block);
d3eff05aaa4c2bc0a7580ee87a54f6693f4a8241Timo Sirainen#ifdef DEBUG
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen if (warn) {
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen /* warn after allocation, so if i_warning() wants to
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen allocate more memory we don't go to infinite loop */
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen i_warning("Growing data stack with: %"PRIuSIZE_T,
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen block->size);
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen }
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen#endif
4dc8837ab37c1a606add1067e21ed868754db4e3Timo Sirainen }
4dc8837ab37c1a606add1067e21ed868754db4e3Timo Sirainen#ifdef DEBUG
4dc8837ab37c1a606add1067e21ed868754db4e3Timo Sirainen memcpy(ret, &size, sizeof(size));
4dc8837ab37c1a606add1067e21ed868754db4e3Timo Sirainen ret = PTR_OFFSET(ret, MEM_ALIGN(sizeof(size)));
4dc8837ab37c1a606add1067e21ed868754db4e3Timo Sirainen /* make sure the sentry contains CLEAR_CHRs. it might not if we
4dc8837ab37c1a606add1067e21ed868754db4e3Timo Sirainen had used t_buffer_get(). */
4dc8837ab37c1a606add1067e21ed868754db4e3Timo Sirainen memset(PTR_OFFSET(ret, size), CLEAR_CHR,
8e5fedd9ada47735be8ac0f8af2a66e8528bd776Timo Sirainen MEM_ALIGN(size + SENTRY_COUNT) - size);
8e5fedd9ada47735be8ac0f8af2a66e8528bd776Timo Sirainen#endif
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen return ret;
d22301419109ed4a38351715e6760011421dadecTimo Sirainen}
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainenvoid *t_malloc(size_t size)
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen{
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen return t_malloc_real(size, TRUE);
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen}
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainenvoid *t_malloc0(size_t size)
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen{
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen void *mem;
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen mem = t_malloc_real(size, TRUE);
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen memset(mem, 0, size);
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen return mem;
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenbool t_try_realloc(void *mem, size_t size)
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen{
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen size_t last_alloc_size;
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen if (unlikely(size == 0 || size > SSIZE_T_MAX))
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen i_panic("Trying to allocate %"PRIuSIZE_T" bytes", size);
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen
b3bb775c6b735a7f6021dea799601fbfdb656e58Timo Sirainen last_alloc_size = current_frame_block->last_alloc_size[frame_pos];
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen /* see if we're trying to grow the memory we allocated last */
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen if (STACK_BLOCK_DATA(current_block) +
b3bb775c6b735a7f6021dea799601fbfdb656e58Timo Sirainen (current_block->size - current_block->left -
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen last_alloc_size) == mem) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* yeah, see if we have space to grow */
d77c309fccbc6a7594f8cb08fb01009fa613c568Timo Sirainen size = MEM_ALIGN(size);
d77c309fccbc6a7594f8cb08fb01009fa613c568Timo Sirainen if (current_block->left >= size - last_alloc_size) {
d77c309fccbc6a7594f8cb08fb01009fa613c568Timo Sirainen /* just shrink the available size */
d22301419109ed4a38351715e6760011421dadecTimo Sirainen current_block->left -= size - last_alloc_size;
d22301419109ed4a38351715e6760011421dadecTimo Sirainen current_frame_block->last_alloc_size[frame_pos] = size;
ced118ac5caf6fe83d34339c2c65c63b2aa768acTimo Sirainen return TRUE;
41264e5dcef8335ab7ba422822b3ab518b7a327aTimo Sirainen }
41264e5dcef8335ab7ba422822b3ab518b7a327aTimo Sirainen }
41264e5dcef8335ab7ba422822b3ab518b7a327aTimo Sirainen
7bd6001d84ecc1792ddfd54fe8efa63c509d90b1Timo Sirainen return FALSE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainensize_t t_get_bytes_available(void)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
9a56220167d02bbcb66a81b7553f4eb4da939945Timo Sirainen return current_block->left;
9a56220167d02bbcb66a81b7553f4eb4da939945Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid *t_buffer_get(size_t size)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen void *ret;
8754bb7a1f24705ffa5434f9e10d57e0b3b88d6eTimo Sirainen
8754bb7a1f24705ffa5434f9e10d57e0b3b88d6eTimo Sirainen ret = t_malloc_real(size, FALSE);
8754bb7a1f24705ffa5434f9e10d57e0b3b88d6eTimo Sirainen
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen last_buffer_size = size;
d67f54632110cfb6aafe2d7cd1f99b031c0b208aTimo Sirainen last_buffer_block = current_block;
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen return ret;
b60baf6af900a610b2b2ddd24a46f8311acc3386Timo Sirainen}
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainenvoid *t_buffer_reget(void *buffer, size_t size)
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen{
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen size_t old_size;
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen void *new_buffer;
b60baf6af900a610b2b2ddd24a46f8311acc3386Timo Sirainen
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen old_size = last_buffer_size;
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen if (size <= old_size)
9a099a65160987349f441c82ab0e38f32b747adbTimo Sirainen return buffer;
9a099a65160987349f441c82ab0e38f32b747adbTimo Sirainen
9a099a65160987349f441c82ab0e38f32b747adbTimo Sirainen new_buffer = t_buffer_get(size);
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen if (new_buffer != buffer)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen memcpy(new_buffer, buffer, old_size);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen return new_buffer;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid t_buffer_alloc(size_t size)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
b60baf6af900a610b2b2ddd24a46f8311acc3386Timo Sirainen i_assert(last_buffer_block != NULL);
b60baf6af900a610b2b2ddd24a46f8311acc3386Timo Sirainen i_assert(last_buffer_size >= size);
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen i_assert(current_block->left >= size);
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen /* we've already reserved the space, now we just mark it used */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen t_malloc_real(size, TRUE);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
b60baf6af900a610b2b2ddd24a46f8311acc3386Timo Sirainen
b60baf6af900a610b2b2ddd24a46f8311acc3386Timo Sirainenvoid t_buffer_alloc_last_full(void)
b60baf6af900a610b2b2ddd24a46f8311acc3386Timo Sirainen{
d3eff05aaa4c2bc0a7580ee87a54f6693f4a8241Timo Sirainen if (last_buffer_block != NULL)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen t_malloc_real(last_buffer_size, TRUE);
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid data_stack_set_clean_after_pop(bool enable ATTR_UNUSED)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#ifndef DEBUG
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen clean_after_pop = enable;
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen#endif
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen}
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainenvoid data_stack_init(void)
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#ifdef DEBUG
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen clean_after_pop = TRUE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#endif
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (data_stack_frame == 0) {
38df0cacce475112991e60d796f8f2105c616f01Timo Sirainen data_stack_frame = 1;
38df0cacce475112991e60d796f8f2105c616f01Timo Sirainen
38df0cacce475112991e60d796f8f2105c616f01Timo Sirainen outofmem_area.block.size = outofmem_area.block.left =
38df0cacce475112991e60d796f8f2105c616f01Timo Sirainen sizeof(outofmem_area) - sizeof(outofmem_area.block);
38df0cacce475112991e60d796f8f2105c616f01Timo Sirainen
eae1d6e75713d3d658908ac39b719992e2f8a456Timo Sirainen current_block = mem_block_alloc(INITIAL_STACK_SIZE);
38df0cacce475112991e60d796f8f2105c616f01Timo Sirainen current_block->left = current_block->size;
38df0cacce475112991e60d796f8f2105c616f01Timo Sirainen current_block->next = NULL;
41264e5dcef8335ab7ba422822b3ab518b7a327aTimo Sirainen
41264e5dcef8335ab7ba422822b3ab518b7a327aTimo Sirainen current_frame_block = NULL;
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen unused_frame_blocks = NULL;
41264e5dcef8335ab7ba422822b3ab518b7a327aTimo Sirainen frame_pos = BLOCK_FRAME_COUNT-1;
41264e5dcef8335ab7ba422822b3ab518b7a327aTimo Sirainen
41264e5dcef8335ab7ba422822b3ab518b7a327aTimo Sirainen last_buffer_block = NULL;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen last_buffer_size = 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen
41264e5dcef8335ab7ba422822b3ab518b7a327aTimo Sirainen t_push();
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
d77c309fccbc6a7594f8cb08fb01009fa613c568Timo Sirainen
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainenvoid data_stack_deinit(void)
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen{
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen t_pop();
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen if (frame_pos != BLOCK_FRAME_COUNT-1)
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen i_panic("Missing t_pop() call");
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen#ifndef USE_GC
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen while (unused_frame_blocks != NULL) {
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen struct stack_frame_block *frame_block = unused_frame_blocks;
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen unused_frame_blocks = unused_frame_blocks->prev;
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen free(frame_block);
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen }
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen free(current_block);
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen free(unused_block);
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen#endif
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen unused_frame_blocks = NULL;
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen current_block = NULL;
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen unused_block = NULL;
38df0cacce475112991e60d796f8f2105c616f01Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen