]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Lib: Save/restore state for linpools
authorOndrej Zajicek (work) <santiago@crfreenet.org>
Tue, 12 Dec 2017 18:51:36 +0000 (19:51 +0100)
committerOndrej Zajicek (work) <santiago@crfreenet.org>
Tue, 12 Dec 2017 18:57:52 +0000 (19:57 +0100)
Also change linpool.current ptr to really point to thr current chunk.

lib/mempool.c
lib/resource.h

index 3cf9c2d3264b5c9d70f0e68514d5d739eb95c870..5a8f2a693e859cd4d99dd1bb3a35c71af508d14f 100644 (file)
@@ -11,7 +11,7 @@
  *
  * Linear memory pools are collections of memory blocks which
  * support very fast allocation of new blocks, but are able to free only
- * the whole collection at once.
+ * the whole collection at once (or in stack order).
  *
  * Example: Each configuration is described by a complex system of structures,
  * linked lists and function trees which are all allocated from a single linear
@@ -37,7 +37,7 @@ const int lp_chunk_size = sizeof(struct lp_chunk);
 struct linpool {
   resource r;
   byte *ptr, *end;
-  struct lp_chunk *first, *current, **plast;   /* Normal (reusable) chunks */
+  struct lp_chunk *first, *current;            /* Normal (reusable) chunks */
   struct lp_chunk *first_large;                        /* Large chunks */
   uint chunk_size, threshold, total, total_large;
 };
@@ -69,7 +69,6 @@ linpool
 *lp_new(pool *p, uint blk)
 {
   linpool *m = ralloc(p, &lp_class);
-  m->plast = &m->first;
   m->chunk_size = blk;
   m->threshold = 3*blk/4;
   return m;
@@ -114,22 +113,25 @@ lp_alloc(linpool *m, uint size)
        }
       else
        {
-         if (m->current)
+         if (m->current && m->current->next)
            {
              /* Still have free chunks from previous incarnation (before lp_flush()) */
-             c = m->current;
-             m->current = c->next;
+             c = m->current->next;
            }
          else
            {
              /* Need to allocate a new chunk */
              c = xmalloc(sizeof(struct lp_chunk) + m->chunk_size);
              m->total += m->chunk_size;
-             *m->plast = c;
-             m->plast = &c->next;
              c->next = NULL;
              c->size = m->chunk_size;
+
+             if (m->current)
+               m->current->next = c;
+             else
+               m->first = c;
            }
+         m->current = c;
          m->ptr = c->data + size;
          m->end = c->data + m->chunk_size;
        }
@@ -190,9 +192,11 @@ lp_flush(linpool *m)
 {
   struct lp_chunk *c;
 
-  /* Relink all normal chunks to free list and free all large chunks */
-  m->ptr = m->end = NULL;
-  m->current = m->first;
+  /* Move ptr to the first chunk and free all large chunks */
+  m->current = c = m->first;
+  m->ptr = c ? c->data : NULL;
+  m->end = c ? c->data + m->chunk_size : NULL;
+
   while (c = m->first_large)
     {
       m->first_large = c->next;
@@ -201,6 +205,49 @@ lp_flush(linpool *m)
   m->total_large = 0;
 }
 
+/**
+ * lp_save - save the state of a linear memory pool
+ * @m: linear memory pool
+ * @p: state buffer
+ *
+ * This function saves the state of a linear memory pool. Saved state can be
+ * used later to restore the pool (to free memory allocated since).
+ */
+void
+lp_save(linpool *m, lp_state *p)
+{
+  p->current = m->current;
+  p->large = m->first_large;
+  p->ptr = m->ptr;
+}
+
+/**
+ * lp_restore - restore the state of a linear memory pool
+ * @m: linear memory pool
+ * @p: saved state
+ *
+ * This function restores the state of a linear memory pool, freeing all memory
+ * allocated since the state was saved. Note that the function cannot un-free
+ * the memory, therefore the function also invalidates other states that were
+ * saved between (on the same pool).
+ */
+void
+lp_restore(linpool *m, lp_state *p)
+{
+  struct lp_chunk *c;
+
+  /* Move ptr to the saved pos and free all newer large chunks */
+  m->current = c = p->current;
+  m->ptr = p->ptr;
+  m->end = c ? c->data + m->chunk_size : NULL;
+
+  while ((c = m->first_large) && (c != p->large))
+    {
+      m->first_large = c->next;
+      xfree(c);
+    }
+}
+
 static void
 lp_free(resource *r)
 {
index 761c6adc1586dee6befab19269bf337f9cb4ce0f..d9d4bb8f10e265e07e107b174561fdc55f09a8bd 100644 (file)
@@ -59,11 +59,18 @@ void mb_free(void *);
 
 typedef struct linpool linpool;
 
+typedef struct lp_state {
+  void *current, *large;
+  byte *ptr;
+} lp_state;
+
 linpool *lp_new(pool *, unsigned blk);
 void *lp_alloc(linpool *, unsigned size);      /* Aligned */
 void *lp_allocu(linpool *, unsigned size);     /* Unaligned */
 void *lp_allocz(linpool *, unsigned size);     /* With clear */
 void lp_flush(linpool *);                      /* Free everything, but leave linpool */
+void lp_save(linpool *m, lp_state *p);         /* Save state */
+void lp_restore(linpool *m, lp_state *p);      /* Restore state */
 
 extern const int lp_chunk_size;
 #define LP_GAS             1024