* Allocate a block of virtual memory that is large enough to start with a * base_block_t header, followed by an object of specified size and alignment. * On success a pointer to the initialized base_block_t header is returned. */
| 245 | * On success a pointer to the initialized base_block_t header is returned. |
| 246 | */ |
| 247 | static base_block_t * |
| 248 | base_block_alloc(tsdn_t *tsdn, base_t *base, extent_hooks_t *extent_hooks, |
| 249 | unsigned ind, pszind_t *pind_last, size_t *extent_sn_next, size_t size, |
| 250 | size_t alignment) { |
| 251 | alignment = ALIGNMENT_CEILING(alignment, QUANTUM); |
| 252 | size_t usize = ALIGNMENT_CEILING(size, alignment); |
| 253 | size_t header_size = sizeof(base_block_t); |
| 254 | size_t gap_size = ALIGNMENT_CEILING(header_size, alignment) - |
| 255 | header_size; |
| 256 | /* |
| 257 | * Create increasingly larger blocks in order to limit the total number |
| 258 | * of disjoint virtual memory ranges. Choose the next size in the page |
| 259 | * size class series (skipping size classes that are not a multiple of |
| 260 | * HUGEPAGE), or a size large enough to satisfy the requested size and |
| 261 | * alignment, whichever is larger. |
| 262 | */ |
| 263 | size_t min_block_size = HUGEPAGE_CEILING(sz_psz2u(header_size + gap_size |
| 264 | + usize)); |
| 265 | pszind_t pind_next = (*pind_last + 1 < sz_psz2ind(SC_LARGE_MAXCLASS)) ? |
| 266 | *pind_last + 1 : *pind_last; |
| 267 | size_t next_block_size = HUGEPAGE_CEILING(sz_pind2sz(pind_next)); |
| 268 | size_t block_size = (min_block_size > next_block_size) ? min_block_size |
| 269 | : next_block_size; |
| 270 | base_block_t *block = (base_block_t *)base_map(tsdn, extent_hooks, ind, |
| 271 | block_size); |
| 272 | if (block == NULL) { |
| 273 | return NULL; |
| 274 | } |
| 275 | |
| 276 | if (metadata_thp_madvise()) { |
| 277 | void *addr = (void *)block; |
| 278 | assert(((uintptr_t)addr & HUGEPAGE_MASK) == 0 && |
| 279 | (block_size & HUGEPAGE_MASK) == 0); |
| 280 | if (opt_metadata_thp == metadata_thp_always) { |
| 281 | pages_huge(addr, block_size); |
| 282 | } else if (opt_metadata_thp == metadata_thp_auto && |
| 283 | base != NULL) { |
| 284 | /* base != NULL indicates this is not a new base. */ |
| 285 | malloc_mutex_lock(tsdn, &base->mtx); |
| 286 | base_auto_thp_switch(tsdn, base); |
| 287 | if (base->auto_thp_switched) { |
| 288 | pages_huge(addr, block_size); |
| 289 | } |
| 290 | malloc_mutex_unlock(tsdn, &base->mtx); |
| 291 | } |
| 292 | } |
| 293 | |
| 294 | *pind_last = sz_psz2ind(block_size); |
| 295 | block->size = block_size; |
| 296 | block->next = NULL; |
| 297 | assert(block_size >= header_size); |
| 298 | base_extent_init(extent_sn_next, &block->extent, |
| 299 | (void *)((uintptr_t)block + header_size), block_size - header_size); |
| 300 | return block; |
| 301 | } |
| 302 | |
| 303 | /* |
| 304 | * Allocate an extent that is at least as large as specified size, with |
no test coverage detected