Author: Pekka Riikonen <priikone@silcnet.org>
- 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
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);
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)"));
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);
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;
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)"));
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"));
/* 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;
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. */
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",
* 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.
*
***/
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 */
Author: Pekka Riikonen <priikone@silcnet.org>
- 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
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;
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
#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 */
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++) {
compl, (void *)i + 1))
goto err;
}
- sleep(3);
+ sleep(4);
SILC_LOG_DEBUG(("Stop thread pool"));
silc_thread_pool_free(tp, TRUE);
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++) {
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);