Added concept of child stacks to SilcStack. Supports now full
authorPekka Riikonen <priikone@silcnet.org>
Tue, 3 Jul 2007 19:47:12 +0000 (19:47 +0000)
committerPekka Riikonen <priikone@silcnet.org>
Tue, 3 Jul 2007 19:47:12 +0000 (19:47 +0000)
memory pool system.

lib/silcutil/silcstack.c
lib/silcutil/silcstack.h
lib/silcutil/silcstack_i.h
lib/silcutil/tests/Makefile.am
lib/silcutil/tests/test_silcstack.c

index 85575e51fbaa1bfc7e5689ed67b21e634bcf7960..7f179eb4e5c4ca5c7a516985f1ac20445ee5072a 100644 (file)
 
 */
 
-/* #define SILC_STACK_DEBUG 1 */
-
 #include "silc.h"
 
-/* Allocate the stack */
+/************************** Types and definitions ***************************/
+
+/* The SilcStack context */
+struct SilcStackStruct {
+  SilcStack parent;                          /* Parent stack */
+  SilcList stacks;                           /* List of stacks */
+  SilcStackDataEntry stack;                  /* Allocated stack blocks */
+  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;
+  SilcUInt32 sbytes_malloc;
+  SilcUInt32 snum_errors;
+#endif /* SILC_DIST_INPLACE */
+};
+
+/************************ Static utility functions **************************/
+
+/* Compute stack block index for the `size'. */
 
