Allocate and register a new SLAB_PAGE_SIZE-aligned page, threading its chunks * onto the thread-local free list. Returns false on OOM (caller falls back to * malloc). Registration happens before any chunk is handed out so that a later * cross-thread free can always recover the page. */
| 213 | * malloc). Registration happens before any chunk is handed out so that a later |
| 214 | * cross-thread free can always recover the page. */ |
| 215 | static bool slab_grow(slab_state_t *s) { |
| 216 | void *mem = NULL; |
| 217 | if (cbm_aligned_alloc(&mem, SLAB_PAGE_SIZE, SLAB_PAGE_SIZE) != 0 || !mem) { |
| 218 | return false; |
| 219 | } |
| 220 | slab_page_t *page = (slab_page_t *)mem; |
| 221 | page->next = s->pages; |
| 222 | atomic_init(&page->owner, s); |
| 223 | atomic_init(&page->remote_free_head, (slab_free_node_t *)NULL); |
| 224 | atomic_init(&page->refcount, 1u); /* owner guard */ |
| 225 | |
| 226 | if (!slab_map_register_page(page)) { |
| 227 | cbm_aligned_free(page); |
| 228 | return false; |
| 229 | } |
| 230 | s->pages = page; |
| 231 | |
| 232 | for (size_t i = 0; i < SLAB_PAGE_CHUNKS; i++) { |
| 233 | slab_free_node_t *node = |
| 234 | (slab_free_node_t *)((char *)page + SLAB_DATA_OFFSET + i * SLAB_CHUNK_SIZE); |
| 235 | node->next = s->freelist; |
| 236 | s->freelist = node; |
| 237 | } |
| 238 | return true; |
| 239 | } |
| 240 | |
| 241 | /* Refill the thread-local free list: first reclaim any cross-thread frees |
| 242 | * queued on owned pages, then grow a fresh page if still empty. */ |
no test coverage detected