- // If our private free list is empty, try to find blocks on our public free list. If that fails,
- // allocate a new region.
- if (EXPECT_FALSE(tl->free_blocks[b_scale] == NULL)) {
- for (int i = 0; i < MAX_NUM_THREADS; ++ i) {
- block_t *x = tl->blocks_from[i];
- if (x != NULL) {
- block_t *next = x->next;
- if (next != NULL) {
- do {
- header_t *h = get_header(x);
- x->next = tl->free_blocks[h->scale];
- tl->free_blocks[h->scale] = x;
- x = next;
- next = x->next;
- } while (next != NULL);
- tl->blocks_from[i] = x;
- }
- }
- }
- // allocate a new region
- if (tl->free_blocks[b_scale] == NULL) {
- char *region = get_new_region(b_scale);
- size_t b_size = 1 << b_scale;
- size_t region_size = (b_size < REGION_SIZE) ? REGION_SIZE : b_size;
- for (int i = region_size; i != 0; i -= b_size) {
- block_t *b = (block_t *)(region + i - b_size);
- b->next = tl->free_blocks[b_scale];
- tl->free_blocks[b_scale] = b;
- }
+ block_t *b = pop_free_list(tl, b_scale);
+ if (b != NULL) {
+ TRACE("m1", "nbd_malloc: returning block %p", b, 0);
+ return b;
+ }
+
+ // The free list is empty so process blocks freed from other threads and then check again.
+ process_incoming_blocks(tl);
+ b = pop_free_list(tl, b_scale);
+ if (b != NULL) {
+ TRACE("m1", "nbd_malloc: returning block %p", b, 0);
+ return b;
+ }
+
+#ifdef RECYCLE_PAGES
+ // The current active page is completely allocated. Make the oldest partially allocated page
+ // the new active page.
+ size_class_t *sc = &tl->size_class[b_scale];
+ if (sc->oldest_partial != NULL) {
+ sc->active_page = sc->oldest_partial;
+ sc->oldest_partial = sc->oldest_partial->next;
+ sc->oldest_partial->prev = NULL;
+ b = pop_free_list(tl, b_scale);
+ ASSERT(b != NULL);
+ TRACE("m1", "nbd_malloc: returning block %p", b, 0);
+ return b;
+ }
+ // There are no partially allocated pages so get a new page.
+
+#endif//RECYCLE_PAGES
+
+ // Get a new page.
+ char *page = get_new_region(b_scale);
+ b = (block_t *)page; // grab the first block on the page
+
+ // Break up the remainder of the page into blocks and put them on the free list. Start at the
+ // end of the page so that the free list ends up in increasing order, for ease of debugging.
+ if (b_scale < PAGE_SCALE) {
+ size_t block_size = (1 << b_scale);
+ block_t *head = NULL;
+ for (int offset = PAGE_SIZE - block_size; offset > 0; offset -= block_size) {
+ block_t *x = (block_t *)(page + offset);
+ x->next = head; head = x;