-SilcStack silc_stack_alloc(SilcUInt32 stack_size)
+static SilcUInt32 silc_stack_get_index(SilcUInt32 size, SilcUInt32 *ret_bsize)
 {
-  SilcStack stack;
+  SilcUInt32 bsize, si;
 
-  stack = silc_calloc(1, sizeof(*stack));
-  if (!stack)
-    return NULL;
+  if (size < SILC_STACK_DEFAULT_SIZE)
+    size = SILC_STACK_DEFAULT_SIZE;
+  si = 0;
+  bsize = SILC_STACK_DEFAULT_SIZE;
+  while (bsize < size) {
+    bsize <<= 1;
+    si++;
+  }
 
-  stack->frames = silc_calloc(SILC_STACK_DEFAULT_NUM,
-                             sizeof(*stack->frames));
-  if (!stack->frames) {
-    silc_free(stack);
-    return NULL;
+  *ret_bsize = bsize;
+
+  return si;
+}
+
+/* Get stack from `stack' or allocate new one. */
+
+static SilcStackDataEntry silc_stack_ref_stack(SilcStack stack,
+                                              SilcUInt32 size,
+                                              SilcUInt32 *ret_si,
+                                              SilcUInt32 *ret_bsize)
+{
+  SilcStackDataEntry e;
+  SilcUInt32 si, bsize;
+
+  /* Get stack block index and block size for requested size */
+  si = silc_stack_get_index(size, &bsize);
+  *ret_si = si;
+  *ret_bsize = bsize;
+
+  SILC_ST_DEBUG(("Get stack block, si %d, size %lu", si, bsize));
+
+  /* Get stack that has block that can house our size requirement. */
+  silc_list_start(stack->stacks);
+  while ((e = silc_list_get(stack->stacks))) {
+    if (!e->data[si])
+      continue;
+
+    silc_list_del(stack->stacks, e);
+    SILC_ST_DEBUG(("Got stack blocks %p from stack %p", e->data, stack));
+    return e;
   }
-  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]),
-                                                stack->alignment));
-  if (!stack->stack[0]) {
-    silc_free(stack->frames);
-    silc_free(stack);
+
+  SILC_ST_DEBUG(("Allocate new stack blocks"));
+
+  /* Allocate new stack blocks */
+  e = silc_calloc(1, sizeof(*e));
+  if (!e)
+    return NULL;
+  e->data[si] = silc_malloc(bsize + SILC_STACK_ALIGN(sizeof(*e->data[0]),
+                                                    stack->alignment));
+  if (!e->data[si]) {
+    silc_free(e);
     return NULL;
   }
-  stack->stack[0]->bytes_left = stack->stack_size;
+  e->data[si]->bytes_left = bsize;
+  e->si = si;
+  e->bsize = bsize;
+
+  SILC_ST_DEBUG(("Got stack blocks %p from stack %p", e->data, stack));
+  return e;
+}
+
+/* Return the `data' back to the `stack'. */
+
+static void silc_stack_unref_stack(SilcStack stack, SilcStackDataEntry e)
+{
+  int i;
+
+  SILC_LOG_DEBUG(("Release stack blocks %p to stack %p, si %d",
+                 e->data, stack, e->si));
+
+  /* Release all blocks from allocations */
+  for (i = e->si; i < SILC_STACK_BLOCK_NUM; i++) {
+    if (!e->data[i])
+      continue;
+    if (!i)
+      e->data[i]->bytes_left = e->bsize;
+    else
+      e->data[i]->bytes_left = SILC_STACK_BLOCK_SIZE(stack, i);
+  }
+
+  silc_list_add(stack->stacks, e);
+}
+
+/* Allocate memory from a specific stack block */
+
+static void *silc_stack_alloc_block(SilcStack stack, SilcStackDataEntry e,
+                                   SilcUInt32 items, SilcUInt32 size)
+{
+  SilcUInt32 asize;
+  void *ptr;
+
+  /* Get pointer and consume the stack block */
+  asize = SILC_STACK_ALIGN(items * size, stack->alignment);
+  ptr = SILC_STACK_DATA_EXT(e->data, e->si, e->bsize, stack->alignment);
+  e->data[e->si]->bytes_left -= asize;
+  memset(ptr, 0, items * size);
+
+  return ptr;
+}
+
+/***************************** SilcStack API ********************************/
+
+/* Allocate the stack */
+
+SilcStack silc_stack_alloc(SilcUInt32 stack_size, SilcStack parent)
+{
+  SilcStack stack;
+  SilcStackDataEntry e;
+  SilcUInt32 si = 0, bsize = 0;
+
+  stack_size = stack_size ? stack_size : SILC_STACK_DEFAULT_SIZE;
+  if (stack_size < SILC_STACK_DEFAULT_SIZE)
+    stack_size = SILC_STACK_DEFAULT_SIZE;
+
+  if (parent) {
+    /* Get stack from parent.  The stack itself is allocated from the
+       parent. */
+    e = silc_stack_ref_stack(parent, stack_size, &si, &bsize);
+    if (!e)
+      return NULL;
+
+    /* Allocate stack from the parent */
+    stack = silc_stack_alloc_block(parent, e, 1, sizeof(*stack));
+    if (!stack) {
+      silc_stack_unref_stack(parent, e);
+      return NULL;
+    }
+
+    stack->parent = parent;
+    stack->stack_size = stack_size;
+    stack->alignment = SILC_STACK_DEFAULT_ALIGN;
+    silc_list_init(stack->stacks, struct SilcStackDataEntryStruct, next);
+
+    /* Allocate stack frames from the parent */
+    stack->frames = silc_stack_alloc_block(parent, e, SILC_STACK_BLOCK_NUM,
+                                          sizeof(*stack->frames));
+    if (!stack->frames) {
+      silc_stack_unref_stack(parent, e);
+      return NULL;
+    }
+
+    /* Set the initial stack */
+    stack->stack = e;
+  } else {
+    /* Dynamically allocate new stack */
+    stack = silc_calloc(1, sizeof(*stack));
+    if (!stack)
+      return NULL;
+
+    stack->stack_size = stack_size;
+    stack->alignment = SILC_STACK_DEFAULT_ALIGN;
+    silc_list_init(stack->stacks, struct SilcStackDataEntryStruct, next);
+
+    /* Create initial stack */
+    stack->stack = silc_calloc(1, sizeof(*stack->stack));
+    if (!stack->stack) {
+      silc_free(stack);
+      return NULL;
+    }
+    stack->stack->data[0] =
+      silc_malloc(stack->stack_size +
+                 SILC_STACK_ALIGN(sizeof(*stack->stack->data[0]),
+                                  stack->alignment));
+    if (!stack->stack->data[0]) {
+      silc_free(stack->stack);
+      silc_free(stack);
+      return NULL;
+    }
+    stack->stack->data[0]->bytes_left = stack->stack_size;
+    stack->stack->si = 0;
+    stack->stack->bsize = stack->stack_size;
+
+    /* Allocate stack frames from the stack itself */
+    stack->frames = silc_stack_alloc_block(stack, stack->stack,
+                                          SILC_STACK_DEFAULT_NUM,
+                                          sizeof(*stack->frames));
+    if (!stack->frames) {
+      silc_free(stack->stack->data[0]);
+      silc_free(stack->stack);
+      silc_free(stack);
+      return NULL;
+    }
+  }
 
   /* Use the allocated stack in first stack frame */
   stack->frame = &stack->frames[0];
   stack->frame->prev = NULL;
   stack->frame->bytes_used = stack->stack_size;
   stack->frame->sp = 1;
-  stack->frame->si = 0;
+  stack->frame->si = si;
+
+  SILC_LOG_DEBUG(("New stack %p, size %d bytes", stack, stack->stack_size));
 
   return stack;
 }
