From 0748bbe1a96d1bbf03f057b8a68ba2de00e91fba Mon Sep 17 00:00:00 2001 From: Pekka Riikonen Date: Mon, 2 Jul 2007 18:03:09 +0000 Subject: [PATCH] Removed unaligned memory allocation. Added getting/setting memory alignment. Moved silc_stack_malloc and silc_stack_realloc from private API to public API. --- lib/silcutil/silcstack.c | 55 ++++++++------ lib/silcutil/silcstack.h | 107 ++++++++++++++++++++++++--- lib/silcutil/silcstack_i.h | 25 ++----- lib/silcutil/tests/test_silcthread.c | 9 ++- 4 files changed, 141 insertions(+), 55 deletions(-) diff --git a/lib/silcutil/silcstack.c b/lib/silcutil/silcstack.c index fabef8ec..85575e51 100644 --- a/lib/silcutil/silcstack.c +++ b/lib/silcutil/silcstack.c @@ -4,7 +4,7 @@ Author: Pekka Riikonen - Copyright (C) 2003 - 2006 Pekka Riikonen + Copyright (C) 2003 - 2007 Pekka Riikonen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -37,12 +37,13 @@ SilcStack silc_stack_alloc(SilcUInt32 stack_size) silc_free(stack); return NULL; } + stack->alignment = SILC_STACK_DEFAULT_ALIGN; /* Create initial stack */ stack->stack_size = stack_size ? stack_size : SILC_STACK_DEFAULT_SIZE; stack->stack[0] = silc_malloc(stack->stack_size + SILC_STACK_ALIGN(sizeof(*stack->stack[0]), - SILC_STACK_DEFAULT_ALIGN)); + stack->alignment)); if (!stack->stack[0]) { silc_free(stack->frames); silc_free(stack); @@ -141,19 +142,16 @@ SilcUInt32 silc_stack_pop(SilcStack stack) return stack->frame->sp + 1; } -/* Allocate memory. If the `aligned' is FALSE this allocates unaligned - memory, otherwise memory is aligned. Returns pointer to the memory - or NULL on error. */ +/* Allocate memory. Returns pointer to the memory or NULL on error. */ -void *silc_stack_malloc(SilcStack stack, SilcUInt32 size, SilcBool aligned) +void *silc_stack_malloc(SilcStack stack, SilcUInt32 size) { void *ptr; SilcUInt32 bsize, bsize2; SilcUInt32 si = stack->frame->si; SILC_STACK_STAT(stack, num_malloc, 1); - SILC_ST_DEBUG(("Allocating %d bytes (%s) from %p", - size, aligned ? "align" : "not align", stack)); + SILC_ST_DEBUG(("Allocating %d bytes from %p", size, stack)); if (silc_unlikely(!size)) { SILC_LOG_ERROR(("Allocation by zero (0)")); @@ -167,8 +165,8 @@ void *silc_stack_malloc(SilcStack stack, SilcUInt32 size, SilcBool aligned) return NULL; } - /* Align properly if wanted */ - size = (aligned ? SILC_STACK_ALIGN(size, SILC_STACK_DEFAULT_ALIGN) : size); + /* Align properly */ + size = SILC_STACK_ALIGN(size, stack->alignment); /* Compute the size of current stack block */ bsize = SILC_STACK_BLOCK_SIZE(stack, si); @@ -204,7 +202,7 @@ void *silc_stack_malloc(SilcStack stack, SilcUInt32 size, SilcBool aligned) SILC_ST_DEBUG(("Allocating new stack block, %d bytes", bsize2)); stack->stack[si] = silc_malloc(bsize2 + SILC_STACK_ALIGN(sizeof(**stack->stack), - SILC_STACK_DEFAULT_ALIGN)); + stack->alignment)); if (silc_unlikely(!stack->stack[si])) { SILC_STACK_STAT(stack, num_errors, 1); return NULL; @@ -231,18 +229,17 @@ void *silc_stack_malloc(SilcStack stack, SilcUInt32 size, SilcBool aligned) the old memory remains intact. */ void *silc_stack_realloc(SilcStack stack, SilcUInt32 old_size, - void *ptr, SilcUInt32 size, SilcBool aligned) + void *ptr, SilcUInt32 size) { SilcUInt32 si = stack->frame->si; SilcUInt32 bsize; void *sptr; if (!ptr) - return silc_stack_malloc(stack, size, aligned); + return silc_stack_malloc(stack, size); SILC_STACK_STAT(stack, num_malloc, 1); - SILC_ST_DEBUG(("Reallocating %d bytes (%d) (%s) from %p", size, old_size, - aligned ? "align" : "not align", stack)); + SILC_ST_DEBUG(("Reallocating %d bytes (%d) from %p", size, old_size, stack)); if (silc_unlikely(!size || !old_size)) { SILC_LOG_ERROR(("Allocation by zero (0)")); @@ -256,17 +253,15 @@ void *silc_stack_realloc(SilcStack stack, SilcUInt32 old_size, return NULL; } - /* Align the old size if needed */ - old_size = (aligned ? - SILC_STACK_ALIGN(old_size, - SILC_STACK_DEFAULT_ALIGN) : old_size); + /* Align properly */ + old_size = SILC_STACK_ALIGN(old_size, stack->alignment); /* Compute the size of current stack block */ bsize = SILC_STACK_BLOCK_SIZE(stack, si); /* Check that `ptr' is last allocation */ sptr = (unsigned char *)stack->stack[si] + - SILC_STACK_ALIGN(sizeof(**stack->stack), SILC_STACK_DEFAULT_ALIGN); + SILC_STACK_ALIGN(sizeof(**stack->stack), stack->alignment); if (stack->stack[si]->bytes_left + old_size + ((unsigned char *)ptr - (unsigned char *)sptr) != bsize) { SILC_LOG_DEBUG(("Cannot reallocate")); @@ -277,8 +272,7 @@ void *silc_stack_realloc(SilcStack stack, SilcUInt32 old_size, /* Now check that the new size fits to this block */ if (stack->stack[si]->bytes_left >= size) { /* It fits, so simply return the old pointer */ - size = (aligned ? SILC_STACK_ALIGN(size, - SILC_STACK_DEFAULT_ALIGN) : size); + size = SILC_STACK_ALIGN(size, stack->alignment); stack->stack[si]->bytes_left -= (size - old_size); SILC_STACK_STAT(stack, bytes_malloc, (size - old_size)); return ptr; @@ -289,6 +283,21 @@ void *silc_stack_realloc(SilcStack stack, SilcUInt32 old_size, return NULL; } +/* Set default alignment */ + +void silc_stack_set_alignment(SilcStack stack, SilcUInt32 alignment) +{ + SILC_LOG_DEBUG(("Set stack %p alignment to %d bytes", stack, alignment)); + stack->alignment = alignment; +} + +/* Get default alignment */ + +SilcUInt32 silc_stack_get_alignment(SilcStack stack) +{ + return stack->alignment; +} + #ifdef SILC_DIST_INPLACE /* Statistics dumping. */ @@ -307,6 +316,8 @@ void silc_stack_stats(SilcStack stack) fprintf(stdout, "\nSilcStack %p statistics :\n\n", stack); fprintf(stdout, " Size of stack : %u\n", (unsigned int)stack_size); + fprintf(stdout, " Stack alignment : %d\n", + (int)stack->alignment); fprintf(stdout, " Number of allocs : %u\n", (unsigned int)stack->snum_malloc); fprintf(stdout, " Bytes allocated : %u\n", diff --git a/lib/silcutil/silcstack.h b/lib/silcutil/silcstack.h index 3543de2a..46a00a2f 100644 --- a/lib/silcutil/silcstack.h +++ b/lib/silcutil/silcstack.h @@ -22,31 +22,31 @@ * DESCRIPTION * * Implementation of data stack which can be used to allocate memory from - * the stack. Basicly SilcStack is a pre-allocated memory pool system + * the stack. Basically SilcStack is a pre-allocated memory pool system * which allows fast memory allocation for routines and applications that * frequently allocate small amounts of memory. Other advantage of this * system is that there are no memory leaks, as long as the stack is * freed eventually. Since the stack is usually allocated only once this * is not an issue. * - * SilcStack can be used to allocate both aligned and unaligned memory so - * it is suitable for allocating structures and is optimal for allocating - * strings and data buffers. SilcStack also supports stack pushing and - * popping allowing to push the stack, allocate memory and then pop it - * to free the allocated memory. The freeing does not actually do any - * real memory freeing so it is optimized for performance. + * SilcStack supports stack pushing and popping allowing to push the stack, + * allocate memory and then pop it to free the allocated memory. The freeing + * does not actually do any real memory freeing so it is optimized for + * performance. The memory alignment may also be specified by user for + * the stack. This allows the caller to use special alignment for memory + * allocations, if needed. * * A basic set of utility functions are provided for application that wish * to use the SilcStack as their primary memory allocation source. The * following functions support SilcStack: * - * silc_smalloc, silc_smalloc_ua, silc_scalloc, silc_srealloc, silc_smemdup, - * silc_sstrdup, silc_buffer_salloc, silc_buffer_salloc_size, + * silc_smalloc, silc_smalloc, silc_scalloc, silc_srealloc, silc_smemdup, + * silc_sfree, silc_sstrdup, silc_buffer_salloc, silc_buffer_salloc_size, * silc_buffer_srealloc, silc_buffer_srealloc_size, silc_buffer_scopy, * silc_buffer_sclone, silc_buffer_sformat, silc_buffer_sformat_vp, * silc_buffer_sstrformat, silc_buffer_senlarge, silc_mp_sinit * - * The data stack is not thread-safe. If the same stack context must be + * The SilcStack context is not thread-safe. If the same SilcStack must be * used in multithreaded environment concurrency control must be employed. * Each thread should allocate their own SilcStack. * @@ -223,6 +223,93 @@ SilcUInt32 silc_stack_push(SilcStack stack, SilcStackFrame *frame); ***/ SilcUInt32 silc_stack_pop(SilcStack stack); +/****f* silcutil/SilcStackAPI/silc_stack_malloc + * + * SYNOPSIS + * + * void *silc_stack_malloc(SilcStack stack, SilcUInt32 size); + * + * DESCRIPTION + * + * Low level memory allocation routine. Allocates memor block of size of + * `size' from the `stack'. The allocated memory is aligned so it can be + * used to allocate memory for structures, for example. Returns the + * allocated memory address or NULL if memory could not be allocated from + * the `stack'. + * + * NOTES + * + * This function should be used only if low level memory allocation with + * SilcStack is needed. Instead, silc_smalloc, could be used. + * + ***/ +void *silc_stack_malloc(SilcStack stack, SilcUInt32 size); + +/****f* silcutil/SilcStackAPI/silc_stack_realloc + * + * SYNOPSIS + * + * void *silc_stack_realloc(SilcStack stack, SilcUInt32 old_size, + * *void *ptr, SilcUInt32 size); + * + * DESCRIPTION + * + * Attempts to reallocate memory by changing the size of the `ptr' into + * `size'. This routine works only if the previous allocation to `stack' + * was `ptr'. If there is another memory allocation between allocating + * `ptr' and this call this routine will return NULL. NULL is also + * returned if the `size' does not fit into the current block. If NULL + * is returned the old memory remains intact. + * + * NOTES + * + * This function should be used only if low level memory allocation with + * SilcStack is needed. Instead, silc_srealloc, could be used. + * + ***/ +void *silc_stack_realloc(SilcStack stack, SilcUInt32 old_size, + void *ptr, SilcUInt32 size); + +/****f* silcutil/SilcStackAPI/silc_stack_set_alignment + * + * SYNOPSIS + * + * void silc_stack_set_alignment(SilcStack stack, SilcUInt32 alignment); + * + * DESCRIPTION + * + * Sets/changes the memory alignment in the `stack' to `alignment' which + * is the alignment in bytes. By default, the SilcStack will use alignment + * suited for the platform where it is used. This function can be used + * change this alignment, if such change is needed. You may check the + * current alignment by calling silc_stack_get_alignment. + * + * NOTES + * + * It is not mandatory to call this function. By default the SilcStack + * will always use alignment suited for the used platform. This function + * should be called only if the alignment needs to be changed to something + * other than the default on the used platform. For example, some + * hardware device, such as crypto accelerator, may require special + * alignment. + * + ***/ +void silc_stack_set_alignment(SilcStack stack, SilcUInt32 alignment); + +/****f* silcutil/SilcStackAPI/silc_stack_get_alignment + * + * SYNOPSIS + * + * SilcUInt32 silc_stack_get_alignment(SilcStack stack); + * + * DESCRIPTION + * + * Returns the memory alignment used with `stack'. The alignment is in + * bytes. + * + ***/ +SilcUInt32 silc_stack_get_alignment(SilcStack stack); + #include "silcstack_i.h" #endif /* SILCSTACK_H */ diff --git a/lib/silcutil/silcstack_i.h b/lib/silcutil/silcstack_i.h index 33c90323..c7ee81d8 100644 --- a/lib/silcutil/silcstack_i.h +++ b/lib/silcutil/silcstack_i.h @@ -4,7 +4,7 @@ Author: Pekka Riikonen - Copyright (C) 2003 - 2005 Pekka Riikonen + Copyright (C) 2003 - 2007 Pekka Riikonen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -58,6 +58,7 @@ struct SilcStackStruct { SilcStackFrame *frames; /* Allocated stack frames */ SilcStackFrame *frame; /* Current stack frame */ SilcUInt32 stack_size; /* Default stack size */ + SilcUInt32 alignment; /* Memory alignment */ #ifdef SILC_DIST_INPLACE /* Statistics */ SilcUInt32 snum_malloc; @@ -76,9 +77,9 @@ struct SilcStackStruct { SILC_STACK_DEFAULT_SIZE * (1L << ((si) - 1)) << 1); /* Returns a pointer to the data in the frame */ -#define SILC_STACK_DATA(stack, si, bsize) \ - (((unsigned char *)(stack)->stack[si]) + \ - SILC_STACK_ALIGN(sizeof(**(stack)->stack), SILC_STACK_DEFAULT_ALIGN) + \ +#define SILC_STACK_DATA(stack, si, bsize) \ + (((unsigned char *)(stack)->stack[si]) + \ + SILC_STACK_ALIGN(sizeof(**(stack)->stack), (stack)->alignment) + \ ((bsize) - (stack)->stack[si]->bytes_left)) #ifdef SILC_DIST_INPLACE @@ -88,23 +89,7 @@ struct SilcStackStruct { #else /* !SILC_DIST_INPLACE */ #define SILC_STACK_STAT(stack, stat, val) #define SILC_ST_DEBUG(fmt) -#endif /* SILC_DIST_INPLACE */ - -/* Allocate memory. If the `aligned' is FALSE this allocates unaligned - memory, otherwise memory is aligned. Returns pointer to the memory - or NULL on error. */ -void *silc_stack_malloc(SilcStack stack, SilcUInt32 size, SilcBool aligned); -/* Attempts to reallocate memory by changing the size of the `ptr' into - `size'. This routine works only if the previous allocation to `stack' - was `ptr'. If there is another memory allocation between allocating - `ptr' and this call this routine will return NULL. NULL is also returned - if the `size' does not fit into the current block. If NULL is returned - the old memory remains intact. */ -void *silc_stack_realloc(SilcStack stack, SilcUInt32 old_size, - void *ptr, SilcUInt32 size, SilcBool aligned); - -#ifdef SILC_DIST_INPLACE /* Prints statistics of the usage of SilcStack to stdout. */ void silc_stack_stats(SilcStack stack); #endif /* SILC_DIST_INPLACE */ diff --git a/lib/silcutil/tests/test_silcthread.c b/lib/silcutil/tests/test_silcthread.c index 920cb6f9..1b0245f8 100644 --- a/lib/silcutil/tests/test_silcthread.c +++ b/lib/silcutil/tests/test_silcthread.c @@ -43,7 +43,7 @@ int main(int argc, char **argv) SILC_LOG_DEBUG(("Allocate thread pool")); - tp = silc_thread_pool_alloc(NULL, 0, 2, TRUE); + tp = silc_thread_pool_alloc(NULL, 0, 2, FALSE); if (!tp) goto err; for (i = 0; i < 4; i++) { @@ -52,7 +52,7 @@ int main(int argc, char **argv) compl, (void *)i + 1)) goto err; } - sleep(3); + sleep(4); SILC_LOG_DEBUG(("Stop thread pool")); silc_thread_pool_free(tp, TRUE); @@ -74,7 +74,7 @@ int main(int argc, char **argv) silc_thread_pool_free(tp, TRUE); SILC_LOG_DEBUG(("Allocate thread pool")); - tp = silc_thread_pool_alloc(NULL, 8, 16, FALSE); + tp = silc_thread_pool_alloc(NULL, 3, 20, TRUE); if (!tp) goto err; for (i = 0; i < 8; i++) { @@ -86,6 +86,9 @@ int main(int argc, char **argv) if (!silc_thread_pool_run(tp, FALSE, schedule, func, (void *)0xff, compl, (void *)0xff)) goto err; + sleep(1); + + silc_thread_pool_purge(tp); silc_schedule(schedule); -- 2.24.0