For use by exported routines below that want specific alignments Note: this code can be slow for alignments > 16, and can significantly fragment memory. The expectation is that memalign/posix_memalign/valloc/pvalloc will not be invoked very often. This requirement simplifies our implementation and allows us to tune for expected allocation patterns.
| 1326 | // often. This requirement simplifies our implementation and allows |
| 1327 | // us to tune for expected allocation patterns. |
| 1328 | void* do_memalign(size_t align, size_t size) { |
| 1329 | ASSERT((align & (align - 1)) == 0); |
| 1330 | ASSERT(align > 0); |
| 1331 | if (size + align < size) return NULL; // Overflow |
| 1332 | |
| 1333 | // Fall back to malloc if we would already align this memory access properly. |
| 1334 | if (align <= AlignmentForSize(size)) { |
| 1335 | void* p = do_malloc(size); |
| 1336 | ASSERT((reinterpret_cast<uintptr_t>(p) % align) == 0); |
| 1337 | return p; |
| 1338 | } |
| 1339 | |
| 1340 | if (UNLIKELY(Static::pageheap() == NULL)) ThreadCache::InitModule(); |
| 1341 | |
| 1342 | // Allocate at least one byte to avoid boundary conditions below |
| 1343 | if (size == 0) size = 1; |
| 1344 | |
| 1345 | if (size <= kMaxSize && align < kPageSize) { |
| 1346 | // Search through acceptable size classes looking for one with |
| 1347 | // enough alignment. This depends on the fact that |
| 1348 | // InitSizeClasses() currently produces several size classes that |
| 1349 | // are aligned at powers of two. We will waste time and space if |
| 1350 | // we miss in the size class array, but that is deemed acceptable |
| 1351 | // since memalign() should be used rarely. |
| 1352 | int cl = Static::sizemap()->SizeClass(size); |
| 1353 | while (cl < kNumClasses && |
| 1354 | ((Static::sizemap()->class_to_size(cl) & (align - 1)) != 0)) { |
| 1355 | cl++; |
| 1356 | } |
| 1357 | if (cl < kNumClasses) { |
| 1358 | ThreadCache* heap = ThreadCache::GetCache(); |
| 1359 | size = Static::sizemap()->class_to_size(cl); |
| 1360 | return CheckedMallocResult(heap->Allocate(size, cl)); |
| 1361 | } |
| 1362 | } |
| 1363 | |
| 1364 | // We will allocate directly from the page heap |
| 1365 | SpinLockHolder h(Static::pageheap_lock()); |
| 1366 | |
| 1367 | if (align <= kPageSize) { |
| 1368 | // Any page-level allocation will be fine |
| 1369 | // TODO: We could put the rest of this page in the appropriate |
| 1370 | // TODO: cache but it does not seem worth it. |
| 1371 | Span* span = Static::pageheap()->New(TCMALLOC_NAMESPACE::pages(size)); |
| 1372 | return UNLIKELY(span == NULL) ? NULL : SpanToMallocResult(span); |
| 1373 | } |
| 1374 | |
| 1375 | // Allocate extra pages and carve off an aligned portion |
| 1376 | const Length alloc = TCMALLOC_NAMESPACE::pages(size + align); |
| 1377 | Span* span = Static::pageheap()->New(alloc); |
| 1378 | if (UNLIKELY(span == NULL)) return NULL; |
| 1379 | |
| 1380 | // Skip starting portion so that we end up aligned |
| 1381 | Length skip = 0; |
| 1382 | while ((((span->start+skip) << kPageShift) & (align - 1)) != 0) { |
| 1383 | skip++; |
| 1384 | } |
| 1385 | ASSERT(skip < alloc); |
no test coverage detected