Module: xenomai-3
Branch: wip/heap-bitmap
Commit: f36e50b95dcc5a897bb8685eefb4a4077407cc66
URL:    
http://git.xenomai.org/?p=xenomai-3.git;a=commit;h=f36e50b95dcc5a897bb8685eefb4a4077407cc66

Author: Philippe Gerum <r...@xenomai.org>
Date:   Fri Jun  3 10:00:38 2016 +0200

copperplate/heapobj-pshared: introduce allocation bitmap

Using a free list for maintaining pages leads to pathological
execution times when releasing blocks obtained from huge heaps
(i.e. hundreds of megabytes). Rework the core to use an allocation
bitmap instead.

---

 lib/copperplate/heapobj-pshared.c |  424 +++++++++++++++++++++----------------
 lib/copperplate/internal.h        |   18 +-
 2 files changed, 259 insertions(+), 183 deletions(-)

diff --git a/lib/copperplate/heapobj-pshared.c 
b/lib/copperplate/heapobj-pshared.c
index 8c5dac6..bd9ea47 100644
--- a/lib/copperplate/heapobj-pshared.c
+++ b/lib/copperplate/heapobj-pshared.c
@@ -28,6 +28,7 @@
 #include <assert.h>
 #include <errno.h>
 #include <stdio.h>
+#include <stdint.h>
 #include <string.h>
 #include <pthread.h>
 #include <unistd.h>
@@ -43,15 +44,7 @@
 #include "xenomai/init.h"
 #include "internal.h"
 
