Inherit lock from parent when creating SilcStack child.
authorPekka Riikonen <priikone@silcnet.org>
Sun, 8 Jul 2007 17:26:58 +0000 (17:26 +0000)
committerPekka Riikonen <priikone@silcnet.org>
Sun, 8 Jul 2007 17:26:58 +0000 (17:26 +0000)
Check stack blocks from parent if child doesn't have them instead
of immediately allocating new one.  Added silc_stack_purge.

lib/silcutil/silcstack.c
lib/silcutil/silcstack.h
lib/silcutil/tests/test_silcstack.c

index ab5cd62b510a7f4ff32790b85af83fe7f59eabaf..d22fba3f5b1d544f1129cfb8ba1ee4d52ee786bf 100644 (file)
@@ -78,7 +78,8 @@ static SilcStackDataEntry silc_stack_ref_stack(SilcStack stack,
   *ret_si = si;
   *ret_bsize = bsize;
 
-  SILC_ST_DEBUG(("Get stack block, si %d, size %lu", si, bsize));
+  SILC_ST_DEBUG(("Get stack block, si %d, size %lu, stack %p",
+                si, bsize, stack));
 
   silc_mutex_lock(stack->lock);
 
@@ -94,6 +95,12 @@ static SilcStackDataEntry silc_stack_ref_stack(SilcStack stack,
     return e;
   }
 
+  /* If we are child, get block from parent */
+  if (stack->parent) {
+    silc_mutex_unlock(stack->lock);
+    return silc_stack_ref_stack(stack->parent, size, ret_si, ret_bsize);
+  }
+
   SILC_ST_DEBUG(("Allocate new stack blocks"));
 
   /* Allocate new stack blocks */
@@ -193,6 +200,7 @@ SilcStack silc_stack_alloc(SilcUInt32 stack_size, SilcStack parent)
     stack->alignment = SILC_STACK_DEFAULT_ALIGN;
     stack->oom_handler = parent->oom_handler;
     stack->oom_context = parent->oom_context;
+    stack->lock = parent->lock;
     silc_list_init(stack->stacks, struct SilcStackDataEntryStruct, next);
 
     /* Allocate stack frames from the parent */
@@ -244,10 +252,10 @@ SilcStack silc_stack_alloc(SilcUInt32 stack_size, SilcStack parent)
       silc_free(stack);
       return NULL;
     }
-  }
 
-  /* Allocate lock */
-  silc_mutex_alloc(&stack->lock);
+    /* Allocate lock */
+    silc_mutex_alloc(&stack->lock);
+  }
 
   /* Use the allocated stack in first stack frame */
   stack->frame = &stack->frames[0];
@@ -273,9 +281,6 @@ void silc_stack_free(SilcStack stack)
 
   SILC_LOG_DEBUG(("Free stack %p", stack));
 
-  if (stack->lock)
-    silc_mutex_free(stack->lock);
-
   if (!stack->parent) {
     silc_list_start(stack->stacks);
     while ((e = silc_list_get(stack->stacks))) {
@@ -288,6 +293,9 @@ void silc_stack_free(SilcStack stack)
       silc_free(stack->stack->data[i]);
     silc_free(stack->stack);
 
+    if (stack->lock)
+      silc_mutex_free(stack->lock);
+
     silc_free(stack);
   } else {
     /* Return all stack blocks to the parent */
@@ -530,6 +538,63 @@ SilcUInt32 silc_stack_get_alignment(SilcStack stack)
   return stack->alignment;
 }
 
+/* Purge stack */
+
+SilcBool silc_stack_purge(SilcStack stack)
+{
+  SilcStackDataEntry e;
+  SilcBool ret = FALSE;
+  int i;
+
+  SILC_LOG_DEBUG(("Purge stack %p", stack));
+
+  /* Go through the default stack */
+  for (i = SILC_STACK_BLOCK_NUM - 1; i > 3; i--) {
+    if (stack->stack->data[i] &&
+       stack->stack->data[i]->bytes_left == SILC_STACK_BLOCK_SIZE(stack, i)) {
+      SILC_LOG_DEBUG(("Purge %d bytes",
+                     SILC_STACK_BLOCK_SIZE(stack, i)));
+      silc_free(stack->stack->data[i]);
+      stack->stack->data[i] = NULL;
+      ret = TRUE;
+    }
+  }
+
+  silc_mutex_lock(stack->lock);
+
+  /* Remove one child stack */
+  if (silc_list_count(stack->stacks) > 2) {
+    silc_list_start(stack->stacks);
+    e = silc_list_get(stack->stacks);
+
+    SILC_LOG_DEBUG(("Remove stack blocks %p", e->data));
+    silc_list_del(stack->stacks, e);
+    ret = TRUE;
+
+    for (i = 0; i < SILC_STACK_BLOCK_NUM; i++)
+      silc_free(e->data[i]);
+    silc_free(e);
+  }
+
+  /* Go through the child stacks */
+  silc_list_start(stack->stacks);
+  while ((e = silc_list_get(stack->stacks))) {
+    for (i = SILC_STACK_BLOCK_NUM - 1; i > 3; i--) {
+      if (e->data[i]) {
+       SILC_LOG_DEBUG(("Purge %d bytes",
+                       SILC_STACK_BLOCK_SIZE(stack, i)));
+       silc_free(e->data[i]);
+       e->data[i] = NULL;
+       ret = TRUE;
+      }
+    }
+  }
+
+  silc_mutex_unlock(stack->lock);
+
+  return ret;
+}
+
 #ifdef SILC_DIST_INPLACE
 /* Statistics dumping. */
 
index c60cd7b7221b76b92855b49ffaa805c39edc6336..99d1c4ad3ddc0f5aca6dc5c60e5788c790c85aed 100644 (file)
@@ -365,6 +365,25 @@ void silc_stack_set_alignment(SilcStack stack, SilcUInt32 alignment);
  ***/
 SilcUInt32 silc_stack_get_alignment(SilcStack stack);
 
+/****f* silcutil/SilcStackAPI/silc_stack_purge
+ *
+ * SYNOPSIS
+ *
+ *    SilcBool silc_stack_purge(SilcStack stack);
+ *
+ * DESCRIPTION
+ *
+ *    Purges the `stack' from extra unused memory.  This purges only `stack'
+ *    and not its parent if `stack' is a child.  This purges only large
+ *    allocations.  The 1024, 2048, 4096 and 8192 bytes of allocations remain.
+ *    Call this multiple times to purge even more.  Returns FALSE when there
+ *    is no more to purge.  This does not purge memory blocks that currently
+ *    have allocations.  No memory allocations from the stack are lost, so
+ *    this is always safe to call.
+ *
+ ***/
+SilcBool silc_stack_purge(SilcStack stack);
+
 #include "silcstack_i.h"
 
 #endif /* SILCSTACK_H */
index f3c190912a8e12f48d018e17111de144aaceca2a..22474625d27804888001e0c6c5631f916fabec5e 100644 (file)
@@ -169,6 +169,10 @@ int main(int argc, char **argv)
   silc_stack_free(child);
   silc_stack_stats(stack);
 
+  SILC_LOG_DEBUG(("Purge stack"));
+  silc_stack_purge(stack);
+  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);