]> git.ipfire.org Git - thirdparty/bird.git/blobdiff - lib/mempool.c
Merge branch 'bmp'
[thirdparty/bird.git] / lib / mempool.c
index 5a8f2a693e859cd4d99dd1bb3a35c71af508d14f..9d4404f7cab4c567c01e625324400ad35385f89b 100644 (file)
 
 struct lp_chunk {
   struct lp_chunk *next;
-  uint size;
   uintptr_t data_align[0];
   byte data[0];
 };
 
-const int lp_chunk_size = sizeof(struct lp_chunk);
+#define LP_DATA_SIZE   (page_size - OFFSETOF(struct lp_chunk, data))
 
 struct linpool {
   resource r;
   byte *ptr, *end;
   struct lp_chunk *first, *current;            /* Normal (reusable) chunks */
   struct lp_chunk *first_large;                        /* Large chunks */
-  uint chunk_size, threshold, total, total_large;
+  uint total, total_large;
 };
 
+_Thread_local linpool *tmp_linpool;
+
 static void lp_free(resource *);
 static void lp_dump(resource *);
 static resource *lp_lookup(resource *, unsigned long);
-static size_t lp_memsize(resource *r);
+static struct resmem lp_memsize(resource *r);
 
 static struct resclass lp_class = {
   "LinPool",
@@ -59,19 +60,14 @@ static struct resclass lp_class = {
 /**
  * lp_new - create a new linear memory pool
  * @p: pool
- * @blk: block size
  *
  * lp_new() creates a new linear memory pool resource inside the pool @p.
- * The linear pool consists of a list of memory chunks of size at least
- * @blk.
+ * The linear pool consists of a list of memory chunks of page size.
  */
 linpool
-*lp_new(pool *p, uint blk)
+*lp_new(pool *p)
 {
-  linpool *m = ralloc(p, &lp_class);
-  m->chunk_size = blk;
-  m->threshold = 3*blk/4;
-  return m;
+  return ralloc(p, &lp_class);
 }
 
 /**
@@ -102,14 +98,13 @@ lp_alloc(linpool *m, uint size)
   else
     {
       struct lp_chunk *c;
-      if (size >= m->threshold)
+      if (size > LP_DATA_SIZE)
        {
          /* Too large => allocate large chunk */
          c = xmalloc(sizeof(struct lp_chunk) + size);
          m->total_large += size;
          c->next = m->first_large;
          m->first_large = c;
-         c->size = size;
        }
       else
        {
@@ -121,10 +116,10 @@ lp_alloc(linpool *m, uint size)
          else
            {
              /* Need to allocate a new chunk */
-             c = xmalloc(sizeof(struct lp_chunk) + m->chunk_size);
-             m->total += m->chunk_size;
+             c = alloc_page();
+
+             m->total += LP_DATA_SIZE;
              c->next = NULL;
-             c->size = m->chunk_size;
 
              if (m->current)
                m->current->next = c;
@@ -133,7 +128,7 @@ lp_alloc(linpool *m, uint size)
            }
          m->current = c;
          m->ptr = c->data + size;
-         m->end = c->data + m->chunk_size;
+         m->end = c->data + LP_DATA_SIZE;
        }
       return c->data;
     }
@@ -192,10 +187,17 @@ lp_flush(linpool *m)
 {
   struct lp_chunk *c;
 
-  /* Move ptr to the first chunk and free all large chunks */
+  /* Move ptr to the first chunk and free all other chunks */
   m->current = c = m->first;
   m->ptr = c ? c->data : NULL;
-  m->end = c ? c->data + m->chunk_size : NULL;
+  m->end = c ? c->data + LP_DATA_SIZE : NULL;
+
+  while (c && c->next)
+  {
+    struct lp_chunk *d = c->next;
+    c->next = d->next;
+    free_page(d);
+  }
 
   while (c = m->first_large)
     {
@@ -218,6 +220,7 @@ lp_save(linpool *m, lp_state *p)
 {
   p->current = m->current;
   p->large = m->first_large;
+  p->total_large = m->total_large;
   p->ptr = m->ptr;
 }
 
@@ -237,9 +240,10 @@ 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;
+  m->current = c = p->current ?: m->first;
+  m->ptr = p->ptr ?: (c ? c->data : NULL);
+  m->end = c ? (c->data + LP_DATA_SIZE) : NULL;
+  m->total_large = p->total_large;
 
   while ((c = m->first_large) && (c != p->large))
     {
@@ -257,7 +261,7 @@ lp_free(resource *r)
   for(d=m->first; d; d = c)
     {
       c = d->next;
-      xfree(d);
+      free_page(d);
     }
   for(d=m->first_large; d; d = c)
     {
@@ -277,30 +281,33 @@ lp_dump(resource *r)
     ;
   for(cntl=0, c=m->first_large; c; c=c->next, cntl++)
     ;
-  debug("(chunk=%d threshold=%d count=%d+%d total=%d+%d)\n",
-       m->chunk_size,
-       m->threshold,
+  debug("(count=%d+%d total=%d+%d)\n",
        cnt,
        cntl,
        m->total,
        m->total_large);
 }
 
-static size_t
+static struct resmem
 lp_memsize(resource *r)
 {
   linpool *m = (linpool *) r;
-  struct lp_chunk *c;
-  int cnt = 0;
+  struct resmem sz = {
+    .overhead = sizeof(struct linpool) + ALLOC_OVERHEAD,
+    .effective = m->total_large,
+  };
 
-  for(c=m->first; c; c=c->next)
-    cnt++;
-  for(c=m->first_large; c; c=c->next)
-    cnt++;
+  for (struct lp_chunk *c = m->first_large; c; c = c->next)
+    sz.overhead += sizeof(struct lp_chunk) + ALLOC_OVERHEAD;
+
+  uint regular = 0;
+  for (struct lp_chunk *c = m->first; c; c = c->next)
+    regular++;
 
-  return ALLOC_OVERHEAD + sizeof(struct linpool) +
-    cnt * (ALLOC_OVERHEAD + sizeof(struct lp_chunk)) +
-    m->total + m->total_large;
+  sz.effective += LP_DATA_SIZE * regular;
+  sz.overhead += (sizeof(struct lp_chunk) + ALLOC_OVERHEAD) * regular;
+
+  return sz;
 }
 
 
@@ -311,10 +318,7 @@ lp_lookup(resource *r, unsigned long a)
   struct lp_chunk *c;
 
   for(c=m->first; c; c=c->next)
-    if ((unsigned long) c->data <= a && (unsigned long) c->data + c->size > a)
-      return r;
-  for(c=m->first_large; c; c=c->next)
-    if ((unsigned long) c->data <= a && (unsigned long) c->data + c->size > a)
+    if ((unsigned long) c->data <= a && (unsigned long) c->data + LP_DATA_SIZE > a)
       return r;
   return NULL;
 }