@@ -65,12 +247,31 @@ SilcStack silc_stack_alloc(SilcUInt32 stack_size)
 
 void silc_stack_free(SilcStack stack)
 {
+  SilcStackDataEntry e;
   int i;
 
-  silc_free(stack->frames);
-  for (i = 0; i < SILC_STACK_BLOCK_NUM; i++)
-    silc_free(stack->stack[i]);
-  silc_free(stack);
+  SILC_LOG_DEBUG(("Free stack %p", stack));
+
+  if (!stack->parent) {
+    silc_list_start(stack->stacks);
+    while ((e = silc_list_get(stack->stacks))) {
+      for (i = 0; i < SILC_STACK_BLOCK_NUM; i++)
+       silc_free(e->data[i]);
+      silc_free(e);
+    }
+
+    for (i = 0; i < SILC_STACK_BLOCK_NUM; i++)
+      silc_free(stack->stack->data[i]);
+    silc_free(stack->stack);
+
+    silc_free(stack);
+  } else {
+    silc_list_start(stack->stacks);
+    while ((e = silc_list_get(stack->stacks)))
+      silc_stack_unref_stack(stack->parent, e);
+
+    silc_stack_unref_stack(stack->parent, stack->stack);
+  }
 }
 
 /* Push to next stack frame */
