diff options
Diffstat (limited to 'libbanshee/libcompat/alloc.c')
-rw-r--r-- | libbanshee/libcompat/alloc.c | 133 |
1 files changed, 133 insertions, 0 deletions
diff --git a/libbanshee/libcompat/alloc.c b/libbanshee/libcompat/alloc.c new file mode 100644 index 00000000000..7f2cfd369b2 --- /dev/null +++ b/libbanshee/libcompat/alloc.c @@ -0,0 +1,133 @@ +/* + * Copyright (c) 1999-2001 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ +/* TBD: recover unusued portions of pages for use as individual pages */ + +#include <stddef.h> +#include "regions.h" + +static void alloc_block(region r, struct allocator *a, struct ablock *blk, + void **p1, int s1, int a1, void **p2, int s2, int a2, + size_t blksize, int needsclear) +{ + struct page *newp; + char *mem1, *mem2; + + mem1 = PALIGN(blk->allocfrom, a1); + mem2 = PALIGN(mem1 + s1, a2); + + /* Can't use last byte of page (pointers to the byte after an object are + valid) */ + if (mem2 + s2 >= blk->base + blksize) + { + if (blksize == RPAGESIZE) + { + newp = alloc_single_page(a->pages); + a->pages = newp; + blk->allocfrom = (char *)newp + offsetof(struct page, previous); + set_region(newp, 1, r); + } + else + { + newp = alloc_pages(blksize >> RPAGELOG, a->bigpages); + a->bigpages = newp; + blk->allocfrom = (char *)newp + offsetof(struct page, previous); + set_region(newp, blksize >> RPAGELOG, r); + } + blk->base = (char *)newp; + + if (needsclear) + preclear(blk->allocfrom, blksize - (blk->allocfrom - (char *)newp)); + mem1 = PALIGN(blk->allocfrom, a1); + mem2 = PALIGN(mem1 + s1, a2); + } + + ASSERT_INUSE(blk->base, r); + blk->allocfrom = mem2 + s2; + + *p1 = mem1; + *p2 = mem2; +} + +void qalloc(region r, struct allocator *a, void **p1, int s1, int a1, + void **p2, int s2, int a2, int needsclear) +{ + struct page *p; + char *mem; + int npages; + int n = ALIGN(s1, a2) + s2; /* Yes, this is correct (see alloc_block) */ + + if (n <= RPAGESIZE / K) + { + alloc_block(r, a, &a->page, p1, s1, a1, p2, s2, a2, RPAGESIZE, + needsclear); + return; + } + if (n <= RPAGESIZE) + { + alloc_block(r, a, &a->superpage, p1, s1, a1, p2, s2, a2, + K * RPAGESIZE, needsclear); + return; + } + if (n <= RPAGESIZE * K) + { + alloc_block(r, a, &a->hyperpage, p1, s1, a1, p2, s2, a2, + K * K * RPAGESIZE, needsclear); + return; + } + + npages = (n + ALIGN(offsetof(struct page, previous), a1) + RPAGESIZE - 1) + >> RPAGELOG; + p = alloc_pages(npages, a->bigpages); + a->bigpages = p; + set_region(p, npages, r); + + mem = (char *)p + offsetof(struct page, previous); + *p1 = PALIGN(mem, a1); + *p2 = PALIGN((char *) *p1 + s1, a2); + if (needsclear) + preclear(*p2, s2); +} + +void free_all_pages(region r, struct allocator *a) +/* Assumes freepages_lock held */ +{ + struct page *p, *next; + + for (p = a->pages; p; p = next) + { + next = p->next; + free_single_page(r, p); + } + for (p = a->bigpages; p; p = next) + { + next = p->next; + free_pages(r, p); + } +} |