Removed unaligned memory allocation. Added getting/setting
authorPekka Riikonen <priikone@silcnet.org>
Mon, 2 Jul 2007 18:03:09 +0000 (18:03 +0000)
committerPekka Riikonen <priikone@silcnet.org>
Mon, 2 Jul 2007 18:03:09 +0000 (18:03 +0000)
memory alignment.  Moved silc_stack_malloc and silc_stack_realloc
from private API to public API.

lib/silcutil/silcstack.c
lib/silcutil/silcstack.h
lib/silcutil/silcstack_i.h
lib/silcutil/tests/test_silcthread.c

index fabef8ec7dbddc953b8ba2ff45cec6f7f4aafeca..85575e51fbaa1bfc7e5689ed67b21e634bcf7960 100644 (file)
@@ -4,7 +4,7 @@
 
   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
@@ -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",
index 3543de2af26bf3ac91a35d7bff5f38bb7994abfd..46a00a2f1528e2f10e104acff4688c6c323b98ac 100644 (file)
  * 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 */
index 33c90323a16828c8df404afb0de9cba8c52d4ccd..c7ee81d83b7e5f09b6aeb9e8baf3d85b22a2808d 100644 (file)
@@ -4,7 +4,7 @@
 
   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
@@ -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 */
index 920cb6f9de94cf72e578f10774e6c23fab6f9078..1b0245f82bef104dd4a4e45f03197cb59794f0fd 100644 (file)
@@ -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);