-#define HOBJ_PAGE_SHIFT        9       /* 2^9 => 512 bytes */
-#define HOBJ_PAGE_SIZE         (1U << HOBJ_PAGE_SHIFT)
-#define HOBJ_PAGE_MASK         (~(HOBJ_PAGE_SIZE-1))
-#define HOBJ_PAGE_ALIGN(addr)  (((addr)+HOBJ_PAGE_SIZE-1)&HOBJ_PAGE_MASK)
-
-#define HOBJ_MINALIGNSZ (1U << 4) /* i.e. 16 bytes */
-#define HOBJ_MAXEXTSZ   (1U << 31) /* i.e. 2Gb */
-
-enum {
+enum {                         /* FIXME: page_free redundant with bitmap */
        page_free =0,
        page_cont =1,
        page_list =2
@@ -66,8 +59,9 @@ struct shared_extent {
        struct holder link;
        memoff_t membase;       /* Base offset of page array */
        memoff_t memlim;        /* Offset limit of page array */
-       memoff_t freelist;      /* Head of free page list */
-       struct page_entry pagemap[1]; /* Start of page map */
+       memoff_t bitmap;        /* Offset of allocation bitmap */
+       int bitwords;           /* 32bit words in bitmap */
+       struct page_entry pagemap[0]; /* Start of page map */
 };
 
 /*
@@ -117,24 +111,38 @@ static inline size_t __align_to(size_t size, size_t al)
        return ((size+al-1)&(~(al-1)));
 }
 
-static inline size_t get_pagemap_size(size_t h)
+static inline size_t get_pagemap_size(size_t h,
+                                     memoff_t *bmapoff, int *bmapwords)
 {
+       int nrpages = h >> HOBJ_PAGE_SHIFT, bitmapw;
+       size_t pagemapsz;
+
        /*
         * Return the size of the meta data required to map 'h' bytes
         * of user memory in pages of HOBJ_PAGE_SIZE bytes. The meta
         * data includes the length of the extent descriptor, plus the
-        * length of the page mapping array. 'h' must be a multiple of
-        * HOBJ_PAGE_SIZE on entry.
+        * length of the page mapping array followed by the allocation
+        * bitmap. 'h' must be a multiple of HOBJ_PAGE_SIZE on entry.
         */
        assert((h & ~HOBJ_PAGE_MASK) == 0);
-       return __align_to((h >> HOBJ_PAGE_SHIFT) * sizeof(struct page_entry)
-                         + sizeof(struct shared_extent), HOBJ_MINALIGNSZ);
+       pagemapsz = __align_to(nrpages * sizeof(struct page_entry),
+                              sizeof(uint32_t));
+       bitmapw =__align_to(nrpages, 32) / 32;
+       if (bmapoff)
+               *bmapoff = offsetof(struct shared_extent, pagemap) + pagemapsz;
+       if (bmapwords)
+               *bmapwords = bitmapw;
+
+       return __align_to(pagemapsz
+                         + sizeof(struct shared_extent)
+                         + bitmapw * sizeof(uint32_t),
+                         HOBJ_MINALIGNSZ);
 }
 
 static void init_extent(void *base, struct shared_extent *extent)
 {
-       caddr_t freepage;
-       int n, lastpgnum;
+       int lastpgnum;
+       uint32_t *p;
 
        __holder_init_nocheck(base, &extent->link);
 
@@ -146,20 +154,18 @@ static void init_extent(void *base, struct shared_extent 
*extent)
         */
        assert(lastpgnum >= 1);
 
-       /* Mark each page as free in the page map. */
-       for (n = 0, freepage = __shref(base, extent->membase);
-            n < lastpgnum; n++, freepage += HOBJ_PAGE_SIZE) {
-               *((memoff_t *)freepage) = __shoff(base, freepage) + 
HOBJ_PAGE_SIZE;
-               extent->pagemap[n].type = page_free;
-               extent->pagemap[n].bcount = 0;
-       }
-
-       *((memoff_t *)freepage) = 0;
-       extent->pagemap[lastpgnum].type = page_free;
-       extent->pagemap[lastpgnum].bcount = 0;
+       /* Mark all pages as free in the page map. */
+       memset(extent->pagemap, 0, lastpgnum * sizeof(struct page_entry));
 
-       /* The first page starts the free list of a new extent. */
-       extent->freelist = extent->membase;
+       /* Clear the allocation bitmap. */
+       p = __shref(base, extent->bitmap);
+       memset(p, 0, extent->bitwords * sizeof(uint32_t));
+       /*
+        * Mark the unused trailing bits (due to alignment) as busy,
+        * we don't want to pick them since they don't map any actual
+        * memory from the page pool.
+        */
+       p[lastpgnum / 32] |= ~(-1U >> (31 - (lastpgnum & 31)));
 }
 
 static int init_heap(struct shared_heap *heap, void *base,
@@ -168,7 +174,9 @@ static int init_heap(struct shared_heap *heap, void *base,
 {
        struct shared_extent *extent;
        pthread_mutexattr_t mattr;
-       int ret;
+       int ret, bmapwords;
+       memoff_t bmapoff;
+       size_t metasz;
 
        namecpy(heap->name, name);
 
@@ -203,15 +211,20 @@ static int init_heap(struct shared_heap *heap, void *base,
         * /...................\
         * \....(page map)...../
         * /...................\
+        * \.....(bitmap)....../
+        * /...................\
         * +-------------------+ <= extent->membase
         * |                   |
-        * |  (user memory)    |
+        * |    (page pool)    |
         * |                   |
         * +-------------------+
         *                       <= extent->memlim
         */
        extent = mem;
-       extent->membase = __shoff(base, mem) + get_pagemap_size(size);
+       metasz = get_pagemap_size(size, &bmapoff, &bmapwords);
+       extent->bitmap = __shoff(base, mem) + bmapoff;
+       extent->bitwords = bmapwords;
+       extent->membase = __shoff(base, mem) + metasz;
        extent->memlim = extent->membase + size;
        init_extent(base, extent);
        __list_append(base, &extent->link, &heap->extents);
@@ -249,91 +262,130 @@ static int init_main_heap(struct session_heap *m_heap,
        return 0;
 }
 
+static inline void flip_page_range(uint32_t *p, int b, int nr)
+{
+       for (;;) {
+               *p ^= (1 << b);
+               if (--nr == 0)
+                       return;
+               if (--b < 0) {
+                       b = 31;
+                       p--;
+               }
+       }
+}
+
+static int reserve_page_range(uint32_t *bitmap, int bitwords, int nrpages)
+{
+       int n, b, r, seq, beg, end;
+       uint32_t v = -1U;
+
+       /*
+        * Look for a free contiguous range of at least nrpages
+        * page(s) in the bitmap. Once found, flip the corresponding
+        * bit sequence from clear to set, then return the heading
+        * page number. Otherwise, return -1 on failure.
+        */
+       for (n = 0, seq = 0; n < bitwords; n++) {
+               v = bitmap[n];
+               b = 0;
+               while (v != -1U) {
+                       r = ctz(v);
+                       if (r) {
+                               seq += r;
+                               if (seq >= nrpages) {
+                                       beg = n * 32 + b + r - seq;
+                                       end = beg + nrpages - 1;
+                                       flip_page_range(bitmap + end / 32,
+                                                       end & 31, nrpages);
+                                       return beg;
+                               }
+                       } else {
+                               seq = 0;
+                               r = 1;
+                       }
+                       b += r;
+                       v >>= r;
+                       v |= -1U << (32 - r);
+               }
+       }
+       
+       return -1;
+}
+
+static inline
+caddr_t get_page_addr(void *base,
+                     struct shared_extent *extent, int pgnum)
+{
+       return __shref(base, extent->membase) + (pgnum << HOBJ_PAGE_SHIFT);
+}
+
 static caddr_t get_free_range(struct shared_heap *heap, size_t bsize, int 
log2size)
 {
-       caddr_t block, eblock, freepage, lastpage, headpage, freehead = NULL;
        struct shared_extent *extent;
-       size_t pnum, pcont, fcont;
        void *base = main_base;
+       caddr_t block, eblock;
+       uint32_t *bitmap;
+       size_t areasz;
+       int pstart, n;
+
+       /*
+        * Scanning each extent, search for a range of contiguous
+        * pages in the extent's bitmap. The range must be at least
+        * 'bsize' long.
+        */
 
+       areasz =__align_to(bsize, HOBJ_PAGE_SIZE) >> HOBJ_PAGE_SHIFT;
        __list_for_each_entry(base, extent, &heap->extents, link) {
-               freepage = __shref_check(base, extent->freelist);
-               while (freepage) {
-                       headpage = freepage;
-                       fcont = 0;
-                       /*
-                        * Search for a range of contiguous pages in
-                        * the free page list of the current
-                        * extent. The range must be 'bsize' long.
-                        */
-                       do {
-                               lastpage = freepage;
-                               freepage = __shref_check(base, *((memoff_t 
*)freepage));
-                               fcont += HOBJ_PAGE_SIZE;
-                       } while (freepage == lastpage + HOBJ_PAGE_SIZE
-                                && fcont < bsize);
-                       if (fcont >= bsize) {
-                               /*
-                                * Ok, got it. Just update the free
-                                * page list, then proceed to the next
-                                * step.
-                                */
-                               if (__shoff(base, headpage) == extent->freelist)
-                                       extent->freelist = *((memoff_t 
*)lastpage);
-                               else
-                                       *((memoff_t *)freehead) = *((memoff_t 
*)lastpage);
-
-                               goto splitpage;
-                       }
-                       freehead = lastpage;
-               }
+               bitmap = __shref(base, extent->bitmap);
+               pstart = reserve_page_range(bitmap, extent->bitwords, areasz);
+               if (pstart >= 0)
+                       goto splitpage;
        }
 
        return NULL;
 
-splitpage:
-
+splitpage:     
        /*
-        * At this point, headpage is valid and points to the first page
-        * of a range of contiguous free pages larger or equal than
-        * 'bsize'.
+        * pstart is the starting page number of a range of contiguous
+        * free pages larger or equal than 'bsize'.
         */
        if (bsize < HOBJ_PAGE_SIZE) {
                /*
-                * If the allocation size is smaller than the standard page
-                * size, split the page in smaller blocks of this size,
-                * building a free list of free blocks.
+                * If the allocation size is smaller than the internal
+                * page size, split the page in smaller blocks of this
+                * size, building a free list of bucketed free blocks.
                 */
-               for (block = headpage, eblock =
-                    headpage + HOBJ_PAGE_SIZE - bsize; block < eblock;
-                    block += bsize)
+               for (block = get_page_addr(base, extent, pstart),
+                    eblock = block + HOBJ_PAGE_SIZE - bsize;
+                    block < eblock; block += bsize)
                        *((memoff_t *)block) = __shoff(base, block) + bsize;
 
                *((memoff_t *)eblock) = 0;
-       } else
-               *((memoff_t *)headpage) = 0;
-
-       pnum = (__shoff(base, headpage) - extent->membase) >> HOBJ_PAGE_SHIFT;
+       }
 
        /*
         * Update the page map.  If log2size is non-zero (i.e. bsize
-        * <= 2 * PAGESIZE), store it in the first page's slot to
-        * record the exact block size (which is a power of
-        * two). Otherwise, store the special marker page_list,
-        * indicating the start of a block whose size is a multiple of
-        * the standard page size, but not necessarily a power of two.
-        * In any case, the following pages slots are marked as
-        * 'continued' (page_cont).
+        * <= 2 * PAGESIZE), store it in the slot heading the page
+        * range to record the exact block size (which is a power of
+        * two).
+        *
+        * Otherwise, store the special marker page_list, indicating
+        * the start of a block which size is a multiple of the
+        * standard page size, but not necessarily a power of two.
+        *
+        * Page slots following the heading one bear the page_cont
+        * marker.
         */
-       extent->pagemap[pnum].type = log2size ?: page_list;
-       extent->pagemap[pnum].bcount = 1;
+       extent->pagemap[pstart].type = log2size ?: page_list;
+       extent->pagemap[pstart].bcount = 1;
 
-       for (pcont = bsize >> HOBJ_PAGE_SHIFT; pcont > 1; pcont--) {
-               extent->pagemap[pnum + pcont - 1].type = page_cont;
-               extent->pagemap[pnum + pcont - 1].bcount = 0;
+       for (n = bsize >> HOBJ_PAGE_SHIFT; n > 1; n--) {
+               extent->pagemap[pstart + n - 1].type = page_cont;
+               extent->pagemap[pstart + n - 1].bcount = 0;
        }
 
-       return headpage;
+       return get_page_addr(base, extent, pstart);
 }
 
 static inline size_t  __attribute__ ((always_inline))
@@ -353,8 +405,8 @@ static void *alloc_block(struct shared_heap *heap, size_t 
size)
 {
        struct shared_extent *extent;
        void *base = main_base;
+       size_t pgnum, bsize;
        int log2size, ilog;
-       size_t pnum, bsize;
        caddr_t block;
 
        if (size == 0)
@@ -362,22 +414,20 @@ static void *alloc_block(struct shared_heap *heap, size_t 
size)
 
        size = align_alloc_size(size);
        /*
-        * It becomes more space efficient to directly allocate pages from
-        * the free page list whenever the requested size is greater than
-        * 2 times the page size. Otherwise, use the bucketed memory
-        * blocks.
+        * It becomes more space efficient to directly allocate pages
+        * from the free page pool whenever the requested size is
+        * greater than 2 times the page size. Otherwise, use the
+        * bucketed memory blocks.
         */
        if (size <= HOBJ_PAGE_SIZE * 2) {
-               /*
-                * Find the first power of two greater or equal to the
-                * rounded size. The log2 value of this size is also
-                * computed.
-                */
-               for (bsize = (1 << HOBJ_MINLOG2), log2size = HOBJ_MINLOG2;
-                    bsize < size; bsize <<= 1, log2size++)
-                       ;       /* Loop */
-
+               /* Find log2(size). */
+               log2size = sizeof(size) * 8 - 1 - clz(size);
+               if (size & (size - 1))
+                       log2size++;
+               /* That is the actual block size we need. */
+               bsize = 1 << log2size;
                ilog = log2size - HOBJ_MINLOG2;
+               assert(ilog < HOBJ_NBUCKETS);
 
                write_lock_nocancel(&heap->lock);
 
@@ -400,8 +450,8 @@ static void *alloc_block(struct shared_heap *heap, size_t 
size)
                        }
                        assert(0);
                found:
-                       pnum = (__shoff(base, block) - extent->membase) >> 
HOBJ_PAGE_SHIFT;
-                       ++extent->pagemap[pnum].bcount;
+                       pgnum = (__shoff(base, block) - extent->membase) >> 
HOBJ_PAGE_SHIFT;
+                       ++extent->pagemap[pgnum].bcount;
                }
 
                heap->buckets[ilog].freelist = *((memoff_t *)block);
@@ -425,12 +475,14 @@ done:
 
 static int free_block(struct shared_heap *heap, void *block)
 {
-       int log2size, ret = 0, nblocks, xpage, ilog, pagenr, maxpages;
-       caddr_t freepage, lastpage, nextpage, tailpage, freeptr;
-       size_t pnum, pcont, boffset, bsize;
+       int log2size, ret = 0, nblocks, xpage, ilog, pagenr,
+               maxpages, pghead, pgtail, n;
        struct shared_extent *extent;
+       memoff_t *tailp, pgoff, boff;
+       caddr_t freep, startp, endp;
        void *base = main_base;
-       memoff_t *tailptr;
+       uint32_t *bitmap;
+       size_t bsize;
 
        write_lock_nocancel(&heap->lock);
 
@@ -448,11 +500,11 @@ static int free_block(struct shared_heap *heap, void 
*block)
        goto out;
 found:
        /* Compute the heading page number in the page map. */
-       pnum = (__shoff(base, block) - extent->membase) >> HOBJ_PAGE_SHIFT;
-       boffset = (__shoff(base, block) -
-                  (extent->membase + (pnum << HOBJ_PAGE_SHIFT)));
+       pgoff = __shoff(base, block) - extent->membase;
+       pghead = pgoff >> HOBJ_PAGE_SHIFT;
+       boff = pgoff & ~HOBJ_PAGE_MASK;
 
-       switch (extent->pagemap[pnum].type) {
+       switch (extent->pagemap[pghead].type) {
        case page_free: /* Unallocated page? */
        case page_cont: /* Not a range heading page? */
                ret = -EINVAL;
@@ -462,76 +514,73 @@ found:
                pagenr = 1;
                maxpages = (extent->memlim - extent->membase) >> 
HOBJ_PAGE_SHIFT;
                while (pagenr < maxpages &&
-                      extent->pagemap[pnum + pagenr].type == page_cont)
+                      extent->pagemap[pghead + pagenr].type == page_cont)
                        pagenr++;
                bsize = pagenr * HOBJ_PAGE_SIZE;
 
-       free_page_list:
-               /* Link all freed pages in a single sub-list. */
-               for (freepage = (caddr_t)block,
-                    tailpage = (caddr_t)block + bsize - HOBJ_PAGE_SIZE;
-                    freepage < tailpage; freepage += HOBJ_PAGE_SIZE)
-                       *((memoff_t *)freepage) = __shoff(base, freepage) + 
HOBJ_PAGE_SIZE;
-
        free_pages:
                /* Mark the released pages as free in the extent's page map. */
-               for (pcont = 0; pcont < pagenr; pcont++)
-                       extent->pagemap[pnum + pcont].type = page_free;
+               for (n = 0; n < pagenr; n++)
+                       extent->pagemap[pghead + n].type = page_free;
+
+               /* Likewise for the allocation bitmap. */
+               bitmap = __shref(base, extent->bitmap);
+               pgtail = pghead + pagenr - 1;
                /*
-                * Return the sub-list to the free page list, keeping
-                * an increasing address order to favor coalescence.
+                * Mark the released page(s) as free in the
+                * bitmap. Caution: this is a reverse scan from the
+                * end of the bitfield mapping the area.
                 */
-               for (nextpage = __shref_check(base, extent->freelist), lastpage 
= NULL;
-                    nextpage && nextpage < (caddr_t)block;
-                    lastpage = nextpage, nextpage = __shref_check(base, 
*((memoff_t *)nextpage)))
-                 ;     /* Loop */
-
-               *((memoff_t *)tailpage) = __shoff_check(base, nextpage);
-               if (lastpage)
-                       *((memoff_t *)lastpage) = __shoff(base, block);
-               else
-                       extent->freelist = __shoff(base, block);
+               flip_page_range(bitmap + pgtail / 32, pgtail & 31, pagenr);
                break;
 
        default:
-
-               log2size = extent->pagemap[pnum].type;
+               log2size = extent->pagemap[pghead].type;
                bsize = (1 << log2size);
-               if ((boffset & (bsize - 1)) != 0) {     /* Not a block start? */
+               if ((boff & (bsize - 1)) != 0) { /* Not at block start? */
                        ret = -EINVAL;
                        goto out;
                }
                /*
-                * Return the page to the free list if we've just
+                * Return the page to the free pool if we've just
                 * freed its last busy block. Pages from multi-page
-                * blocks are always pushed to the free list (bcount
+                * blocks are always pushed to the free pool (bcount
                 * value for the heading page is always 1).
                 */
                ilog = log2size - HOBJ_MINLOG2;
-               if (--extent->pagemap[pnum].bcount > 0) {
-                       /* Return the block to the bucketed memory space. */
+               if (--extent->pagemap[pghead].bcount > 0) {
+                       /*
+                        * Page is still busy after release, return
+                        * the block to the free list then bail out.
+                        */
                        *((memoff_t *)block) = heap->buckets[ilog].freelist;
                        heap->buckets[ilog].freelist = __shoff(base, block);
                        ++heap->buckets[ilog].fcount;
                        break;
                }
 
+               /*
+                * The page the block was sitting on is idle, return
+                * it to the pool.
+                */
                pagenr = bsize >> HOBJ_PAGE_SHIFT;
+               /*
+                * In the simplest case, we only have a single block
+                * to deal with, which spans multiple consecutive
+                * pages: release it as a range of pages.
+                */
                if (pagenr > 1)
-                       /*
-                        * The simplest case: we only have a single
-                        * block to deal with, which spans multiple
-                        * pages. We just need to release it as a list
-                        * of pages, without caring about the
-                        * consistency of the bucket.
-                        */
-                       goto free_page_list;
+                       goto free_pages;
 
-               freepage = __shref(base, extent->membase) + (pnum << 
HOBJ_PAGE_SHIFT);
-               block = freepage;
-               tailpage = freepage;
-               nextpage = freepage + HOBJ_PAGE_SIZE;
+               pagenr = 1;
                nblocks = HOBJ_PAGE_SIZE >> log2size;
+               /*
+                * Decrease the free bucket count by the number of
+                * blocks that the empty page we are returning to the
+                * pool may contain. The block we are releasing can't
+                * be part of the free list by definition, hence
+                * nblocks - 1.
+                */
                heap->buckets[ilog].fcount -= (nblocks - 1);
                assert(heap->buckets[ilog].fcount >= 0);
 
@@ -553,22 +602,25 @@ found:
                 * traversed, or we hit the end of list, whichever
                 * comes first.
                 */
-               for (tailptr = &heap->buckets[ilog].freelist,
-                            freeptr = __shref_check(base, *tailptr), xpage = 1;
-                    freeptr && nblocks > 0;
-                    freeptr = __shref_check(base, *((memoff_t *)freeptr))) {
-                       if (freeptr < freepage || freeptr >= nextpage) {
+               startp = get_page_addr(base, extent, pghead);
+               endp = startp + HOBJ_PAGE_SIZE;
+               for (tailp = &heap->buckets[ilog].freelist,
+                            freep = __shref_check(base, *tailp), xpage = 1;
+                    freep && nblocks > 0;
+                    freep = __shref_check(base, *((memoff_t *)freep))) {
+                       if (freep < startp || freep >= endp) {
                                if (xpage) { /* Limit random writes */
-                                       *tailptr = __shoff(base, freeptr);
+                                       *tailp = __shoff(base, freep);
                                        xpage = 0;
                                }
-                               tailptr = (memoff_t *)freeptr;
+                               tailp = (memoff_t *)freep;
                        } else {
                                --nblocks;
                                xpage = 1;
                        }
                }
-               *tailptr = __shoff_check(base, freeptr);
+               *tailp = __shoff_check(base, freep);
+
                goto free_pages;
        }
 
@@ -581,10 +633,10 @@ out:
 
 static size_t check_block(struct shared_heap *heap, void *block)
 {
-       size_t pnum, boffset, bsize, ret = 0;
+       size_t pgnum, pgoff, boff, bsize, ret = 0;
        struct shared_extent *extent;
+       int ptype, maxpages, pagenr;
        void *base = main_base;
-       int ptype;
 
        read_lock_nocancel(&heap->lock);
 
@@ -599,16 +651,25 @@ static size_t check_block(struct shared_heap *heap, void 
*block)
        goto out;
 found:
        /* Compute the heading page number in the page map. */
-       pnum = (__shoff(base, block) - extent->membase) >> HOBJ_PAGE_SHIFT;
-       ptype = extent->pagemap[pnum].type;
+       pgoff = __shoff(base, block) - extent->membase;
+       pgnum = pgoff >> HOBJ_PAGE_SHIFT;
+       ptype = extent->pagemap[pgnum].type;
        if (ptype == page_free || ptype == page_cont)
                goto out;
 
-       bsize = (1 << ptype);
-       boffset = (__shoff(base, block) -
-                  (extent->membase + (pnum << HOBJ_PAGE_SHIFT)));
-       if ((boffset & (bsize - 1)) != 0) /* Not a block start? */
-               goto out;
+       if (ptype == page_list) {
+               pagenr = 1;
+               maxpages = (extent->memlim - extent->membase) >> 
HOBJ_PAGE_SHIFT;
+               while (pagenr < maxpages &&
+                      extent->pagemap[pgnum + pagenr].type == page_cont)
+                       pagenr++;
+               bsize = pagenr * HOBJ_PAGE_SIZE;
+       } else {
+               bsize = (1 << ptype);
+               boff = pgoff & ~HOBJ_PAGE_MASK;
+               if ((boff & (bsize - 1)) != 0) /* Not at block start? */
+                       goto out;
+       }
 
        ret = bsize;
 out:
@@ -646,7 +707,7 @@ static int create_main_heap(pid_t *cnode_r)
                size = HOBJ_PAGE_SIZE * 2;
 
        len = size + sizeof(*m_heap);
-       len += get_pagemap_size(size);
+       len += get_pagemap_size(size, NULL, NULL);
 
        /*
         * Bind to (and optionally create) the main session's heap:
@@ -885,7 +946,7 @@ int heapobj_init(struct heapobj *hobj, const char *name, 
size_t size)
                size = HOBJ_PAGE_SIZE * 2;
 
        len = size + sizeof(*heap);
-       len += get_pagemap_size(size);
+       len += get_pagemap_size(size, NULL, NULL);
 
        /*
         * Create a heap nested in the main shared heap to hold data
@@ -950,18 +1011,21 @@ int heapobj_extend(struct heapobj *hobj, size_t size, 
void *unused)
 {
        struct shared_heap *heap = __mptr(hobj->pool_ref);
        struct shared_extent *extent;
+       int state, bmapwords;
+       memoff_t bmapoff;
        size_t metasz;
-       int state;
 
        if (hobj == &main_pool) /* Can't extend the main pool. */
                return __bt(-EINVAL);
 
        size = __align_to(size, HOBJ_PAGE_SIZE);
-       metasz = get_pagemap_size(size);
+       metasz = get_pagemap_size(size, &bmapoff, &bmapwords);
        extent = alloc_block(&main_heap.heap, size + metasz);
        if (extent == NULL)
                return __bt(-ENOMEM);
 
+       extent->bitmap = __shoff(main_base, extent) + bmapoff;
+       extent->bitwords = bmapwords;
        extent->membase = __shoff(main_base, extent) + metasz;
        extent->memlim = extent->membase + size;
        init_extent(main_base, extent);
diff --git a/lib/copperplate/internal.h b/lib/copperplate/internal.h
index 23047b4..0d68ac9 100644
--- a/lib/copperplate/internal.h
+++ b/lib/copperplate/internal.h
@@ -38,9 +38,21 @@
 #define DEFAULT_REGISTRY_ROOT          NULL
 #endif
 
-#define HOBJ_MINLOG2    3
-#define HOBJ_MAXLOG2    22     /* Must hold pagemap::bcount objects */
-#define HOBJ_NBUCKETS   (HOBJ_MAXLOG2 - HOBJ_MINLOG2 + 2)
+#define HOBJ_PAGE_SHIFT        9 /* 2^9 => 512 bytes */
+#if HOBJ_PAGE_SHIFT > 21
+#error "page size is too large"
+#endif
+
+#define HOBJ_PAGE_SIZE (1UL << HOBJ_PAGE_SHIFT)
+#define HOBJ_PAGE_MASK (~(HOBJ_PAGE_SIZE-1))
+
+#define HOBJ_MINLOG2    4      /* 16 bytes */
+/* +1 for holding HOBJ_PAGE_SIZE < x <= HOBJ_PAGE_SIZE * 2 */
+#define HOBJ_MAXLOG2    (HOBJ_PAGE_SHIFT + 1)
+#define HOBJ_NBUCKETS   (HOBJ_MAXLOG2 - HOBJ_MINLOG2 + 1)
+#define HOBJ_MINALIGNSZ (1U << HOBJ_MINLOG2)
+
+#define HOBJ_MAXEXTSZ   (1U << 31) /* 2Gb */
 
 /*
  * The struct below has to live in shared memory; no direct reference


_______________________________________________
Xenomai-git mailing list
Xenomai-git@xenomai.org
https://xenomai.org/mailman/listinfo/xenomai-git

Reply via email to