struct page *alloc_pages(int n, struct page *next) { struct page *best; int bestn; struct page *scan; assert(n >= K); scan = unused_pages; /* Find first fit */ for (;;) { if (!scan) return alloc_new(n, next); if (scan->pagecount >= n) break; scan = scan->next; } /* Now find best fit */ best = scan; bestn = scan->pagecount; for (;;) { scan = scan->next; if (!scan) return alloc_split(best, n, next); if (scan->pagecount >=n && scan->pagecount < bestn) { best = scan; bestn = scan->pagecount; } } }
struct page *alloc_new(int n, struct page *next) /* Assumes freepages_lock held */ { struct page *newp = region_get_mem(n << RPAGELOG); assert(newp); assert(!((long)newp & (RPAGESIZE - 1))); /* region_get_mem may get us more memory than we asked for */ return alloc_split(newp, n, next); }
void scavenge_single_pages(int n) { /* Add n pages to the single_pages list */ struct page *scan, *best; __rcintptr bestn; /* Take any group in unused_pages that is <= n or < K. Remember smallest entry > n too. This is sortof equivalent to a best fit where we allow partial allocations to make up a whole */ best = NULL; bestn = (__rcintptr)1 << (sizeof(__rcintptr) * CHAR_BIT - 2); scan = unused_pages; while (scan) { /* The pages < K can't be used for anything but single pages so we might as well grab them even if they are a little too big */ if (scan->pagecount <= n || scan->pagecount < K) { struct page *adding = scan; scan = scan->next; n -= adding->pagecount; unlink_page(&unused_pages, adding); add_single_pages(adding); assert(single_pages->pagecount > 0); if (n <= 0) return; } else { if (scan->pagecount < bestn) { bestn = scan->pagecount; best = scan; } scan = scan->next; } } /* Still not enough. Split the best block if there is one, allocate new pages otherwise */ if (!best) { add_single_pages(alloc_new(n, NULL)); } else if (best->pagecount - n < K) { unlink_page(&unused_pages, best); add_single_pages(best); assert(single_pages->pagecount > 0); } else { add_single_pages(alloc_split(best, n, NULL)); assert(single_pages->pagecount > 0); } }
struct page* alloc_new(int n, struct page *next) { /* Assumes freepages_lock held */ struct page *newp = region_get_mem( (INT_PTR)n << RPAGELOG ); if (!newp) { if (nomem_h) nomem_h(); abort(); } assert( !( (long)newp & (RPAGESIZE - 1) ) ); /*newp->list_id = Hash(pthread_self())%MAXLISTS;*/ newp->list_id = list_id % MAXLISTS; /* region_get_mem may get us more memory than we asked for */ return alloc_split(newp, n, next); }