@@ -81,23 +282,11 @@ SilcUInt32 silc_stack_push(SilcStack stack, SilcStackFrame *frame)
     return 0;
 
   if (!frame) {
-    /* See if all frames are in use, and allocate SILC_STACK_DEFAULT_NUM
-       many new frames if needed. */
     if (stack->frame->sp >= SILC_STACK_ALIGN(stack->frame->sp,
                                             SILC_STACK_DEFAULT_NUM)) {
-      int i = stack->frame->sp;
-      SILC_LOG_DEBUG(("Allocating more stack frames"));
-      frame = silc_realloc(stack->frames,
-                          SILC_STACK_ALIGN(i + 1, SILC_STACK_DEFAULT_NUM) *
-                          sizeof(*stack->frames));
-      if (!frame)
-       return 0;
-      stack->frames = frame;
-      stack->frame = &stack->frames[i - 1];
-
-      /* The prev pointers may become invalid in silc_realloc() */
-      for (i = 1; i < stack->frame->sp; i++)
-       stack->frames[i].prev = &stack->frames[i - 1];
+      SILC_LOG_DEBUG(("SilcStack %p running out of frames, cannot push",
+                     stack));
+      return stack->frame->sp;
     }
 
     frame = &stack->frames[stack->frame->sp];
@@ -107,7 +296,7 @@ SilcUInt32 silc_stack_push(SilcStack stack, SilcStackFrame *frame)
   frame->prev = stack->frame;
   frame->sp = stack->frame->sp + 1;
   frame->si = stack->frame->si;
-  frame->bytes_used = stack->stack[frame->si]->bytes_left;
+  frame->bytes_used = stack->stack->data[frame->si]->bytes_left;
   stack->frame = frame;
 
   SILC_ST_DEBUG(("Push %p: sp %d -> %d, si %d", stack, frame->prev->sp,
@@ -122,18 +311,17 @@ SilcUInt32 silc_stack_pop(SilcStack stack)
 {
   SilcUInt32 si;
 
-  if (!stack)
+  if (!stack || !stack->frame->prev)
     return 0;
 
   /* Pop */
-  assert(stack->frame->prev);
   si = stack->frame->si;
   while (si > stack->frame->prev->si) {
-    if (stack->stack[si])
-      stack->stack[si]->bytes_left = SILC_STACK_BLOCK_SIZE(stack, si);
+    if (stack->stack->data[si])
+      stack->stack->data[si]->bytes_left = SILC_STACK_BLOCK_SIZE(stack, si);
     si--;
   }
-  stack->stack[si]->bytes_left = stack->frame->bytes_used;
+  stack->stack->data[si]->bytes_left = stack->frame->bytes_used;
   stack->frame = stack->frame->prev;
 
   SILC_ST_DEBUG(("Pop %p: sp %d -> %d, si %d", stack, stack->frame->sp + 1,
@@ -172,10 +360,10 @@ void *silc_stack_malloc(SilcStack stack, SilcUInt32 size)
   bsize = SILC_STACK_BLOCK_SIZE(stack, si);
 
   /* See if there is space in the current stack block */
-  if (stack->stack[si]->bytes_left >= size) {
+  if (stack->stack->data[si]->bytes_left >= size) {
     /* Get pointer to the memory */
     ptr = SILC_STACK_DATA(stack, si, bsize);
-    stack->stack[si]->bytes_left -= size;
+    stack->stack->data[si]->bytes_left -= size;
     SILC_STACK_STAT(stack, bytes_malloc, size);
     return ptr;
   }
@@ -198,23 +386,24 @@ void *silc_stack_malloc(SilcStack stack, SilcUInt32 size)
   }
 
   /* Allocate the block if it doesn't exist yet */
-  if (!stack->stack[si]) {
+  if (!stack->stack->data[si]) {
     SILC_ST_DEBUG(("Allocating new stack block, %d bytes", bsize2));
-    stack->stack[si] = silc_malloc(bsize2 +
-                                  SILC_STACK_ALIGN(sizeof(**stack->stack),
-                                                   stack->alignment));
-    if (silc_unlikely(!stack->stack[si])) {
+    stack->stack->data[si] =
+      silc_malloc(bsize2 +
+                 SILC_STACK_ALIGN(sizeof(**stack->stack->data),
+                                  stack->alignment));
+    if (silc_unlikely(!stack->stack->data[si])) {
       SILC_STACK_STAT(stack, num_errors, 1);
       return NULL;
     }
-    stack->stack[si]->bytes_left = bsize2;
+    stack->stack->data[si]->bytes_left = bsize2;
   }
 
   /* Now return memory from this new block.  It is guaranteed that in this
      block there is enough space for this memory. */
-  assert(stack->stack[si]->bytes_left >= size);
+  assert(stack->stack->data[si]->bytes_left >= size);
   ptr = SILC_STACK_DATA(stack, si, bsize2);
-  stack->stack[si]->bytes_left -= size;
+  stack->stack->data[si]->bytes_left -= size;
   stack->frame->si = si;
   SILC_STACK_STAT(stack, bytes_malloc, size);
 
@@ -260,9 +449,9 @@ void *silc_stack_realloc(SilcStack stack, SilcUInt32 old_size,
   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), stack->alignment);
-  if (stack->stack[si]->bytes_left + old_size +
+  sptr = (unsigned char *)stack->stack->data[si] +
+    SILC_STACK_ALIGN(sizeof(**stack->stack->data), stack->alignment);
+  if (stack->stack->data[si]->bytes_left + old_size +
       ((unsigned char *)ptr - (unsigned char *)sptr) != bsize) {
     SILC_LOG_DEBUG(("Cannot reallocate"));
     SILC_STACK_STAT(stack, num_errors, 1);
@@ -270,10 +459,10 @@ 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) {
+  if (stack->stack->data[si]->bytes_left >= size) {
     /* It fits, so simply return the old pointer */
     size = SILC_STACK_ALIGN(size, stack->alignment);
-    stack->stack[si]->bytes_left -= (size - old_size);
+    stack->stack->data[si]->bytes_left -= (size - old_size);
     SILC_STACK_STAT(stack, bytes_malloc, (size - old_size));
     return ptr;
   }
@@ -303,11 +492,12 @@ SilcUInt32 silc_stack_get_alignment(SilcStack stack)
 
 void silc_stack_stats(SilcStack stack)
 {
+  SilcStackDataEntry e;
   SilcUInt32 stack_size = 0;
   int i, c = 0;
 
   for (i = 0; i < SILC_STACK_BLOCK_NUM; i++) {
-    if (!stack->stack[i])
+    if (!stack->stack->data[i])
       continue;
     stack_size += SILC_STACK_BLOCK_SIZE(stack, i);
     c++;
@@ -330,5 +520,22 @@ void silc_stack_stats(SilcStack stack)
          (unsigned int)SILC_STACK_ALIGN(stack->frame->sp,
                                         SILC_STACK_DEFAULT_NUM));
   fprintf(stdout, "  Number of blocks        : %u\n", c);
+  fprintf(stdout, "  Number of stacks        : %d\n",
+         silc_list_count(stack->stacks));
+
+  silc_list_start(stack->stacks);
+  while ((e = silc_list_get(stack->stacks))) {
+    stack_size = 0;
+    c = 0;
+    for (i = 0; i < SILC_STACK_BLOCK_NUM; i++) {
+      if (!e->data[i])
+       continue;
+      stack_size += e->data[i]->bytes_left;
+      c++;
+    }
+    fprintf(stdout, "\n  Size of stack           : %u\n",
+           (unsigned int)stack_size);
+    fprintf(stdout, "  Number of blocks        : %u\n", c);
+  }
 }
 #endif /* SILC_DIST_INPLACE */
index 46a00a2f1528e2f10e104acff4688c6c323b98ac..8003666f9d9ff12478914d0c681cdcb9f8f07179 100644 (file)
  * the stack.  This allows the caller to use special alignment for memory
  * allocations, if needed.
  *
+ * SilcStack is also a full featured memory pool which allows user to group
+ * together multiple stacks.  Child stacks may be created from a parent stack
+ * without consuming the parent stack.  When the child is freed, its memory
+ * is returned back to the parent and can be used again by other childs.
+ * It is also possible to create child stacks from another child stack.
+ *
  * 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:
@@ -44,7 +50,8 @@
  * 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
+ * silc_buffer_sstrformat, silc_buffer_senlarge, silc_mp_sinit,
+ * silc_dlist_sinit, silc_hash_table_alloc
  *
  * The SilcStack context is not thread-safe.  If the same SilcStack must be
  * used in multithreaded environment concurrency control must be employed.
@@ -81,13 +88,10 @@ typedef struct SilcStackStruct *SilcStack;
  *
  *    Static stack frame context that optionally can be used as stack
  *    frame in SilcStack.  By default silc_stack_push use pre-allocated
- *    stack frame (or allocates new one if all frames are reserved), but
- *    user may also use statically allocated SilcStackFrame instead.  This
- *    is recommended when using SilcStack in recursive routine and the
- *    recursion may become deep.  Using static frame assures that during
- *    recursion frames never run out and silc_stack_push never allocates
- *    any memory.  In other normal usage statically allocated SilcStackFrame
- *    is not needed, unless performance is critical.
+ *    stack frame, but user may also use statically allocated SilcStackFrame
+ *    instead.  This is recommended when using SilcStack in recursive routine
+ *    and the recursion may become deep.  Using static frame assures that
+ *    during recursion frames never run out.
  *
  ***/
 typedef struct SilcStackFrameStruct SilcStackFrame;
@@ -96,7 +100,7 @@ typedef struct SilcStackFrameStruct SilcStackFrame;
  *
  * SYNOPSIS
  *
- *    SilcStack silc_stack_alloc(SilcUInt32 stack_size);
+ *    SilcStack silc_stack_alloc(SilcUInt32 stack_size, SilcStack parent);
  *
  * DESCRIPTION
  *
@@ -104,11 +108,19 @@ typedef struct SilcStackFrameStruct SilcStackFrame;
  *    allocation by various routines.  Returns the pointer to the stack
  *    that must be freed with silc_stack_free function when it is not
  *    needed anymore.  If the `stack_size' is zero (0) by default a
- *    1 kilobyte (1024 bytes) stack is allocated.  If the `stack_size'
+ *    2 kilobytes (2048 bytes) stack is allocated.  If the `stack_size'
  *    is non-zero the byte value must be multiple by 8.
  *
+ *    If `parent' is non-NULL the created stack is a child of the `parent'
+ *    stack.  All of childs the memory is allocated from the `parent' and
+ *    will be returned back to the parent when the child is freed.  Note
+ *    that, even though child allocated memory from the parent, the parent's
+ *    stack is not consumed.
+ *
+ *    Returns NULL on error.
+ *
  ***/
-SilcStack silc_stack_alloc(SilcUInt32 stack_size);
+SilcStack silc_stack_alloc(SilcUInt32 stack_size, SilcStack parent);
 
 /****f* silcutil/SilcStackAPI/silc_stack_free
  *
@@ -121,6 +133,9 @@ SilcStack silc_stack_alloc(SilcUInt32 stack_size);
  *    Frees the data stack context.  The stack cannot be used anymore after
  *    this and all allocated memory are freed.
  *
+ *    If `stack' is a child stack, its memory is returned back to its
+ *    parent.
+ *
  ***/
 void silc_stack_free(SilcStack stack);
 
index c7ee81d83b7e5f09b6aeb9e8baf3d85b22a2808d..03bc8986dab2a37ca221d3e2cbd437d36ef9076c 100644 (file)
 #endif
 
 /* The default stack size when stack is created */
-#define SILC_STACK_DEFAULT_SIZE       1024
+#define SILC_STACK_DEFAULT_SIZE 2048
 
-/* Number of pre-allocated stack frames */
-#define SILC_STACK_DEFAULT_NUM        8
+/* Number of pre-allocated stack frames.  Frames are allocated from the
+   stack itself. */
+#define SILC_STACK_DEFAULT_NUM 32
 
 /* Default alignment */
-#define SILC_STACK_DEFAULT_ALIGN      sizeof(unsigned long)
+#define SILC_STACK_DEFAULT_ALIGN sizeof(unsigned long)
 
-/* Maximum allocation that can be made with SilcStack.  This is
-   SILC_STACK_DEFAULT_SIZE * (2 ^ (SILC_STACK_BLOCK_NUM - 1)). */
-#define SILC_STACK_MAX_ALLOC          0x02000000
-#define SILC_STACK_BLOCK_NUM          16
+/* Maximum allocation that can be made with SilcStack. */
+#define SILC_STACK_BLOCK_NUM 20
+#define SILC_STACK_MAX_ALLOC \
+  (SILC_STACK_DEFAULT_SIZE * (1L << (SILC_STACK_BLOCK_NUM - 1)) << 1)
 
 /* Stack frame data area */
 typedef struct SilcStackDataStruct {
@@ -44,6 +45,14 @@ typedef struct SilcStackDataStruct {
   /* Stack data area starts here */
 } *SilcStackData;
 
+/* Stack data entry */
+typedef struct SilcStackDataEntryStruct {
+  struct SilcStackDataEntryStruct *next;
+  SilcStackData data[SILC_STACK_BLOCK_NUM];   /* Blocks */
+  SilcUInt32 bsize;                          /* Default block size */
+  SilcUInt32 si;                             /* Default block index */
+} *SilcStackDataEntry;
+
 /* Stack frame */
 struct SilcStackFrameStruct {
   struct SilcStackFrameStruct *prev;          /* Pointer to previous frame */
@@ -52,21 +61,6 @@ struct SilcStackFrameStruct {
   unsigned int si : 5;                       /* Stack index */
 };
 
-/* The SilcStack context */
-struct SilcStackStruct {
-  SilcStackData stack[SILC_STACK_BLOCK_NUM];  /* Allocated stack blocks */
-  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;
-  SilcUInt32 sbytes_malloc;
-  SilcUInt32 snum_errors;
-#endif /* SILC_DIST_INPLACE */
-};
-
 /* Align the requested amount bytes.  The `align' defines the requested
    alignment. */
 #define SILC_STACK_ALIGN(bytes, align) (((bytes) + (align - 1)) & ~(align - 1))
@@ -74,13 +68,17 @@ struct SilcStackStruct {
 /* Computes the size of stack block si. */
 #define SILC_STACK_BLOCK_SIZE(stack, si)               \
   (((si) == 0) ? stack->stack_size :                   \
-   SILC_STACK_DEFAULT_SIZE * (1L << ((si) - 1)) << 1);
+   SILC_STACK_DEFAULT_SIZE * (1L << ((si) - 1)) << 1)
+
+/* Returns a pointer to the data in the given stack block */
+#define SILC_STACK_DATA_EXT(data, si, bsize, alignment)                        \
+  (((unsigned char *)(data)[si]) +                                     \
+   SILC_STACK_ALIGN(sizeof(**(data)), alignment) +                     \
+   ((bsize) - (data)[si]->bytes_left))
 
 /* 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), (stack)->alignment) +    \
-   ((bsize) - (stack)->stack[si]->bytes_left))
+  SILC_STACK_DATA_EXT((stack)->stack->data, si, bsize, (stack)->alignment)
 
 #ifdef SILC_DIST_INPLACE
 /* Statistics updating */
index 4b5513a9342caba6390402533d2dc94941b23bba..364092bbe2ef0da5c7de674af923c15cde7a3f7d 100644 (file)
@@ -20,7 +20,8 @@ AUTOMAKE_OPTIONS = 1.0 no-dependencies foreign
 bin_PROGRAMS =         test_silcstrutil test_silcstringprep test_silchashtable \
        test_silclist test_silcfsm test_silcasync test_silcschedule \
        test_silcnet test_silcstack test_silcmime test_silcfdstream \
-       test_silcatomic test_silcmutex test_silctime test_silcthread
+       test_silcatomic test_silcmutex test_silctime test_silcthread \
+       test_silcdll test_silcenv
 
 test_silcstrutil_SOURCES = test_silcstrutil.c
 test_silcstringprep_SOURCES = test_silcstringprep.c
@@ -37,6 +38,8 @@ test_silcatomic_SOURCES = test_silcatomic.c
 test_silcmutex_SOURCES = test_silcmutex.c
 test_silctime_SOURCES = test_silctime.c
 test_silcthread_SOURCES = test_silcthread.c
+test_silcdll_SOURCES = test_silcdll.c
+test_silcenv_SOURCES = test_silcenv.c
 
 LIBS = $(SILC_COMMON_LIBS)
 LDADD = -L.. -L../.. -lsilc
index e4f87064087ff7fb7cb4b9275a9c8e1957189eb9..f3c190912a8e12f48d018e17111de144aaceca2a 100644 (file)
@@ -7,7 +7,7 @@
 int main(int argc, char **argv)
 {
   SilcBool success = FALSE;
-  SilcStack stack;
+  SilcStack stack, child, child2;
   void *ptr, *ptr2;
   int i;
 
@@ -19,7 +19,7 @@ int main(int argc, char **argv)
   }
 
   SILC_LOG_DEBUG(("Allocating stack of default size (1024 bytes)"));
-  stack = silc_stack_alloc(0);
+  stack = silc_stack_alloc(0, NULL);
   if (!stack)
     goto err;
   silc_stack_stats(stack);
@@ -34,7 +34,7 @@ int main(int argc, char **argv)
   silc_stack_free(stack);
 
   SILC_LOG_DEBUG(("Allocating stack of default size (1024 bytes)"));
-  stack = silc_stack_alloc(0);
+  stack = silc_stack_alloc(0, NULL);
   if (!stack)
     goto err;
   silc_stack_stats(stack);
@@ -93,6 +93,82 @@ int main(int argc, char **argv)
   SILC_LOG_DEBUG(("Popping"));
   silc_stack_stats(stack);
 
+  SILC_LOG_DEBUG(("Creating child stack"));
+  child = silc_stack_alloc(8192, stack);
+  if (!child)
+    goto err;
+  SILC_LOG_DEBUG(("Pushing %d times", NUM_ALLS / 2));
+  for (i = 0; i < NUM_ALLS / 2; i++) {
+    if (!silc_stack_push(child, NULL))
+      goto err;
+    ptr2 = silc_smalloc(child, (i + 1) * 7);
+    if (!ptr2)
+      goto err;
+  }
+  silc_stack_stats(child);
+  SILC_LOG_DEBUG(("Popping %d times", NUM_ALLS / 2));
+  for (i = 0; i < NUM_ALLS / 2; i++)
+    silc_stack_pop(child);
+  silc_stack_stats(child);
+
+  SILC_LOG_DEBUG(("Pushing and reallocating %d times", NUM_ALLS / 10));
+  ptr2 = NULL;
+  if (!silc_stack_push(child, NULL))
+    goto err;
+  for (i = 0; i < NUM_ALLS / 10; i++) {
+    ptr2 = silc_srealloc(child, (i * 7), ptr2, (i + 1) * 7);
+    if (!ptr2)
+      goto err;
+  }
+  ptr = silc_smalloc(child, 100000);
+  silc_stack_stats(child);
+  silc_stack_pop(child);
+  SILC_LOG_DEBUG(("Popping"));
+  silc_stack_stats(child);
+  silc_stack_stats(stack);
+  silc_stack_free(child);
+  silc_stack_stats(stack);
+
+  SILC_LOG_DEBUG(("Creating child stack"));
+  child = silc_stack_alloc(8192, stack);
+  if (!child)
+    goto err;
+  SILC_LOG_DEBUG(("Pushing %d times", NUM_ALLS / 10));
+  for (i = 0; i < NUM_ALLS / 10; i++) {
+    if (!silc_stack_push(child, NULL))
+      goto err;
+    ptr2 = silc_smalloc(child, (i + 1) * 7);
+    if (!ptr2)
+      goto err;
+  }
+  silc_stack_stats(child);
+  SILC_LOG_DEBUG(("Popping %d times", NUM_ALLS / 10));
+  for (i = 0; i < NUM_ALLS / 10; i++)
+    silc_stack_pop(child);
+  silc_stack_stats(child);
+
+  SILC_LOG_DEBUG(("Pushing and reallocating %d times", NUM_ALLS / 10));
+  ptr2 = NULL;
+  if (!silc_stack_push(child, NULL))
+    goto err;
+  for (i = 0; i < NUM_ALLS / 10; i++) {
+    ptr2 = silc_srealloc(child, (i * 7), ptr2, (i + 1) * 7);
+    if (!ptr2)
+      goto err;
+  }
+  SILC_LOG_DEBUG(("Allocate child from child"));
+  child2 = silc_stack_alloc(0, child);
+  ptr = silc_smalloc(child2, 500000);
+  silc_stack_stats(child2);
+  silc_stack_free(child2);
+  silc_stack_stats(child);
+  silc_stack_pop(child);
+  SILC_LOG_DEBUG(("Popping"));
+  silc_stack_stats(child);
+  silc_stack_stats(stack);
+  silc_stack_free(child);
+  silc_stack_stats(stack);
+
   SILC_LOG_DEBUG(("Current alignment: %d", silc_stack_get_alignment(stack)));
   SILC_LOG_DEBUG(("Set alignemtn to 16"));
   silc_stack_set_alignment(stack, 16);